update - what is entity framework in c#




تصفية إطار الكيان حسب مفتاح أساسي (2)

أنا أكتب خدمة طين عامة أحاول تنفيذ أسلوب Get مع طريقة افتراضية اختيارية لتشمل خصائص ومع ذلك أواجه بعض المشاكل لأن FindAsync أعلن فقط على DbSet :

public async virtual Task<TDTO> Get(object[] id)
{
     // I want to do something like this
     var entity = await this.ApplyGetIncludes(this.GetEntityDBSet()).FindAsync(id)
     return this.AdaptToDTO(entity);
}

protected virtual DbSet<TEntity> GetEntityDBSet()
{
    return this._context.Set<TEntity>();
}

protected virtual IQueryable<TEntity> ApplyGetIncludes(IQueryable<TEntity> queryable)
{
    return queryable;
}

أريد أن أفعل شيئا من هذا القبيل كما هو موضح أعلاه:

var entity = await this.ApplyGetIncludes(this.GetEntityDBSet()).FindAsync(id)

ولكن أنا أعلم أن لن تعمل لأننا بحاجة إلى مجموعة دب لذلك أود أن الإعداد للقيام بشيء من هذا القبيل:

var entity = await this.ApplyGetIncludes(this.GetEntityDBSet().FilterByPK(id))
                      .FirstOrDefaultAsync();

لا أحد يعرف كيف يمكنني تصفية حسب المفتاح الأساسي من DbSet ؟


من الممكن، ولكن الأسلوب يحتاج إلى الوصول إلى DbContext أجل الحصول على البيانات الوصفية التي تصف المفتاح الأساسي. ثم يمكن بناء ديناميكيا المسند التعبير لامدا استنادا إلى تلك البيانات الوصفية والقيم التي تم تمريرها.

أولا نحن بحاجة إلى طريقة تجمع المعلومات حول خصائص المفتاح الأساسي للكيان.

ل إف الأساسية انها بسيطة:

static IReadOnlyList<IProperty> GetPrimaryKeyProperties(DbContext dbContext, Type clrEntityType)
{
    return dbContext.Model.FindEntityType(clrEntityType).FindPrimaryKey().Properties;
}

ل EF6 انها أكثر تعقيدا قليلا، ولكن لا تزال قابلة للتنفيذ:

struct KeyPropertyInfo
{
    public string Name;
    public Type ClrType;
}

public static IReadOnlyList<KeyPropertyInfo> GetPrimaryKeyProperties(DbContext dbContext, Type clrEntityType)
{
    var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
    var metadata = objectContext.MetadataWorkspace;
    var objectItemCollection = ((ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace));
    var entityType = metadata.GetItems<EntityType>(DataSpace.OSpace)
        .Single(e => objectItemCollection.GetClrType(e) == clrEntityType);
    return entityType.KeyProperties
        .Select(p => new KeyPropertyInfo
        {
            Name = p.Name,
            ClrType = p.PrimitiveType.ClrEquivalentType
        })
        .ToList();
}

الآن طريقة بناء المسند هي مثل هذا:

static Expression<Func<T, bool>> BuildKeyPredicate<T>(DbContext dbContext, object[] id)
{
    var keyProperties = GetPrimaryKeyProperties(dbContext, typeof(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);
}

الجزء الصعب هنا هو كيفية السماح إف استخدام الاستعلام المعلمة. إذا كنا ببساطة استخدام Expression.Constant(id[i]) ، فإن سكل التي تم إنشاؤها استخدام قيم ثابتة بدلا من المعلمات. لذا فإن الخدعة هي استخدام التعبير وصول الأعضاء (أي الممتلكات أو الحقل) للتعبير المستمر عن نوع مجهول مؤقت عقد القيمة (محاكاة أساسا إغلاق).

بمجرد الحصول على المسند من الأسلوب أعلاه، يمكنك استخدامه ل FirstOrDefaultAsync أو أي طريقة تصفية أخرى.


يبدو السؤال صعبا بعض الشيء. في رأيي، فإنه من المستحيل تحقيق لك تهدف بطريقة عامة لتصفية حسب المفتاح الأساسي لجميع الجداول. معرف في لك أعلاه، يعني مفاتيح الجدول (دبسيت). وعليك أن تعالج الهوية بشكل مختلف وفقا لاستعلام الجدول مختلفة. وبهذه الطريقة، أعتقد أنك أفضل استخدام طريقة مجردة كما يلي للحصول على البيانات

public async abstract Task<TDTO> Get(object[] id)
{
   //I want to do something like this
   var entity = await this.ApplyGetIncludes(this.GetEntityDBSet()).FindAsync(id)
   return this.AdaptToDTO(entity);
}

يجب تنفيذ طريقة جيت وفقا لك الجداول ملموسة (في حين أن كل جدول عادة مفاتيح أساسية مختلفة).





find