这是我想要做的:
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<DatabaseModels.User>)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'.
解决方法
这不是一个微不足道的问题,也没有“一刀切”的方法.你真正想要的是
lazy loading,which was not included in EF7 for many reasons.
我不知道你展示的代码应该做什么,但是一个选择是引入一个存储库模式,你在集合级别指定“要包含的实体”:
public class UserRepository { private readonly IQueryable<User> _dataSet; public UserRepository(IQueryable<User> userDataSet) { _dataSet = userDataSet; } public IQueryable<User> Include() { return _dataSet.Include(u => u.Book) .Include(u => u.Blog); } }
并且您可以将许多逻辑移动到通用基类,只留下Include()方法.例如,您可以在显示(或枚举或…)时使用字符串,以仅选择要包括的相关实体:
public class GenericRepository { // ... public IQueryable<User> Include(string includeGroup = null) { return IncludeGroup(includeGroup); } protected virtual IncludeGroup(string includeGroup) { return _dataSet; } }
然后在UserRepository中:
protected override IQueryable<User> 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();
一种替代方案是始终包含所有导航属性(递归),但就查询效率而言,这将是一种可怕的方法,因为每个查询将是对所有相关表的一个大规模连接,无论是否必要.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。