DBContext Find with Includes - 其中lambda带有主键

时间:2012-10-24 23:44:00

标签: c# entity-framework find dbcontext

我正在编写一个通用存储库,使用DBContext与EF进行交互。

我有一个通用的Get()方法,它接收主键值并返回实体:

public class DALRepository<DALEntity> : IDisposable, IGenericRepository<DALEntity> where DALEntity : class
{
private IDbSet<DALEntity> dbSet;
private NWEntities context;

public DALRepository()
{
  context = new NWEntities();
  context.Configuration.LazyLoadingEnabled = false;
  dbSet = context.Set<DALEntity>();
}

这是一个简单的get方法 - 只适用于PK - 正是我想要的。

public DALEntity Get(string ID)
{
   return dbSet.Find(ID);
}

我现在想要改变它以允许消费者传递包含列表 - 以及只返回他们可以请求返回订单的客户。这是我遇到麻烦的地方。如果我这样做:

public DALEntity Get(string ID, IEnumerable<string> IncludeEntities = null)
{
      IQueryable<DALEntity> query = dbSet;
      query = IncludeEntities.Aggregate(query, (current, includePath) => current.Include(includePath));
}

我不能在IQueryable中使用find。我不能直接查找(),因为我无法传递包含它。如果我在IQueryable上使用where lambda,我怎么告诉它使用实体的PK?我想我可以有一个泛型约束,坚持泛型类型必须实现一些具有良好定义的主列名称(如“ID”)的IPkey接口,但是我不能使用由DBContext生成的实体,因为它们必须实现这个界面。如果我需要的话,我可以更改T4来执行此操作 - 我已经将其更改为发出XML注释,因此不要过于厌恶 - 但是有人有更简单的方法吗?我想我需要的是一个重载的find(),它接受一个包含列表。

所以我的问题是如何使用Find with includes,或者如何在知道PK的情况下编写lambda?我无法接收这样的lambda作为参数,因为这最终会被WCF服务使用。

3 个答案:

答案 0 :(得分:2)

有点奇怪地回答你自己的问题,但万一其他人有这个问题,这就是我所做的。我使用动态LINQ的东西,并使用.Where()的字符串重载版本。我使用了上面提到的一个链接来弄清楚如何获取主键(我的也是来自DBContext),现在这个方法看起来像这样:

public DALEntity Get(string ID, IEnumerable<string> IncludeEntities = null)
{
  var set = ((IObjectContextAdapter)context).ObjectContext.CreateObjectSet<DALEntity>();
  var entitySet = set.EntitySet;
  string[] keyNames = entitySet.ElementType.KeyMembers.Select(k => k.Name).ToArray();
  Debug.Assert(keyNames.Length == 1, "DAL does not work with composite primary keys or tables without primary keys");

  IQueryable<DALEntity> query = dbSet;
  query = IncludeEntities.Aggregate(query, (current, includePath) => current.Include(includePath));

  query = query.Where(keyNames[0] + "= @0", ID);
  return query.FirstOrDefault();
}

答案 1 :(得分:0)

您可以按照此处描述的方式获取您的Key dinamycally:https://stackoverflow.com/a/10796471/971693

话虽如此,如果不使用某种反思,我看不出方法:

public IEnumerable<DALEntity> Get(params string IDs)
{
   var objectSet = objectContext.CreateObjectSet<YourEntityType>();
   var keyNames = objectSet.EntitySet.ElementType.KeyMembers.First(k => k.Name);

   return dbSet.Where(m => ID.Contains((string)m.GetType().GetProperty(keyNames ).GetValue(m, null));
}

首先,params字符串ID将允许您传递1个或更多ID,并将生成一个字符串数组。 该函数的第一部分是动态获取主键的名称。

第二部分创建一个查询,以返回集合中的所有元素,其中主键值(通过反射获得)包含在参数中接收的ID数组中。

答案 2 :(得分:0)

使用Linq的SingleFirst方法,可以搜索IQueryable个对象。

public DALEntity Get(string ID, IEnumerable<string> IncludeEntities = null)
{
      IQueryable<DALEntity> query = dbSet;
      query = IncludeEntities.Aggregate(query, (current, includePath) => current.Include(includePath));
      query = query.Single(x=>x.Id == ID);
}