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

时间:2014-11-11 12:16:21

标签: c# linq entity-framework

我想"假" EF映射类中的导航属性。

考虑一个例子,我有书籍(由#34; isbn"标识)和购买(由#34; 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>>>

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

免责声明:有充分的理由不明确地映射购买&lt; - &gt;债券;不应该与问题相关,但背景是基于Floremin的回答to this question

谢谢!

1 个答案:

答案 0 :(得分:1)

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,您必须创建自己的数据存储库层,该层将使用{{1}初始化将在所有属性和方法中使用。然后,您将使用它进行所有数据访问 - 即您永远不会在代码中直接使用DbContext。这是大型项目的一种很好的做法,特别是如果您需要在将数据存储到数据库之前实现某些业务规则和数据操作。查找“存储库模式”,您肯定会找到许多资源。

这是一个:Using the Repository Pattern with ASP.NET MVC and Entity Framework