Why can I not use the same poco in code first in EF4.1 to project my data?

旧街凉风 提交于 2019-12-25 05:27:21

问题


Consider the following senario: I have a code first model in my project with the Poco object Animal. The animal row has 50 properties and I only want 5 of them in my application. So I will try to project the 5 properties to a Poco object like this

List<Animal> animals = (from an in dbContext.Animal 
                        where an.IsMammal
                        select new Animal { Id = an.Id , Color = an.Color , Height = an.Height, Width = an.Width , Hair = an.Hair }).ToList();

Is not working for Animal is a StrongTyped object and cannot be converted to sql.

Whereas if I declare a new Poco, exactly the same as the Animal one say AnimalDTO

List<AnimalDTO> animals = (from an in dbContext.Animal 
                        where an.IsMammal
                        select new AnimalDTO { Id = an.Id , Color = an.Color , Height = an.Height, Width = an.Width , Hair = an.Hair }).ToList();

I understand that this happens for Animal is a mapped class as far as Entity Framework is concerned. What I want to understand are the inner workings making the one case a valid option and the second one not. Why does .Net not allow the usage of the Poco object as what it essentially is? Is there a reason for that or is it just a feature missing? Is there any workaround to use the first statement so that I can avoid making hundreds of essentially identical dtos?


回答1:


I can't find any link where this limitation of EF is explained. The current EF (6) source is not too communicative either. Where the exception is thrown it only says

// nominal types are not supported

So I've been pondering about it for a while.

I think the bottom line is you can make a real mess of it. More formally stated: you can create entity objects that EF would not consider to be in a valid state. Suppose your Animal had a reference to a Zoo and also a ZooId property. You could put zoo A in the reference and id value of zoo B in the Id.

Then there is the point of tracking entities. When you do

dbContext.Animal.ToList()

the Animal objects are materialized by EF itself. They are added to the context's cache and the change tracker. If you were able to project into entity objects directly, maybe it wouldn't be obvious enough that they don't get tracked.

Suppose you were to give all your mamals the same color. It might look obvious to do:

    var animals = (from an in dbContext.Animal 
        where an.IsMammal
        select new Animal { Id = an.Id , Color = myColorVariable, .... });
    dbContext.SaveChanges();

But you can't. EF only wants to track entities it has materialized itself so it can trust they are in a valid state.

By the way, you can do what you want if you put .AsEnumerable() right before you make a projection. After AsEnumerable EF is out of control. Similarly you could take a valid Animal object, materialized by EF, and assign a non-matching Zoo object and ZooId to it. The problems will come when EF gains control again, e.g. when you try to save changes.



来源:https://stackoverflow.com/questions/16335344/why-can-i-not-use-the-same-poco-in-code-first-in-ef4-1-to-project-my-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!