问题
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