在LINQ到实体类型成员的支持? [英] Type member support in LINQ-to-Entities?

查看:183
本文介绍了在LINQ到实体类型成员的支持?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用实体框架模型中的MVC3项目中,我已经打上了一类这样的:

I have an MVC3 project using the Entity Framework model in which I've marked up a class like this:

public partial class Product
{
    public bool IsShipped
    {
        get { /* do stuff */ }
    }
}

和我想在LINQ EX pression使用方法:

and which I want to use in a LINQ expression:

db.Products.Where(x => x.IsShipped).Select(...);

不过,我得到以下错误:

however, I get the following error:

System.NotSupportedException是未处理由用户code消息=的   指定类型成员的IsShipped是不是实体支持LINQ。   只有初始化,实体成员和实体导航属性   都支持。来源= System.Data.Entity的

System.NotSupportedException was unhandled by user code Message=The specified type member 'IsShipped' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported. Source=System.Data.Entity

我GOOGLE了,但没有发现任何明确的关于这样的用法我想:

I've googled but not found anything definitive about this usage to I tried:

public partial class Product
{
    public bool IsShipped()
    {
        /* do stuff */
    }
}

db.Products.Where(x => x.IsShipped()).Select(...);

但后来我得到:

but then I get:

System.NotSupportedException是未处理由用户code消息= LINQ   以实体不能识别方法布尔IsShipped()方法,   而且这种方法不能被翻译成店前pression。
  来源= System.Data.Entity的

System.NotSupportedException was unhandled by user code Message=LINQ to Entities does not recognize the method 'Boolean IsShipped()' method, and this method cannot be translated into a store expression.
Source=System.Data.Entity

有功能那里,我不想打造成为LINQ查询本身...什么是一个很好的方式来处理呢?

there's functionality there that I don't want to build into the LINQ query itself... what's a good way to handle this?

*更新*

达林使正确的观点,无论在执行完成 IsShipped 将需要转换为SQL查询和编译器可能不知道该怎么办它,从而获​​取所有对象到内存似乎是唯一的选择(除非直接查询到数据库由)。我想它是这样的:

Darin makes the valid point that whatever is done in the implementation of IsShipped would need to be converted to a SQL query and the compiler probably doesn't know how to do it, thus retrieving all objects into memory seems the only choice (unless a direct query to the database is made). I tried it like this:

IEnumerable<Product> xp = db.Quizes
    .ToList()
    .Where(x => !x.IsShipped)
    .Select(x => x.Component.Product);

但它生成此错误:

but it generates this error:

一个关系多重约束冲突发生了:一个   的EntityReference可以具有不超过一个相关目的,但   查询返回多个相关对象。这是一个不可恢复   错误。

A relationship multiplicity constraint violation occurred: An EntityReference can have no more than one related object, but the query returned more than one related object. This is a non-recoverable error.

但奇怪的工作的:

IEnumerable<Product> xp = db.Quizes
    .ToList()
    .Where(x => x.Skill.Id == 3)
    .Select(x => x.Component.Product);

为什么会是这样?

why would that be?

*更新II *

抱歉,这一句也不行......

sorry, that last statement doesn't work either...

*更新III *

我关闭了这个问题有利于寻求解决方案,作为建议在这里打平我的逻辑放到查询 - 讨论会移至<一个href="http://stackoverflow.com/questions/7787625/flattening-a-loop-with-lookups-into-a-single-linq-ex$p$pssion">this新帖子。第二个选择,检索整个原始查询到内存中,可能是不能接受的,但在第三的,在实施逻辑作为直接查询数据库,有待探讨。

I'm closing this question in favour of pursuing a solution as suggested here to flatten my logic into a query - the discussion will move to this new post. The second alternative, to retrieve the entire original query into memory, is likely unacceptable, but the third, of implementing the logic as a direct query to the database, remain to be explored.

感谢大家提出的宝贵意见。

Thanks everyone for the valuable input.

推荐答案

只有这样,才能使这个干(避免重复的逻辑中 IsShipped 其中,第一次),并避免加载所有的数据到内存中,然后再应用滤镜是提取 IsShipped 的内容转换成一名前pression。然后,您可以使用此EX pression作为参数传递给其中, IsShipped 为好。例如:

The only way to make this "DRY" (avoid repeating the logic inside of IsShipped in the Where clause again) and to avoid loading all data into memory before you apply the filter is to extract the content of IsShipped into an expression. You can then use this expression as parameter to Where and in IsShipped as well. Example:

public partial class Product
{
    public int ProductId { get; set; }           // <- mapped to DB
    public DateTime? ShippingDate { get; set; }  // <- mapped to DB
    public int ShippedQuantity { get; set; }     // <- mapped to DB

    // Static expression which must be understood
    // by LINQ to Entities, i.e. translatable into SQL
    public static Expression<Func<Product, bool>> IsShippedExpression
    {
        get { return p => p.ShippingDate.HasValue && p.ShippedQuantity > 0; }
    }

    public bool IsShipped // <- not mapped to DB because readonly
    {
        // Compile expression into delegate Func<Product, bool>
        // and execute delegate
        get { return Product.IsShippedExpression.Compile()(this); }
    }
}

本可以执行的查询,像这样:

The you can perform the query like so:

var result = db.Products.Where(Product.IsShippedExpression).Select(...).ToList();

在这里,你将有只有一个地方把逻辑( IsShippedEx pression ),然后将其用于数据库查询,并在你的 IsShipped 属性为好。

Here you would have only one place to put the logic in (IsShippedExpression) and then use it for database queries and in your IsShipped property as well.

我会这么做吗?在大多数情况下可能是否定的,因为编译EX pression缓慢。除非逻辑非常复杂,有可能是受到改变,我在的情况下使用 IsShipped 的性能没有关系,我会重复的逻辑。它总是可以提取经常使用的过滤器到一个扩展方法:

Would I do this? In most cases probably no, because compiling the expression is slow. Unless the logic is very complex, likely a subject to change and I am in a situation where the performance of using IsShipped doesn't matter, I would repeat the logic. It's always possible to extract often used filters into an extension method:

public static class MyQueryExtensions
{
    public static IQueryable<Product> WhereIsShipped(
        this IQueryable<Product> query)
    {
        return query.Where(p => p.ShippingDate.HasValue && p.ShippedQuantity >0);
    }
}

和再使用这种方式:

var result = db.Products.WhereIsShipped().Select(...).ToList();

您将有两个地方虽然保持逻辑: IsShipped 属性和扩展方法,但你可以重复使用它

You would have two places though the maintain the logic: the IsShipped property and the extension method, but then you can reuse it.

这篇关于在LINQ到实体类型成员的支持?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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