entity framework:“伪造”可查询的导航属性

我想在EF映射的类中“伪造”导航属性。

考虑一个例子,我有书(由“isbn”标识)和购买(由“isbn”标识) – 请注意,书籍和购买有意不直接相互映射。

现在我想为“Book”创建一个扩展方法,以一种可查询的格式返回书籍的所有购买内容

public class Book { public virtual string isbn { get; set; } public virtual string name { get; set; } // Pseudo-code .. does not work, throws an exception // "LINQ to Entities does not recognize the method [...], and this method cannot // be translated into a store expression public virtual IQueryable get_purchases(DbContext context) { return context.Purchases.Where(purchase => purchase.isbn == this.isbn); } } public class Purchase { public virtual string isbn { get; set; } public virtual double price { get; set; } } 

所以最后,我想做任何任意查询,如(完全随机的例子)

 dbContext.Books.Where(book => book.get_purchases(dbContext).Where(purchase => purchase.price > 90)) 

但正如评论中所提到的,我的方法不起作用,因为EF / LINQ无法使用我的扩展方法。

有没有办法做到这一点? 该语句应该可以转换为单个SQL查询; 我不想使用像.ToList()这样的任何方法来避免不必要的大数据集。

这可以通过创建一个返回的函数来工作

 Expression<Func<Book, IQueryable>> 

或者那种类似的东西? (由于我在撰写表达方式时非常可怕,所以无法尝试这种方法),还是有其他办法?

免责声明:有充分的理由不明确地映射购买债券; 与问题无关,但背景是基于Floremin 对这个问题的回答

谢谢!

LINQ to实体将LINQ查询转换为SQL查询,然后在数据库(服务器)中发送和执行。 这就是为什么你得到的例外是你的get_purchases方法无法转换成商店表达式(SQL)。

要获得支付超过90的书籍,您可以使用LINQ Join运算符:

 var books = from b in dBContext.Books join p in dBContext.Purchases on b.isbn equals p.isbn where p.price > 90 select b; 

这是一个很棒的LINQ资源: LINQ 101

如果你想拥有像Book.Purchases这样的类似EF的导航属性,而数据库中没有实际的关系,你必须创建自己的数据存储库层,用DbContext初始化,这将在所有属性和方法。 然后你将使用它来进行所有数据访问 – 即你永远不会在你的代码中直接使用DbContext 。 这是大型项目的一种很好的做法,特别是如果您需要在将数据存储到数据库之前实现某些业务规则和数据操作。 查找“存储库模式”,您肯定会找到许多资源。

这是一个: 使用存储库模式与ASP.NET MVC和entity framework