无法将类型X强制转换为类型Y.LINQ to Entities仅支持强制转换EDM原语或枚举类型

时间:2015-03-22 15:10:18

标签: c# linq entity-framework linq-to-entities

我完全理解这个错误,但是有没有办法实现一些代码,以便实体的linq能够理解我的自定义类型应该被视为decimal基元类型?

我已经创建了一个自定义Money类型,它接受一个可构造函数重载的可空decimal。它具有隐式运算符重载和所有其他类型的酷爵士乐。我想在我的linq中使用这个自定义类型实体投影,但是标题中的错误。

我是否可以在我的Money类型上声明一个属性,"嘿,为了linq投影的目的我原始类型decimal&#34 ;

自定义表达式树/访问者是否可以通过某种方式帮助声明所有类型的Money都被视为linq投影的decimal基元?

[HeyImADecimalForLinqProjections] // custom attribute
public class Money : IComparable<Money>
{
    public Money()
    {
        Value = decimal.Zero;
    }
    public Money(decimal? value)
    {
        if (value.HasValue)
            Value = value.Value;
        else
            Value = decimal.Zero;
    }
    public static implicit operator Money(decimal value)
    {
        return new Money(value);
    }
    public static implicit operator Money(decimal? value)
    {
        return new Money(value.Value);
    }
    ...
}

投影示例:

var items = orderQuery.Where(a => a.OrderId = 345)
    .Select(a => new OrderModel()
        {
            OrderId = a.OrderId,
            SubtotalIncludingTax = a.SubtotalIncludingTax, // no dice, SubtotalIncludingTax is of type Money - Unable to cast the type 'System.Decimal' to type 'Money'. LINQ to Entities only supports casting EDM primitive or enumeration types.
            SubtotalIncludingTaxRaw = a.SubtotalIncludingTax, // this is fine because SubtotalIncludingTaxRaw is of type decimal
        })
    .ToList();

我目前的解决方案有效,但我讨厌它。我首先投射到一个匿名类型,然后将匿名类型投影到我的实际模型。这个例子非常淡化,这种双重投影解决方案导致了很多重复,我宁愿避免。

// first get everything as anonymous projection objects in linq to entities
var anonymousItems = orderQuery.Where(a => a.OrderId = 345)
    .Select(a =>
        {
            OrderId = a.OrderId,
            SubtotalIncludingTax = a.SubtotalIncludingTax // decimal to decimal
    .ToList();

// now cast to our actual model since we are back in .Net world
var items = anonymousItems
    .Select(a => new OrderModel()
        {
            OrderId = a.OrderId,
            SubtotalIncludingTax = a.SubtotalIncludingTax // decimal to Money
    .ToList();

1 个答案:

答案 0 :(得分:2)

此时Entity Framework不支持这样的转换。您可以使用映射属性和未映射的属性(例如:

)进行解决方法
public decimal RawTotalIncludingTax {get;set;}
public Money TotalIncludingTax 
{ 
   get { return RawTotalIncludingtax; }
   set { RawTotalIncludingTax = value; }
}

这可能会将额外的匿名类型保存到具体类型选择中,但仍会留下类似的问题。更有可能的解决方案是一种扩展方法来执行以下操作:

using System;

public static class MoneyExtensions
{
    public static string Format(this decimal val){
        if(val < 0)
            return "(" + Math.Abs(val).ToString("N2") + ")";
        else
            return val.ToString("N2");
    }
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(2.2m.Format());
        Console.WriteLine((-12.42m).Format());
    }
}

这样你就不需要自定义类型,但仍然可以使用你所追求的MoneyExtensions和语法!