Reputation: 7657
I have in my database an Object
which has an object Owner
. Owner
has a string Name
. Object
also holds object Details
.
I need the Object
, it's Details
, and the Owner.Name
. I want to prevent loading the whole Owner
object (as detailled here) and I want only a single database query.
I tried:
DataContext.Objects.Select(o => new { Object = o, OwnerName= o.Owner.Name })
.Include(o => o.Object.Details);
but it throws:
System.InvalidOperationException: 'The result type of the query is neither an EntityType nor a CollectionType with an entity element type. An Include path can only be specified for a query with one of these result types.
Also tried calling Include
before Select
:
var d = DataContext.Objects.Include(o => o.Details)
.Select(o => new { Object = o, OwnerName= o.Owner.Name });
But this ignores the Include
, ie. Accessing d.Details
causes a DB query.
Any ideas?
Upvotes: 1
Views: 1102
Reputation: 13783
You're touching on an issue that does exist in EF.
The problem lies in how EF handles the loading of data. It loads all scalar properties of an object, but not the navigational properties.
Include
influences this behavior, by telling EF to also include a specified navigational property (with all of its scalar properties)
But then we get to Select
. When you use this, you are essentially giving a fixed list of columns that you want to retrieve. This overrides the default behavior of loading all scalar properties, which sadly also overrides the Include
statements that you added.
The simplest solution is to explicitly tell EF to retrieve the details:
var d = DataContext.Objects.Include(o => o.Details)
.Select(o => new {
Object = o,
ObjectDetails = o.Details,
OwnerName= o.Owner.Name
});
As an aside, since the Select
explicitly states which columns EF needs to retrieve, you don't need the Include
statement anymore.
This behavior can already be seen by you retrieving o.Owner.Name
without actually calling Include(o => o.Owner)
.
Upvotes: 0
Reputation: 16991
This should do it (though Details
are loaded in a separate property to correct for @Flatter's comment):
DataContext.Objects
.Include(o => o.Owner>)
.Include(o => o.Details)
.Select(o => new {Object = o,
OwnerName = o.Owner.Name,
Details = o.Details});
It returns a new object
with Object
set to the selected Object
(consider renaming this if you can, its very confusing), and an OwnerName
populated from the Owner table without loading the entire Owner. It also populates Details
as a separate property, since Select
ignores the Include
.
I say it "should" work, because without seeing your table structure, I have to guess based on your descriptions of how things are connected.
Upvotes: 0