ড্যাপারের সাহায্যে আমি কীভাবে নেস্টেড বস্তুর তালিকাগুলি ম্যাপ করব


127

আমি বর্তমানে আমার ডিবি অ্যাক্সেসের জন্য সত্তা ফ্রেমওয়ার্ক ব্যবহার করছি তবে ড্যাপারটি একবার দেখতে চাই। আমার এই জাতীয় ক্লাস রয়েছে:

public class Course{
   public string Title{get;set;}
   public IList<Location> Locations {get;set;}
   ...
}

public class Location{
   public string Name {get;set;}
   ...
}

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


সম্পর্কিত প্রশ্ন: স্ট্যাকওভারফ্লো.com
জেরোইন কে

এখানে আমার সমাধান: stackoverflow.com/a/57395072/8526957
স্যাম Sch

উত্তর:


57

ড্যাপার একটি সম্পূর্ণরূপে বিকশিত ওআরএম নয় এটি ম্যাজিক জেনারেশন সম্পর্কিত কোয়েরিগুলিকে পরিচালনা করে না।

আপনার নির্দিষ্ট উদাহরণের জন্য নিম্নলিখিতগুলি সম্ভবত কাজ করবে:

কোর্স দখল:

var courses = cnn.Query<Course>("select * from Courses where Category = 1 Order by CreationDate");

সম্পর্কিত ম্যাপিং ধরুন:

var mappings = cnn.Query<CourseLocation>(
   "select * from CourseLocations where CourseId in @Ids", 
    new {Ids = courses.Select(c => c.Id).Distinct()});

প্রাসঙ্গিক অবস্থানগুলি দখল করুন

var locations = cnn.Query<Location>(
   "select * from Locations where Id in @Ids",
   new {Ids = mappings.Select(m => m.LocationId).Distinct()}
);

এটি সমস্ত মানচিত্র

এটি পাঠকের উপরে রেখে, আপনি কয়েকটি মানচিত্র তৈরি করেন এবং অবস্থানগুলি সহ আপনার পাঠ্যক্রমগুলি পুনরাবৃত্তি করুন।

সতর্কীকরণin কৌতুক যদি তোমার চেয়ে কম আছে কাজ করবে 2100 লুক-(SQL সার্ভার), আপনি আছে যদি আরো আপনি সম্ভবত করার জন্য query সংশোধন করতে চান select * from CourseLocations where CourseId in (select Id from Courses ... )ব্যবহার যান সেই বিষয়টিই কিনা ভাল হিসাবে আপনি এক সমস্ত ফলাফল হ্যাঁচকা টান পারেQueryMultiple


স্যাম স্পষ্টির জন্য ধন্যবাদ। আপনি উপরে বর্ণিত মত আমি ঠিক অবস্থানগুলি আনার জন্য দ্বিতীয় কোয়েরি চালাচ্ছি এবং ম্যানুয়ালি এগুলি অবশ্যই কোর্সে নির্ধারিত করছি। আমি কেবল এটি নিশ্চিত করতে চেয়েছিলাম যে আমি এমন কোনও কিছু মিস করিনি যা আমাকে একটি প্রশ্নের সাথে তা করতে দেয়।
বি

2
স্যাম, একটি বৃহত অ্যাপ্লিকেশনে যেখানে সংগ্রহগুলি ডোমেন অবজেক্টগুলিতে নিয়মিতভাবে উদাহরণ হিসাবে প্রকাশিত হয়, আপনি এই কোডটি শারীরিকভাবে অবস্থিত হওয়ার পরামর্শ কোথায় দেবেন ? (যদি আপনি একভাবে সম্পূর্ণরূপে নির্মাণ [কোর্সের] থেকে সত্তা গ্রাস চাইবেন হামবড়া অসংখ্য কন্সট্রাকটর আপনার কোডে বিভিন্ন স্থানে)? একটি ক্লাস কারখানায়? অন্য কোথাও?
অগস্ট

177

বিকল্পভাবে, আপনি একটি অনুসন্ধানের সাথে একটি ক্যোয়ারী ব্যবহার করতে পারেন:

var lookup = new Dictionary<int, Course>();
conn.Query<Course, Location, Course>(@"
    SELECT c.*, l.*
    FROM Course c
    INNER JOIN Location l ON c.LocationId = l.Id                    
    ", (c, l) => {
        Course course;
        if (!lookup.TryGetValue(c.Id, out course))
            lookup.Add(c.Id, course = c);
        if (course.Locations == null) 
            course.Locations = new List<Location>();
        course.Locations.Add(l); /* Add locations to course */
        return course;
     }).AsQueryable();
var resultList = lookup.Values;

এখানে https://www.tritac.com/blog/dappernet-by-example/ দেখুন


9
এটি আমার অনেক সময় বাঁচিয়েছিল। একটি পরিবর্তন যা আমার অন্যের দরকার ছিল তা হ'ল স্প্লিটঅন: যুক্তিটি অন্তর্ভুক্ত করা যেহেতু আমি ডিফল্ট "আইডি" ব্যবহার করছিলাম না।
বিল স্যামব্রোন

1
বাম জোয়ারের জন্য আপনি লোকেশন তালিকার একটি শূন্য আইটেম পাবেন। এগুলিকে var আইটেম = দর্শন দ্বারা সরিয়ে দিন al মূল্য; আইটেম.এফের জন্য (x => x.Locations.RemoveAll (y => y == নাল));
চকো স্মিথ

আমি লাইন 1 এর শেষে একটি সেমিকোলন না থাকলে এবং 'এসকিউয়েরেবল ()' এর আগে কমাটি অপসারণ না করে আমি এটি সংকলন করতে পারি না। আমি উত্তরটি সম্পাদনা করব তবে 62 জন উর্ধ্বতন আমার আগে মনে হয়েছিল এটি ঠিক আছে, সম্ভবত আমি কিছু মিস করছি ...
বিটকোডার

1
বাম যোগদানের জন্য: এটিতে আর কোনও ফোরচ করার দরকার নেই। এটি যুক্ত করার আগে কেবল পরীক্ষা করুন: যদি (l! = নাল) কোর্স L লোকেশনস Aএড (এল)।
jpgrassi

1
যেহেতু আপনি একটি অভিধান ব্যবহার করছেন। আপনি যদি কোয়েরি মাল্টিপল এবং কোয়েরি কোর্স এবং অবস্থান পৃথকভাবে ব্যবহার করে থাকেন তবে কোর্সের স্থান নির্ধারণের জন্য একই অভিধানটি ব্যবহার করলে এটি কী দ্রুত হবে? এটি একই জিনিসটি অন্তঃস্থ যোগদানের বিয়োগ যার অর্থ বর্ধিত অনেক বাইট হিসাবে এসকিউএল অভ্যাস?
মাইক

43

lookupঅভিধানের দরকার নেই

var coursesWithLocations = 
    conn.Query<Course, Location, Course>(@"
        SELECT c.*, l.*
        FROM Course c
        INNER JOIN Location l ON c.LocationId = l.Id                    
        ", (course, location) => {
            course.Locations = course.Locations ?? new List<Location>();
            course.Locations.Add(location); 
            return course;
        }).AsQueryable();

3
এটি দুর্দান্ত - এটি আমার মতে নির্বাচিত উত্তর হওয়া উচিত। যদিও লোকেরা এটি করছে তারা করণে নজর রাখেন কারণ এটি পারফরম্যান্সকে প্রভাবিত করতে পারে।
cr1pto

2
এটির সাথে কেবলমাত্র সমস্যাটি হ'ল আপনি প্রতিটি অবস্থানের রেকর্ডে শিরোনামটি নকল করবেন। যদি প্রতি কোর্সে অনেক লোকেশন থাকে তবে এটি তারের জুড়ে চলে যাওয়া উল্লেখযোগ্য পরিমাণে ডেটা ডুপ্লিকেশন হতে পারে যা ব্যান্ডউইদথ বৃদ্ধি করবে, পার্স / মানচিত্রটি পার্স করতে আরও সময় লাগবে এবং সেগুলি পড়তে আরও মেমরি ব্যবহার করবে।
ড্যানিয়েল লরেঞ্জ 15

10
আমি নিশ্চিত না যে এটি আমার প্রত্যাশা মতো কাজ করছে। 3 টি সম্পর্কিত অবজেক্ট সহ আমার 1 টি প্যারেন্ট অবজেক্ট রয়েছে। আমার ব্যবহৃত ক্যোয়ারীটি তিনটি সারি ফিরে পেয়েছে। প্রথম কলামগুলি পিতামাতার বর্ণনা করে যা প্রতিটি সারিটির জন্য সদৃশ; আইডি বিভক্ত প্রতিটি অনন্য শিশু সনাক্ত করতে হবে। আমার ফলাফলগুলি 3 টি বাচ্চা সহ 3 জন নকল পিতা-মাতার .... 3 সন্তানের সাথে এক জন পিতামাতার হওয়া উচিত।
টপউইক

2
@ টপউইক ঠিক আছে। এটি আমার জন্য প্রত্যাশার মতো কাজ করে না।
ম্যাকিয়েজ প্লেজকোলিনস্কি

3
আমি আসলে এই কোড সহ প্রতিটি 3 জন পিতা-মাতার সাথে 1 সন্তানের সাথে শেষ করেছি। আমার ফলাফল @ টপওয়িকের চেয়ে আলাদা কেন তা নিশ্চিত নন, তবে তবুও এটি কার্যকর হয় না।
th3morg

29

আমি জানি আমি এ থেকে সত্যিই দেরি করেছি, তবে অন্য একটি বিকল্প রয়েছে। আপনি এখানে কোয়েরি মাল্টিপল ব্যবহার করতে পারেন। এটার মতো কিছু:

var results = cnn.QueryMultiple(@"
    SELECT * 
      FROM Courses 
     WHERE Category = 1 
  ORDER BY CreationDate
          ; 
    SELECT A.*
          ,B.CourseId 
      FROM Locations A 
INNER JOIN CourseLocations B 
        ON A.LocationId = B.LocationId 
INNER JOIN Course C 
        ON B.CourseId = B.CourseId 
       AND C.Category = 1
");

var courses = results.Read<Course>();
var locations = results.Read<Location>(); //(Location will have that extra CourseId on it for the next part)
foreach (var course in courses) {
   course.Locations = locations.Where(a => a.CourseId == course.CourseId).ToList();
}

3
একটি বিষয় লক্ষণীয়। যদি অনেকগুলি অবস্থান / কোর্স থাকে তবে আপনার একবারে লোকেশনগুলি লুপ করে ডিকশনারি লুকআপ করা উচিত যাতে আপনার N ^ 2 গতির পরিবর্তে N লগ এন থাকে। বৃহত্তর ডেটাসেটে বড় পার্থক্য তৈরি করে।
ড্যানিয়েল লরেঞ্জ 19

6

পার্টিতে দেরি হয়ে যাওয়ার জন্য দুঃখিত (সর্বদা মত) আমার জন্য, এটি একটি ব্যবহার করা আরো সহজ Dictionary, মত Jeroen কে করেনি কর্মক্ষমতা এবং পাঠযোগ্যতা পরিপ্রেক্ষিতে। এছাড়াও, অবস্থানগুলিতে শিরোনামের Distinct()গুণকে এড়ানোর জন্য , আমি সম্ভাব্য ডুপগুলি অপসারণ করতে ব্যবহার করি :

string query = @"SELECT c.*, l.*
    FROM Course c
    INNER JOIN Location l ON c.LocationId = l.Id";
using (SqlConnection conn = DB.getConnection())
{
    conn.Open();
    var courseDictionary = new Dictionary<Guid, Course>();
    var list = conn.Query<Course, Location, Course>(
        query,
        (course, location) =>
        {
            if (!courseDictionary.TryGetValue(course.Id, out Course courseEntry))
            {
                courseEntry = course;
                courseEntry.Locations = courseEntry.Locations ?? new List<Location>();
                courseDictionary.Add(courseEntry.Id, courseEntry);
            }

            courseEntry.Locations.Add(location);
            return courseEntry;
        },
        splitOn: "Id")
    .Distinct()
    .ToList();

    return list;
}

4

কিছু অনুপস্থিত। আপনি যদি Locationsএসকিউএল কোয়েরি থেকে প্রতিটি ক্ষেত্র নির্দিষ্ট না করেন তবে অবজেক্টটি Locationপূরণ করা যাবে না। দেখা যাক:

var lookup = new Dictionary<int, Course>()
conn.Query<Course, Location, Course>(@"
    SELECT c.*, l.Name, l.otherField, l.secondField
    FROM Course c
    INNER JOIN Location l ON c.LocationId = l.Id                    
    ", (c, l) => {
        Course course;
        if (!lookup.TryGetValue(c.Id, out course)) {
            lookup.Add(c.Id, course = c);
        }
        if (course.Locations == null) 
            course.Locations = new List<Location>();
        course.Locations.Add(a);
        return course;
     },
     ).AsQueryable();
var resultList = lookup.Values;

l.*ক্যোয়ারিতে ব্যবহার করে , আমার কাছে অবস্থানের তালিকা ছিল কিন্তু ডেটা ছাড়াই।


0

কারও এটির প্রয়োজন আছে কিনা তা নিশ্চিত নই, তবে দ্রুত এবং নমনীয় কোডিংয়ের জন্য আমার কাছে মডেল ছাড়াই এর গতিশীল সংস্করণ রয়েছে।

var lookup = new Dictionary<int, dynamic>();
conn.Query<dynamic, dynamic, dynamic>(@"
    SELECT A.*, B.*
    FROM Client A
    INNER JOIN Instance B ON A.ClientID = B.ClientID                
    ", (A, B) => {
        // If dict has no key, allocate new obj
        // with another level of array
        if (!lookup.ContainsKey(A.ClientID)) {
            lookup[A.ClientID] = new {
                ClientID = A.ClientID,
                ClientName = A.Name,                                        
                Instances = new List<dynamic>()
            };
        }

        // Add each instance                                
        lookup[A.ClientID].Instances.Add(new {
            InstanceName = B.Name,
            BaseURL = B.BaseURL,
            WebAppPath = B.WebAppPath
        });

        return lookup[A.ClientID];
    }, splitOn: "ClientID,InstanceID").AsQueryable();

var resultList = lookup.Values;
return resultList;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.