仅支持初始化程序,实体成员和实体导航属性


102

我收到此异常:

LINQ to Entities不支持指定的类型成员“付费”。仅支持初始化程序,实体成员和实体导航属性。

    public ActionResult Index()
    {
        var debts = storeDB.Orders
            .Where(o => o.Paid == false)
            .OrderByDescending(o => o.DateCreated);

        return View(debts);
    }

我的模特班

public partial class Order
{
    public bool Paid {
        get {
            return TotalPaid >= Total;
        }
    }

    public decimal TotalPaid {
        get {
            return Payments.Sum(p => p.Amount);
        }
    }

Payments是一个包含字段金额的Related表,如果删除其中显示有关付款的正确信息的Where子句,该查询将起作用,任何提示代码有什么问题?

像建议的答案一样解决:

    public ActionResult Index()
    {
        var debts = storeDB.Orders
            .OrderByDescending(o => o.DateCreated)
            .ToList()
            .Where(o => o.Paid == false);

        return View(debts);
    }

15
简单答案:您不能在linq-to-entities查询中使用未映射的属性!仅映射的属性会转换为SQL。
Ladislav Mrnka,2011年

Answers:


114

实体试图将您的Paid属性转换为SQL,但不能执行,因为它不是表架构的一部分。

您可以做的是让Entity查询没有付费过滤器的表,然后过滤掉没有付费的表。

public ActionResult Index()
{
    var debts = storeDB.Orders
        //.Where(o => o.Paid == false)
        .OrderByDescending(o => o.DateCreated);

    debts = debts.Where(o => o.Paid == false);

    return View(debts);
}

当然,这意味着您将所有数据带回Web服务器并在其上过滤数据。如果要在数据库服务器上进行过滤,则可以在表上创建“计算列”或使用“存储过程”。


25

只是不得不解决类似的问题。上述解决方案需要内存处理,这是一个不好的做法(延迟加载)。

我的解决方案是编写一个返回谓词的助手:

public static class Extensions
{
    public static Expression<Func<Order, bool>> IsPaid()
    {
        return order => order.Payments.Sum(p => p.Amount) >= order.Total;
    }
}

您可以将linq语句重写为:

var debts = storeDB.Orders
                    .Where(Extensions.IsPaid())
                    .OrderByDescending(o => o.DateCreated);

当您要重用计算逻辑(DRY)时,这很方便。缺点是逻辑不在您的域模型中。


1
有许多库试图使这种方法更加“内置”,请参见:stackoverflow.com/a/27383641/470183。Linq-to-entities仅限于使用“规范函数”的表达式-可以将其转换为SQL。C#6引入了“表达式主体函数”,但这些不是真正的lambda(请参阅:stackoverflow.com/a/28411444/470183)。不过这将是件好事,这在框架因此WIBNI data.uservoice.com/forums/...
詹姆斯关闭

1
感谢您提供的这个简单明了的示例Expression<Func<xx,yy>>。我以前曾经了解过,但现在看来很明显。
AlexB

17

此问题也可能源于[NotMapped]在数据库模型和视图模型中具有相同名称的属性。

在投影期间,AutoMapper会尝试从数据库中选择它;并且数据库中不存在NotMapped属性。

解决方案是Ignore在从数据库模型映射到视图模型时,使用AutoMapper配置中的属性。

  1. 在数据库模型中查找[NotMapped]具有名称的属性Foo
  2. Foo在视图模型中查找具有相同名称的属性。
  3. 如果是这种情况,请更改您的AutoMapper配置。加.ForMember(a => a.Foo, b => b.Ignore());

Dang AutoMapper Projection也抓住了我,谢谢您的回答!
Chase Florell '18

15

Linq将这些语句转换为SQL语句,然后将其执行到数据库中。

现在,此转换仅对实体成员,初始化程序和实体导航属性进行。因此,要实现功能或进行属性比较,我们需要先将它们转换为内存中列表,然后再应用功能来检索数据。

因此总的来说,

var debts = storeDB.Orders.toList()
        .Where(o => o.Paid == false)
        .OrderByDescending(o => o.DateCreated);

21
我建议要求某人在订单上进行toList()是危险的,因为这将意味着检索整个列表
elgrego 2016年

这对我有好处,因为我的问题属性在Sum Linq函数中,而不在Where子句中。因此,我没有得到不必要的数据,并且在检索的数据上,我正在执行在列表上使用的Linq Sum函数。谢谢!一开始看起来很糟的东西在某些情况下可能会很有帮助!
Dov Miller

11

另一个可能的原因是因为您正在使用IEnumerable自己的财产,而不是ICollection

所以代替:

public class This
{
    public long Id { get; set; }
    //...
    public virtual IEnumerable<That> Thats { get; set; }
}

做这个:

public class This
{
    public long Id { get; set; }
    //...
    public virtual ICollection<That> Thats { get; set; }
}

而且您太笨拙了……失去了2个小时的愚蠢东西。



0

我遇到了这个问题,因为有一个只有get without set属性的成员变量

这意味着它auto calculatednot stored作为列中的the table

因此它not existtable schema

所以make sure,任何成员变量not auto calculated,以have一个gettersetter属性


-1

您的edmx和上下文模型具有一些新添加到db中的diffrent属性。

更新您的EDMX,正确刷新它,合并您的项目,然后再次运行。

它将解决您的问题。

此致Ganesh Nikam

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.