Cast() exception: LINQ to Entities only supports casting EDM primitive or enumeration types

asp.net-mvc c# casting entity-framework linq-to-entities

Question

I want to display some entity named CriminalEvent in a general-purpose MVC view I wrote. The view requires that the Model pass to it shall implement the IDataModel interface. Now, CriminalEvent has the properties to implement this interface but under a different name and I cannot change it.

So in my code I inherited CriminalEvent and my derived class (also called CriminalEvent, stupid I guess but allows me to avoid many code changes...) has explicit interface code:

Using ViewApp;
public interface IDataModel
{
    int ID { get; set; }
    int CriminalEventID { get; set; }
}

public class ViewCriminalEvent : AIM.Police.DB.CriminalEvent, IDataModel
{
    int IDataModel.ID
    {
        get { return CriminalEventID; }
        set { CriminalEventID = value; }
    }
}

(I know, in this case the interface's ID property equals CriminalEventID, it's Ok)

I expected to be able to read the AIM.Police.DB.CriminalEvent Entities and populate my view model by Linq to Entities Cast()ing them to the derived CriminalEvent, like this:

The view model (I need to populate the CriminalEvents property):

Using ViewApp;
public class CriminalEventMainViewModel
{
    public IEnumerable<IDataModel> CriminalEvents { get; set; }
    public IDataModel SelectedEntity { get; set; }

    public string SubEntityDisplayName { get; set; }

    public IEnumerable<IDataModel> SubEntityCollection { get; set; }
    public IDataModel SelectedSubEntity { get; set; }
}

and the Controller code:

Using ViewApp;    
private ViewResult CriminalEventIndexView(CriminalEvent selectedCriminalEvent = null)
{
    CriminalEventMainViewModel viewModel =
        new CriminalEventMainViewModel();

    using (var db1 = new AIM.Police.DB.InvestigationContext(lazyLoadingEnabled: false))
    {
        viewModel.CriminalEvents = db1.CriminalEvents.Cast<ViewCriminalEvent>().ToList(); // THIS LINE THROWS THE EXCEPTION
        viewModel.SelectedEntity = selectedCriminalEvent;
    }
    return View("Index", (object)viewModel);
}

Note both the original CriminalEvent class and the InvestigationContext are found in the AIM.Police.DB dll that I cannot touch

The Error:

Unable to cast the type 'AIM.Police.DB.CriminalEvent' to type 'InvestigationSimulator.Models.CriminalEvent'. LINQ to Entities only supports casting EDM primitive or enumeration types.

Why do I get this error? Remarks on my approach are always welcome..

1
2
1/1/2014 10:45:27 AM

Accepted Answer

Since you're getting all of the entities, you could materialize the query first, then perform the cast.

This would perform the Cast in memory instead of trying to formulate it as part of the query translation. The error comes because LINQ to Entities doesn't support transforming the SQL to a non-entity class, even when it inherits from an entity class, because there is no mapping for the additional columns to the SELECT statement. By materializing the data, then performing the Cast in memory (LINQ to Objects), you avoid the translation error.

However, in your case, you have the inheritance backwards for this to work. For it to work, I'd suggest having the DB model implement IDataModel and avoid the cast entirely, see http://msdn.microsoft.com/en-us/library/vstudio/bb738696(v=vs.100).aspx and http://msdn.microsoft.com/en-us/library/wa80x488.aspx. In particular, your partial class can implement the interface (honestly don't remember if the designer allows you to add an interface definition since I only do code-first these days). Note that may remove the need for your view-specific model entirely.

viewModel.CriminalEvents = db1.CriminalEvents.ToList();

The alternative, which I would probably do, is keep the view model completely separate (not have it inherit from the entity class) and use AutoMapper to map between them.

var criminalEvents = db1.CriminalEvents.ToList();
viewModel.CriminalEvents = Mapper.Map<CriminalEventViewModel>(criminalEvents);
3
12/31/2013 5:08:08 PM

Popular Answer

Enumerable.Cast<TResult> is trying to cast every element in the collection. And it fails in your scenario (no surprise) because you are trying to cast instances of parent (AIM.Police.DB.CriminalEvent) class to objects of child (InvestigationSimulator.Models.CriminalEvent) class. You cannot do such casting in C#.

In order to fix this you will need to load objects from your DB first and then convert (map) them manually to your Model class. Easiest code is like this:

viewModel.CriminalEvents = db1.CriminalEvents.ToList().Select(ce => new InvestigationSimulator.Models.CriminalEvent() { Id = ce.Id, }).ToList();


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow