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

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

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

public class DALRepository : IDisposable, IGenericRepository where DALEntity : class { private IDbSet dbSet; private NWEntities context; public DALRepository() { context = new NWEntities(); context.Configuration.LazyLoadingEnabled = false; dbSet = context.Set(); } 

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

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

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

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

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

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

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

 public DALEntity Get(string ID, IEnumerable IncludeEntities = null) { var set = ((IObjectContextAdapter)context).ObjectContext.CreateObjectSet(); 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 query = dbSet; query = IncludeEntities.Aggregate(query, (current, includePath) => current.Include(includePath)); query = query.Where(keyNames[0] + "= @0", ID); return query.FirstOrDefault(); } 

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

话虽这么说,我没有看到一种方法没有使用一些反思:

 public IEnumerable Get(params string IDs) { var objectSet = objectContext.CreateObjectSet(); 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,并将生成一个字符串数组。 该函数的第一部分是动态获取主键的名称。

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

使用Linq的Single或First方法,它们允许您搜索IQueryable对象。

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