实体框架:“伪造”可查询的导航属性

本文关键字:查询 导航 属性 框架 伪造 实体 | 更新日期: 2023-09-27 18:30:03

我想"伪造"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<Purchase> 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<Purchase>>>

或者类似的东西?(还不能尝试这个,因为我在写表达式方面绝对很糟糕(,还是有其他方法?

免责声明:有充分的理由不明确映射购买<>债券;应该与问题无关,但背景是基于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

如果要具有类似 EF 的导航属性(如数据库中没有实际关系的Book.Purchases(,则必须创建自己的数据存储库层,该层将使用将在所有属性和方法中使用的DbContext进行初始化。然后,您将将其用于所有数据访问 - 即您永远不会直接在代码中使用DbContext。对于大型项目来说,这是一个很好的做法,尤其是在数据存储到数据库中之前需要实现一些业务规则和数据操作时。查找"存储库模式",您一定会找到许多资源。

下面是一个:将存储库模式与 ASP.NET MVC 和实体框架结合使用