Cannot apply type X to type Y. LINQ to Entities only supports listing of EDM primitives or enumeration types

I fully understand this error, but is there a way to implement some code so that linq for objects understands that my user type should be considered as a primitive type decimal?

I created my own type Money, which is nullable decimalfor one of my constructor overloads. It has an implicit operator overload and all other types of cool jazz. I want to use this custom type in my linq objects, but alas, there is an error in the header.

Is there an attribute that I can declare in my type Moneythat says: "Hey, for the purposes of linq-predictions, I'm from a primitive type decimal"?

Is there any way to create a tree / visitor for a custom expression to declare that all types Moneyshould be considered primitives decimalfor linq predictions?

[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);
    }
    ...
}

Projection Example:

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();

My current solution works, but I hate it. First, I design an anonymous type, then project an anonymous type on my actual model. This example is heavily irrigated, and this dual projection solution leads to a lot of repetitions that I would rather avoid.

// 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();
+4
source share
1 answer

At this time, the Entity Framework does not support casting like this. You may have a workaround with a display property and a non-display property, for example:

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 , .

+2

All Articles