3

我正在编写一个通用存储库以使用 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));
}

我不能将 find 与 IQueryable 一起使用。而且我不能直接 Find() 因为我不能将包含传递给它。如果我在 IQueryable 上使用 where lambda,我如何告诉它使用实体的 PK?我想我可能有一个泛型约束,它坚持泛型类型必须实现一些具有明确定义的主列名称(例如“ID”)的 IPkey 接口,但是我不能使用 DBContext 生成的实体,因为它们必须实现这个界面。如果需要,我可以更改 T4 来执行此操作——而且我已经将其更改为发出 XML 注释,因此不太反感——但有人有更简单的方法吗?我想我需要的是一个接受包含列表的重载 find() 。

所以我的问题是如何将 Find 与包含一起使用,或者如何在它知道 PK 的地方编写 lambda?我无法接收这样的 lambda 作为参数,因为它最终会被 WCF 服务使用。

4

3 回答 3

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();
}
于 2012-10-26T03:04:30.123 回答
0

您可以按照此处描述的方式获得您的密钥: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 数组中。

于 2012-10-25T00:38:28.443 回答
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);
}
于 2012-10-25T10:01:49.973 回答