我正在编写一个通用存储库,使用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服务使用。
答案 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)