如何简化与entity framework的有多种关系的访问?

这是我想要做的:

var user = db.User.First(conditions); user.Book.First(); 

目前这是我必须这样做的。

 var user = db.User.Include("Book").First(conditionsForUser); user.Book.First(); 

我想简化这个的原因是因为我不想在每次想要访问关系时指定包含的内容。 看起来很麻烦。

例如:鉴于我之前已经检索过用户,我希望能够执行以下操作:

 user.Book.First() user.Blog.First() user.SomeOtherHasManyRelationship.Where(conditions) 

这是我到目前为止:

  public object RelationshipFor(string relationship) { using (var db = User.DbContext()) { var relationshipType = TypeRepresentedBy(relationship); // unused for now, not sure if I need the type of the relationship var myTable = ((ICollection)db.Send(RelationshipName)); // RelationshipName is "User" in this instance. var meWithRelationship = myTable.Where(i => i.Send(IdColumn) == Id).Include(relationship); // currently, myTable doesn't know about 'Where' for some reason. return meWithRelationship.Send(relationship); } } 

然后如何使用将是如下:

 user.RelationshipFor("Book") // returns a list of books 

我的代码中有一些其他逻辑,它进一步抽象出来,这将允许我做user.Book.First() 。 希望我可以获得许多开源许可,因为我在ActiveRecord风格的crud之后建模了很多api。

请注意,我正在使用我为帮助处理动态性而设置的一组扩展来减轻痛苦: https : //github.com/NullVoxPopuli/csharp-extensions

更新1:

  public object RelationshipFor(string relationship) { using (var db = User.DbContext()) { var myTable = (DbSet)db.Send(RelationshipName); var myInclude = myTable.Include(i => i.Send(relationship)); var meWithRelationship = myInclude.First(i => (long)i.Send(IdColumn) == Id); return meWithRelationship.Send(relationship); } } 

就目前而言,我已经对用户的演员进行了硬编码,试图让事情变得有效。 我现在的错误是:

 Unable to cast object of type 'System.Linq.Expressions.MethodCallExpressionN' to type 'System.Linq.Expressions.MemberExpression'. 

这不是一个小问题,也没有“一刀切”的方法。 你实际上看起来是延迟加载,由于很多原因,它不包含在EF7中 。

我不知道您展示的代码应该做什么,但一种选择是引入一个存储库模式,您可以在集合级别指定“要包含的实体”:

 public class UserRepository { private readonly IQueryable _dataSet; public UserRepository(IQueryable userDataSet) { _dataSet = userDataSet; } public IQueryable Include() { return _dataSet.Include(u => u.Book) .Include(u => u.Blog); } } 

并且您可以将许多逻辑移动到通用基类,只留下Include()方法。 例如,您可以在显示(或枚举或…)时使用字符串,以仅选择要包括的相关实体:

 public class GenericRepository { // ... public IQueryable Include(string includeGroup = null) { return IncludeGroup(includeGroup); } protected virtual IncludeGroup(string includeGroup) { return _dataSet; } } 

然后在UserRepository

 protected override IQueryable IncludeGroup(string includeGroup) { switch (includeGroup.ToUpperInvariant()) { case "BOOK": return _dataSet.Include(u => u.Book) .Include(u => u.Book.Author); case "BLOG": return _dataSet.Include(u => u.Blog); default: return base.Include(includeGroup); } } 

然后像这样使用它:

 var userRepo = new UserRepository(db.User); var userWithBooks = userRepo.Include("Book"); var firstUser = userWithBooks.FirstOrDefault(u => u.Name == "Foo"); var firstUserFirstBook = firstUser.Book.FirstOrDefault(); 

一种替代方案是始终包括所有导航属性(递归地),但就查询效率而言,这将是一种可怕的方法,因为每个查询将是对所有相关表的一个大规模连接,无论是否必要。