实体框架:“伪造”一个可查询的导航属性 [英] Entity Framework: "Faking" a queryable navigation property

查看:122
本文介绍了实体框架:“伪造”一个可查询的导航属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



考虑一个例子,我有一本书(由isbn标识)和购买(由isbn标识) - 请注意,图书和购买意图不是直接映射到彼此。



现在我想创建一个扩展方法对于书,以可查询的格式返回所有购买的书籍,如

  public class Book 
{
public virtual string isbn {get;组; }
public virtual string name {get;组; }


//伪代码..不起作用,引发异常
//LINQ to Entities不识别方法[...]方法不能
//转换为存储表达式
public virtual IQueryable< Purchase> get_purchases(DbContext context)
{
return context.Purchases.Where(purchase => purchase

$ b public class购买
{
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()来避免不必要的大量数据集的撤回。



这可以通过创建返回一个

 表达式< Func< Book,IQueryable< Purchase>>> 

或任何类型的(不能尝试这个,因为我绝对可怕的写作表达),还是有其他方法?



免责声明:有一个很好的理由,不明确地映射购买债券;不应该与问题相关,但背景是基于Floremin的答案 to this question



谢谢!

解决方案

LINQ to entity将LINQ查询转换成SQL查询,然后在数据库(服务器)中发送和执行。这就是为什么你得到例外,你的 get_purchases 方法不能被翻译成存储表达式(SQL)。



要获取支付超过90的书籍可以使用LINQ加入运算符:

  var books = from b in dBContext.Books 
加入p在dBContext中。b.isbn上的购买等于p.isbn
其中p.price> 90
选择b;

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



如果你想拥有类似EF的导航属性像 Book.Purchases 在数据库中没有实际关系的情况下,您必须创建自己的数据存储库层,该层将使用 DbContext 将用于所有属性和方法。那么你将会使用它来进行所有的数据访问,也就是你永远不会在代码中直接使用 DbContext 。这是较大项目的一个很好的做法,尤其是在数据库中存储数据之前需要实现一些业务规则和数据操作。查找存储库模式,您一定会找到许多资源。



这是一个:使用ASP.NET MVC和实体框架的存储库模式


I'd like to "fake" a navigation property in an EF-mapped class.

Consider an example where I have books (identified by "isbn") and purchases (identified by "isbn" too) - note that Books and Purchases are intentionally NOT directly mapped to each other.

Now I'd like to create an extension method for "Book" that returns all purchases of the book in a queryable format, something like

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; }
}

So in the end, I'd like to do any arbitrary queries such as (completely random example)

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

But as mentioned in the comment, my approach doesn't work, as EF / LINQ can't make use of my extension method.

Is there any way to do this? The statement should be translateable into a single SQL query; I don't want to use any methods like .ToList() to avoid retreiving unnecessarily huge datasets.

Could this work by creating a function that returns an

Expression<Func<Book, IQueryable<Purchase>>>

or anything of that kind? (Couldn't try this yet as I am absolutely horrible at writing expressions), or is there any other approach?

Disclaimer: There is a good reason to not explicitly map Purchases <-> Bonds; shouldn't be relevant to the question, but the background is based on Floremin's answer to this question

Thanks!

解决方案

LINQ to entities translates LINQ queries into SQL queries which are then sent and executed in the database (server). That's why you get the exception that your get_purchases method cannot be translated into store expression (SQL).

To get books that were paid more than 90 you can use LINQ Join operator:

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

Here is a great LINQ resource: LINQ 101

If you want to have EF-like navigation properties like Book.Purchases where there is no actual relation in the database, you'd have to create your own data repository layer that would be initialized with the DbContext which would be used in all properties and methods. Then you would be using that for all data access - i.e. you'd never use DbContext directly in your code. This is a good practice on larger projects, especially if you need to implement some business rules and data manipulation before it gets stored in the database. Look up "repository pattern" and you're sure to find many resources.

Here's one: Using the Repository Pattern with ASP.NET MVC and Entity Framework

这篇关于实体框架:“伪造”一个可查询的导航属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆