সি # সত্তা-ফ্রেমওয়ার্ক: আমি কীভাবে একটি .ফাইন্ড এবং .একটি মডেল অবজেক্টে অন্তর্ভুক্ত করতে পারি?


145

আমি mvcmusicstore অনুশীলন টিউটোরিয়াল করছি। অ্যালবাম পরিচালকের জন্য স্ক্যাফোল্ড তৈরি করার সময় আমি কিছু লক্ষ্য করেছি (সম্পাদনা মুছুন যোগ করুন)।

আমি কোডটি মার্জিতভাবে লিখতে চাই, তাই আমি এটি লেখার পরিষ্কার উপায়টি খুঁজছি।

এফওয়াইআই আমি দোকানটিকে আরও জেনেরিক করে তুলছি:

অ্যালবাম = আইটেম

জেনারস = বিভাগসমূহ

শিল্পী = ব্র্যান্ড

এখানে সূচকটি কীভাবে পুনরুদ্ধার করা হয় (এমভিসি দ্বারা উত্পাদিত):

var items = db.Items.Include(i => i.Category).Include(i => i.Brand);

মুছে ফেলার আইটেমটি কীভাবে পুনরুদ্ধার করা হয়েছে তা এখানে:

Item item = db.Items.Find(id);

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

আমি কীভাবে দ্বিতীয়টি লিখতে পারি এবং কী কী ভিতরে ভিতরে স্থাপন করতে পারে (অগ্রাধিকার হিসাবে 1 লাইনে) ... তাত্ত্বিকভাবে - এর মতো কিছু:

Item item = db.Items.Find(id).Include(i => i.Category).Include(i => i.Brand);

কারও যদি সাধারণভাবে এটি করার দরকার হয় ইন-কোর আমার উত্তরটি দেখুন
5

উত্তর:


162

আপনাকে Include()প্রথমে ব্যবহার করতে হবে , তারপরে ফলাফলের ক্যোয়ারী থেকে একটি একক বস্তু পুনরুদ্ধার করতে হবে :

Item item = db.Items
              .Include(i => i.Category)
              .Include(i => i.Brand)
              .SingleOrDefault(x => x.ItemId == id);

24
আমি সত্যিই উত্তরোত্তর (সিঙ্গলঅরডিফল্ট) ব্যবহার করার পরামর্শ দেব, টোললিস্ট প্রথমে সমস্ত এন্ট্রি পুনরুদ্ধার করবে এবং তারপরে একটি নির্বাচন করবে
স্যান্ডার রিজকেন

5
যদি আমাদের কাছে একটি যৌগিক প্রাথমিক কী থাকে এবং এটি সম্পর্কিত অনুসন্ধানের ওভারলোড ব্যবহার করে থাকে তবে এটি ভেঙে যায়।
ঝাঁপল্টে

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

3
@ ইরাবঞ্চি সঠিক। এটি ব্যবহারকারীর পক্ষে কাজ করতে পারে, তবে অপারেশন এবং এর পার্শ্ব-প্রতিক্রিয়াগুলি যতদূর আমি জানি সন্ধানের সমতুল্য নয়।
মিউইলসন

3
এটি ব্যবহার করছে না
বলেই আসলে অপ্সের

73

ডেনিসের উত্তরটি ব্যবহার করছে Includeএবং SingleOrDefault। পরেরটি ডাটাবেসে গোল-ট্রিপ করে যায়।

সম্পর্কিত সত্তা সুস্পষ্টভাবে লোড করার জন্য, এর Findসাথে একত্রে বিকল্প হিসাবে ব্যবহার করা হয় Load...

একটি এমএসডিএন উদাহরণের নীচে :

using (var context = new BloggingContext()) 
{ 
  var post = context.Posts.Find(2); 

  // Load the blog related to a given post 
  context.Entry(post).Reference(p => p.Blog).Load(); 

  // Load the blog related to a given post using a string  
  context.Entry(post).Reference("Blog").Load(); 

  var blog = context.Blogs.Find(1); 

  // Load the posts related to a given blog 
  context.Entry(blog).Collection(p => p.Posts).Load(); 

  // Load the posts related to a given blog  
  // using a string to specify the relationship 
  context.Entry(blog).Collection("Posts").Load(); 
}

অবশ্যই, Findস্টোরটিতে কোনও অনুরোধ না করে অবিলম্বে ফিরে আসে, যদি সেই সত্তা ইতিমধ্যে প্রসঙ্গে লোড করা থাকে।


30
এই পদ্ধতিটি Findতাই ব্যবহার করে যদি সত্তা উপস্থিত থাকে, সত্তার জন্য ডিবিতে কোনও রাউন্ড ট্রিপ নেই। কিন্তু, আপনি যে প্রতিটি সম্পর্কের প্রতিযোগিতা করছেন Loadসেটির জন্য আপনার কাছে একটি গোল-ট্রিপ থাকবে , অন্যদিকে সমস্ত কিছু SingleOrDefaultবোঝার সাথে একত্রে মিশ্রণ Include
ইরাভানচি

আমি যখন এসকিউএল প্রোফাইলে 2 এর সাথে তুলনা করি তখন সন্ধান করুন / লোডটি আমার ক্ষেত্রে ভাল ছিল (আমার 1: 1 সম্পর্ক ছিল)। @ ইরাবঞ্চি: আপনি কি বলতে চাইছেন যে যদি আমার 1: মিটার সম্পর্ক থাকে তবে এটি স্টোরকে এম টাইম বলে ডাকত? ... কারণ এতটা বোঝা যায় না।
লার্নার

3
1: মি রিলেশন নয়, একাধিক সম্পর্ক। প্রতিবার আপনি যখন Loadফাংশনটি কল করবেন তখন কলটি ফিরে আসার পরে সম্পর্কটি পপুলেশন করা উচিত। তাই আপনি যদি Loadএকাধিক সম্পর্কের জন্য একাধিকবার কল করেন তবে প্রতিবারই একটি রাউন্ড ট্রিপ হবে। এমনকি একটি একক সম্পর্কের জন্যও যদি Findপদ্ধতিটি স্মৃতিতে সত্তাটি না খুঁজে পায় তবে এটি দুটি বৃত্তাকার ট্রিপ করে: একটির জন্য Findএবং দ্বিতীয়টির জন্য Load। কিন্তু IncludeSingleOrDefaultপদ্ধতির সত্তা এবং সম্পর্ককে আমি জানি যতদূর যেতে পেরেছি (তবে আমি নিশ্চিত নই)
ইরভানচি

1
সংগ্রহ এবং রেফারেন্সগুলি আলাদাভাবে আচরণ করার চেয়ে যদি এটি কোনওভাবে অন্তর্ভুক্ত নকশাটি অনুসরণ করতে পারত তবে ভাল হত। এটি একটি getById () মুখোমুখি তৈরি করা আরও কঠিন করে তোলে যা কেবলমাত্র এক্সপ্রেশন <ফানক <টি, অবজেক্ট >> (যেমন _repo.GetById (id, x => x.Mylecલેક્શન))
ডেরেক গ্রেয়ার

4
আপনার পোস্টের রেফারেন্সটি উল্লেখ করতে মনঃ এমএসডিএন.মাইক্রোসফটকম /en-us/data/jj574232.aspx#expected
হোসেইন

1

আপনাকে আইবিকিয়ারেবলকে ডিবিসেটে কাস্ট করতে হবে

var dbSet = (DbSet<Item>) db.Set<Item>().Include("");

return dbSet.Find(id);


ডিবিসেটে কোনও .Find বা .FindAsync নেই। এটি কি ইএফ কোর?
থিয়েরি

ইফ কোরটিতে ইফ 6 রয়েছে
রাফায়েল আর সুজা

আমি আশাবাদী ছিলাম এবং তারপরে "অকার্যকস্টএক্সেপশন"
জেডএক্স

0

আমার জন্য কাজ করেনি। তবে আমি এটি এরকম করে সমাধান করেছি।

var item = db.Items
             .Include(i => i.Category)
             .Include(i => i.Brand)
             .Where(x => x.ItemId == id)
             .First();

ঠিক আছে কি না তা জানেন না। তবে অন্য একটি ডেনিস আমাকে একটি ভুল ত্রুটি দিয়েছে .SingleOrDefault(x => x.ItemId = id);


4
ডেনিসের সমাধানটিও অবশ্যই কাজ করবে। ডাবল পরিবর্তে SingleOrDefault(x => x.ItemId = id)শুধুমাত্র ভুল একক কারণে সম্ভবত আপনি এই ত্রুটি আছে ? ===
স্লুমা

6
হ্যাঁ, দেখে মনে হচ্ছে আপনি ব্যবহার করেছেন = না ==। সিনট্যাক্স ভুল;)
রাল্ফ এন

আমি তাদের উভয়ই চেষ্টা করেছিলাম == এবং = তবুও আমাকে .SingleOrDefault (x => x.ItemId = id) এ ত্রুটি দিয়েছে; = / আমার কোডটিতে অন্য কিছু হওয়া উচিত যা ভুল। তবে যেভাবে করলাম তা কি খারাপ পথ? আপনার ডেনিসের কোড অনুসারে ডেনিসের একটি সিনগেল রয়েছে তার অর্থ আমি বুঝতে পারি না।
জোহান

0

কোনও অনুসন্ধানের সাথে ফিল্টার করার আসল কোন সহজ উপায় নেই। তবে আমি কার্যকারিতাটির প্রতিলিপি ঘনিষ্ঠভাবে নিয়ে এসেছি তবে দয়া করে আমার সমাধানের জন্য কয়েকটি জিনিস নোট করুন।

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

  1. অনুসন্ধানটি মৌলিকভাবে পৃথক কারণ এটি ডাটাবেস অনুসন্ধানের আগে ট্র্যাকিংয়ে উপস্থিত থাকলে সত্তাটি গ্রহণ করে।

  2. অতিরিক্তভাবে এটি কোনও অবজেক্ট দ্বারা ফিল্টার করতে পারে যাতে ব্যবহারকারীর প্রাথমিক কীটি জানতে না হয়।

  3. এই সমাধানটি সত্ত্বা ফ্রেমওয়ার্ক কোরের জন্য।

  4. এটি প্রসঙ্গে অ্যাক্সেস প্রয়োজন

এখানে যুক্ত করার জন্য কিছু এক্সটেনশন পদ্ধতি রয়েছে যা আপনাকে প্রাথমিক কী দ্বারা ফিল্টার করতে সহায়তা করবে

    public static IReadOnlyList<IProperty> GetPrimaryKeyProperties<T>(this DbContext dbContext)
    {
        return dbContext.Model.FindEntityType(typeof(T)).FindPrimaryKey().Properties;
    }

    //TODO Precompile expression so this doesn't happen everytime
    public static Expression<Func<T, bool>> FilterByPrimaryKeyPredicate<T>(this DbContext dbContext, object[] id)
    {
        var keyProperties = dbContext.GetPrimaryKeyProperties<T>();
        var parameter = Expression.Parameter(typeof(T), "e");
        var body = keyProperties
            // e => e.PK[i] == id[i]
            .Select((p, i) => Expression.Equal(
                Expression.Property(parameter, p.Name),
                Expression.Convert(
                    Expression.PropertyOrField(Expression.Constant(new { id = id[i] }), "id"),
                    p.ClrType)))
            .Aggregate(Expression.AndAlso);
        return Expression.Lambda<Func<T, bool>>(body, parameter);
    }

    public static Expression<Func<T, object[]>> GetPrimaryKeyExpression<T>(this DbContext context)
    {
        var keyProperties = context.GetPrimaryKeyProperties<T>();
        var parameter = Expression.Parameter(typeof(T), "e");
        var keyPropertyAccessExpression = keyProperties.Select((p, i) => Expression.Convert(Expression.Property(parameter, p.Name), typeof(object))).ToArray();
        var selectPrimaryKeyExpressionBody = Expression.NewArrayInit(typeof(object), keyPropertyAccessExpression);

        return Expression.Lambda<Func<T, object[]>>(selectPrimaryKeyExpressionBody, parameter);
    }

    public static IQueryable<TEntity> FilterByPrimaryKey<TEntity>(this DbSet<TEntity> dbSet, DbContext context, object[] id)
        where TEntity : class
    {
        return FilterByPrimaryKey(dbSet.AsQueryable(), context, id);
    }

    public static IQueryable<TEntity> FilterByPrimaryKey<TEntity>(this IQueryable<TEntity> queryable, DbContext context, object[] id)
        where TEntity : class
    {
        return queryable.Where(context.FilterByPrimaryKeyPredicate<TEntity>(id));
    }

একবার আপনার এই এক্সটেনশন পদ্ধতিগুলি পরে আপনি ফিল্টার করতে পারেন:

query.FilterByPrimaryKey(this._context, id);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.