ড্যাপারে মাল্টিম্যাপিংয়ের সঠিক ব্যবহার


111

প্রোডাক্ট আইটেম এবং সম্পর্কিত গ্রাহকদের একটি তালিকা ফেরত দেওয়ার জন্য আমি ড্যাপারের মাল্টিম্যাপিং বৈশিষ্ট্যটি ব্যবহার করার চেষ্টা করছি।

[Table("Product")]
public class ProductItem
{
    public decimal ProductID { get; set; }        
    public string ProductName { get; set; }
    public string AccountOpened { get; set; }
    public Customer Customer { get; set; }
} 

public class Customer
{
    public decimal CustomerId { get; set; }
    public string CustomerName { get; set; }
}

আমার ড্যাপার কোডটি নিম্নরূপ

var sql = @"select * from Product p 
            inner join Customer c on p.CustomerId = c.CustomerId 
            order by p.ProductName";

var data = con.Query<ProductItem, Customer, ProductItem>(
    sql,
    (productItem, customer) => {
        productItem.Customer = customer;
        return productItem;
    },
    splitOn: "CustomerId,CustomerName"
);

এটি দুর্দান্ত কাজ করে তবে গ্রাহকদের সমস্ত সম্পত্তি ফিরে পাওয়ার জন্য স্প্লিটঅন প্যারামিটারে আমার সম্পূর্ণ কলামের তালিকা যুক্ত করতে হবে বলে মনে হচ্ছে। যদি আমি "গ্রাহক নাম" যুক্ত না করি তবে এটি বাতিল হয়। আমি কি মাল্টিম্যাপিং বৈশিষ্ট্যের মূল কার্যকারিতাটি মিস করছি। আমি প্রতিবার কলামের নামের একটি সম্পূর্ণ তালিকা যুক্ত করতে চাই না।


আপনি তখন ডেটাগ্রিডভিউতে উভয় সারণীটি কীভাবে প্রদর্শন করবেন? একটি ছোট উদাহরণ অনেক প্রশংসা করা হবে।
অঙ্কুর সনি

উত্তর:


184

আমি সবেমাত্র একটি পরীক্ষা চালিয়েছি যা ভাল কাজ করে:

var sql = "select cast(1 as decimal) ProductId, 'a' ProductName, 'x' AccountOpened, cast(1 as decimal) CustomerId, 'name' CustomerName";

var item = connection.Query<ProductItem, Customer, ProductItem>(sql,
    (p, c) => { p.Customer = c; return p; }, splitOn: "CustomerId").First();

item.Customer.CustomerId.IsEqualTo(1);

স্প্লিটঅন পরমকে স্প্লিট পয়েন্ট হিসাবে নির্দিষ্ট করা দরকার, এটি আইডিতে ডিফল্ট হয়। যদি একাধিক বিভাজন পয়েন্ট থাকে তবে আপনাকে সেগুলি কমা সীমানা তালিকায় যুক্ত করতে হবে।

বলুন আপনার রেকর্ডসেটটি দেখতে এমন দেখাচ্ছে:

প্রোডাক্টআইডি | প্রোডাক্টনাম | অ্যাকাউন্ট খোলা | গ্রাহকআইডি | ক্রেতার নাম
--------------------------------------- ----------- --------------

এই ক্রমের কলামগুলি কীভাবে 2 টি বস্তুতে বিভক্ত করা যায় তা ডিপারকে জানতে হবে। একটি অভিসম্পূর্ণ চেহারা দেখায় যে গ্রাহক কলাম থেকে শুরু হয় CustomerId, তাই splitOn: CustomerId

একটি নেই বড় সতর্কীকরণ এখানে, যদি অন্তর্নিহিত সারণিতে কলাম ক্রম কিছু কারণে ফ্লিপ হয়:

প্রোডাক্টআইডি | প্রোডাক্টনাম | অ্যাকাউন্ট খোলা | গ্রাহক নাম | CustomerId  
--------------------------------------- ----------- --------------

splitOn: CustomerId একটি শূন্য গ্রাহকের নাম ফলাফল হবে।

যদি আপনি CustomerId,CustomerNameবিভক্ত পয়েন্ট হিসাবে নির্দিষ্ট করেন তবে ড্যাপার ধরে নেয় যে আপনি ফলাফলটি 3 টি অবজেক্টে বিভক্ত করার চেষ্টা করছেন। প্রথম শুরুতে শুরু হয়, দ্বিতীয়টি শুরু হয় CustomerId, তৃতীয় দিকে CustomerName


2
ধন্যবাদ স্যাম হ্যাঁ আপনার ডান এটি কলামগুলির রিটার্ন অর্ডার যা গ্রাহকনামে সমস্যা ছিল গ্রাহকআইড ফিরিয়ে দেওয়া হচ্ছে গ্রাহক নামটি বাতিল হয়ে আসছিল was
রিচার্ড ফরেস্ট

18
একটি জিনিস মনে রাখবেন যে আপনার মধ্যে ফাঁকা স্থান থাকতে পারে না spliton, অর্থাত্ CustomerId,CustomerNameনয় CustomerId, CustomerName, যেহেতু ড্যাপার Trimস্ট্রিং বিভক্ত হওয়ার ফলাফল দেয় না । এটি কেবল জেনেরিক স্প্লিটন ত্রুটি নিক্ষেপ করবে। আমাকে একদিন পাগল করে দিয়েছে।
jes

2
@ আপনার সর্বদা কলামের নাম ব্যবহার করা উচিত এবং কখনও কোনও তারা ব্যবহার করা উচিত নয়, এটি স্কয়ারকে কম কাজ দেয় এবং আপনি যেমন কলামের ক্রমটি ভুল করেন তেমন পরিস্থিতি পাবেন না this
হারাগ

3
@ ওয়েহইডস - আইডি, আইডি, আইডি সম্পর্কিত যেটি ডিপার কোডটি দেখছে এটি কেস সংবেদনশীল নয়, এবং এটি স্প্লিটঅন-এর পাঠ্যটিও ছাঁটাই করে - এটি ড্যাপারের v1.50.2.0।
হারাগ

2
যে কেউ ভাবছেন, আপনার যদি 3 টি অবজেক্টে কোনও ক্যোয়ারী বিভক্ত করতে হয়: "আইডি" নামে একটি কলামে এবং "কিছু আইডআইডি" নামে একটি কলামে, বিভক্ত ধারাটিতে প্রথম "আইডি" অন্তর্ভুক্ত করার বিষয়টি নিশ্চিত করুন। যদিও ডিপার "আইডিতে" ডিফল্টরূপে বিভক্ত হয়, এক্ষেত্রে এটি স্পষ্টভাবে সেট করতে হবে।
এসবিউ

27

আমাদের টেবিলগুলির নামও আপনার একইভাবে দেওয়া হয়েছে, যেখানে 'কাস্টমারআইডি' এর মতো কিছু 'নির্বাচিত *' অপারেশন ব্যবহার করে দুবার ফিরে আসতে পারে। অতএব, ড্যাপার তার কাজটি করছে তবে খুব শীঘ্রই বিভক্ত হচ্ছে (সম্ভবত), কারণ কলামগুলি হবে:

(select * might return):
ProductID,
ProductName,
CustomerID, --first CustomerID
AccountOpened,
CustomerID, --second CustomerID,
CustomerName.

এটি স্প্লিটটনকে তৈরি করে: প্যারামিটারটি এতটা দরকারী নয়, বিশেষত যখন আপনি নিশ্চিত হন না যে কলামগুলি কীভাবে ফিরে আসবে Of অবশ্যই আপনি ম্যানুয়ালি কলামগুলি নির্দিষ্ট করতে পারবেন ... তবে এটি 2017 এবং আমরা খুব কমই বেসিক অবজেক্টের জন্য এটি করি।

আমরা যা করি, এবং এটি বহু বছরের জন্য হাজারো প্রশ্নের জন্য দুর্দান্ত কাজ করেছে, কেবল আইডির জন্য একটি উপনাম ব্যবহার করা হয় এবং কখনও স্প্লিটটন নির্দিষ্ট করে না (ডাপারের ডিফল্ট 'আইডি' ব্যবহার করে)।

select 
p.*,

c.CustomerID AS Id,
c.*

... ভাল খবর! ডিপার কেবলমাত্র ডিফল্টরূপে আইডিতে বিভক্ত হয়ে যায় এবং সেই আইডিটি সমস্ত গ্রাহক কলামের আগে ঘটে। অবশ্যই এটি আপনার রিটার্ন রিসেটসেটে একটি অতিরিক্ত কলাম যুক্ত করবে, তবে কোন কলামগুলি কোন অবজেক্টের অন্তর্ভুক্ত তা সঠিকভাবে জেনে যাওয়ার যুক্ত ইউটিলিটির জন্য এটি অত্যন্ত ন্যূনতম ওভারহেড। এবং আপনি এটি সহজেই প্রসারিত করতে পারেন। ঠিকানা এবং দেশের তথ্য দরকার?

select
p.*,

c.CustomerID AS Id,
c.*,

address.AddressID AS Id,
address.*,

country.CountryID AS Id,
country.*

সর্বোপরি, আপনি স্পষ্টভাবে ন্যূনতম পরিমাণে বর্গক্ষেত্রের মধ্যে দেখিয়ে যাচ্ছেন যা কোন বস্তুর সাথে কলামগুলি যুক্ত। বাকীটিও ডাপার করে।


এটি কোনও সংক্ষিপ্ত পদ্ধতির যতক্ষণ না কোনও সারণীর আইডির ক্ষেত্র নেই।
বার্নার্ড ভ্যান্ডার বেকেন

এই পদ্ধতির সাথে একটি টেবিলের এখনও একটি আইডি ক্ষেত্র থাকতে পারে ... তবে এটি পিকে হওয়া উচিত। আপনাকে কেবল উপনামটি তৈরি করতে হবে না সুতরাং এটি আসলে একটু কম কাজ। (আমি 'আইডি' নামক একটি কলাম পিকে নয় এটি অত্যন্ত অস্বাভাবিক (খারাপ ফর্ম?) বলে মনে করব)
ব্ল্যাকজ্যাকটম্যাক

5

নিম্নলিখিত কাঠামো ধরে নেওয়া যেখানে '|' বিভাজনের বিন্দু এবং টিএস হল সেই সত্তা যেখানে ম্যাপিং প্রয়োগ করা উচিত।

       TFirst         TSecond         TThird           TFourth
------------------+-------------+-------------------+------------
col_1 col_2 col_3 | col_n col_m | col_A col_B col_C | col_9 col_8
------------------+-------------+-------------------+------------

নিম্নলিখিত লিখতে হবে যে ডিপার কোয়েরি নীচে।

Query<TFirst, TSecond, TThird, TFourth, TResut> (
    sql : query,
    map: Func<TFirst, TSecond, TThird, TFourth, TResut> func,
    parma: optional,
    splitOn: "col_3, col_n, col_A, col_9")

সুতরাং আমরা টিফার্স্টটি কল_এন কল_ম টি_সকোন্ডের জন্য, কল_1 কল_2 কল_3 ম্যাপ করতে চাই ...

স্প্লিটঅন এক্সপ্রেসনটি অনুবাদ করে:

টিএফ্রিস্টে সমস্ত কলামের ম্যাপিং শুরু করুন যতক্ষণ না আপনি 'কল_3' নামকরণ করা বা এলিয়াসযুক্ত কলাম খুঁজে পান এবং ম্যাপিংয়ের ফলাফলের মধ্যে 'কল_3' অন্তর্ভুক্ত করেন।

তারপরে 'কল_এন' থেকে শুরু করে সমস্ত কলামে টিসেকেন্ডে ম্যাপিং শুরু করুন এবং নতুন বিভাজক না পাওয়া পর্যন্ত ম্যাপিং চালিয়ে যান, যা এই ক্ষেত্রে 'কোল_এ' হয় এবং এটি টিটিয়ার্ড ম্যাপিংয়ের শুরু চিহ্নিত করে এবং তাই একটি।

বর্গ কোয়েরির কলাম এবং ম্যাপিং অবজেক্টের প্রপসগুলি 1: 1 টির সাথে থাকে (যার অর্থ তাদের একই নামকরণ করা উচিত), যদি বর্গ কোয়েরির ফলে প্রাপ্ত কলামগুলির নামগুলি পৃথক হয় তবে আপনি এএস ব্যবহার করে এটিকে উলেস করতে পারেন [ কিছু_আলিয়াস_নাম] এর অভিব্যক্তি।


2

আরও একটি সতর্কতা আছে। যদি কাস্টমারআইডি ফিল্ডটি শূন্য হয় (সাধারণত বাম জোড়ার সাথে অনুসন্ধানে) ড্যাপার গ্রাহক = সাথে নালার সাথে পণ্য আইটেম তৈরি করে। উপরের উদাহরণে:

var sql = "select cast(1 as decimal) ProductId, 'a' ProductName, 'x' AccountOpened, cast(null as decimal) CustomerId, 'n' CustomerName";
var item = connection.Query<ProductItem, Customer, ProductItem>(sql, (p, c) => { p.Customer = c; return p; }, splitOn: "CustomerId").First();
Debug.Assert(item.Customer == null); 

এবং আরও একটি সতর্কতা / ফাঁদ। যদি আপনি স্প্লিটঅনে নির্দিষ্ট ক্ষেত্রটি মানচিত্র না করেন এবং সেই ক্ষেত্রে শূন্য ড্যাপার সম্পর্কিত জিনিসটি তৈরি করে এবং পূরণ করে (এই ক্ষেত্রে গ্রাহক)। পূর্ববর্তী স্ক্যুএল সহ এই শ্রেণিটি ব্যবহার করে দেখানোর জন্য:

public class Customer
{
    //public decimal CustomerId { get; set; }
    public string CustomerName { get; set; }
}
...
Debug.Assert(item.Customer != null);
Debug.Assert(item.Customer.CustomerName == "n");  

ক্লাসে কাস্টোম্রিড যুক্ত করার পাশাপাশি দ্বিতীয় উদাহরণের কোনও সমাধান আছে? আমার একটি সমস্যা হচ্ছে যেখানে আমার নাল বস্তুর প্রয়োজন, তবে এটি আমাকে একটি খালি বস্তু দিচ্ছে। ( Stackoverflow.com/questions/27231637/... )
jmzagorski

1

আমি আমার রেপোতে এটি সাধারণভাবে করি, আমার ব্যবহারের ক্ষেত্রে ভাল কাজ করে। আমি ভেবেছিলাম ভাগ করে নেব। হয়তো কেউ এটিকে আরও বাড়িয়ে দেবে।

কিছু ত্রুটিগুলি হ'ল:

  • এটি ধরে নিয়েছে যে আপনার বিদেশী কী বৈশিষ্ট্যগুলি আপনার চাইল্ড অবজেক্টের নাম "" আইডি ", যেমন ইউনিটআইড।
  • আমার কাছে এটি পিতা-মাতার কাছে কেবলমাত্র 1 টি সন্তানের বস্তুটি ম্যাপিং করছে।

কোড:

    public IEnumerable<TParent> GetParentChild<TParent, TChild>()
    {
        var sql = string.Format(@"select * from {0} p 
        inner join {1} c on p.{1}Id = c.Id", 
        typeof(TParent).Name, typeof(TChild).Name);

        Debug.WriteLine(sql);

        var data = _con.Query<TParent, TChild, TParent>(
            sql,
            (p, c) =>
            {
                p.GetType().GetProperty(typeof (TChild).Name).SetValue(p, c);
                return p;
            },
            splitOn: typeof(TChild).Name + "Id");

        return data;
    }

0

আপনার যদি একটি বৃহত সত্তা মানচিত্রের প্রয়োজন হয় তবে প্রতিটি ক্ষেত্র লিখতে হবে একটি কঠিন কাজ।

আমি @ ব্ল্যাকজ্যাককেট ম্যাক উত্তরটি চেষ্টা করেছিলাম, তবে আমার টেবিলে একটি আইড কলাম রয়েছে অন্যটি নয় (আমি জানি এটি একটি ডিবি ডিজাইনের সমস্যা, তবে ...) তবে এটি ড্যাপারে একটি অতিরিক্ত বিভাজন sertোকায়, এজন্যই

select
p.*,

c.CustomerID AS Id,
c.*,

address.AddressID AS Id,
address.*,

country.CountryID AS Id,
country.*

আমার জন্য কাজ করে না। তারপর আমি এই একটি সামান্য পরিবর্তনের সঙ্গে শেষ হয়েছে, শুধু একটি নাম দিয়ে আপনি কোনো বিভক্ত পয়েন্ট যে টেবিল কোনো ক্ষেত্র সহ মিলছে না, পরিবর্তন যদি করতে পারে ঢোকান as Idদ্বারা as _SplitPoint_ভালো চূড়ান্ত SQL স্ক্রিপ্ট দেখায়:

select
p.*,

c.CustomerID AS _SplitPoint_,
c.*,

address.AddressID AS _SplitPoint_,
address.*,

country.CountryID AS _SplitPoint_,
country.*

তারপরে ড্যাপারে এটির জন্য মাত্র একটি স্প্লিট যুক্ত করুন

cmd =
    "SELECT Materials.*, " +
    "   Product.ItemtId as _SplitPoint_," +
    "   Product.*, " +
    "   MeasureUnit.IntIdUM as _SplitPoint_, " +
    "   MeasureUnit.* " +
    "FROM   Materials INNER JOIN " +
    "   Product ON Materials.ItemtId = Product.ItemtId INNER JOIN " +
    "   MeasureUnit ON Materials.IntIdUM = MeasureUnit.IntIdUM " +
List < Materials> fTecnica3 = (await dpCx.QueryAsync<Materials>(
        cmd,
        new[] { typeof(Materials), typeof(Product), typeof(MeasureUnit) },
        (objects) =>
        {
            Materials mat = (Materials)objects[0];
            mat.Product = (Product)objects[1];
            mat.MeasureUnit = (MeasureUnit)objects[2];
            return mat;
        },
        splitOn: "_SplitPoint_"
    )).ToList();
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.