【发布时间】:2016-04-27 19:34:57
【问题描述】:
我在查询中使用Include 包含导航属性,以便以后不会延迟加载。但是,当我使用 Select 投影创建匿名包装对象时,它不起作用。
让我展示一个简化的例子。 实体:
public class UserEntity {
public string Name {get;set;}
public virtual ICollection<UserEntity> Friends { get; set; }
}
查询:
var entry = _dbCtx
.Users
.Include(x => x.Friends)
// Select here is simplified, but it shows the wrapping
.Select(user => new {
User = user
})
.First();
// Here we have additional lazy loaded DB call
var friends = entry.User.Friends.Select(x => x.Name).ToList();
我还从生成的 SQL 中看到,导航属性不包括在内:
SELECT
[Limit1].[Name] AS [Name],
FROM ( SELECT TOP (1)
[Extent1].[Name] AS [Name]
FROM [dbo].[Users] AS [Extent1]
) AS [Limit1]
在这种情况下是否可以Include导航属性Friends,以便User在不延迟加载的情况下获取数据?
我希望这也能起作用:
var entry = _dbCtx
.Users
.Select(user => new {
User = user
})
.Include(x => x.User.Friends)
.First();
但遇到异常:
InvalidOperationException:查询的结果类型既不是 EntityType 也不是具有实体元素类型的 CollectionType。只能为具有这些结果类型之一的查询指定包含路径。
我想到了一些解决方法,但它们有点棘手:
-
在
Select中为我们的匿名对象添加附加属性:var entry = _dbCtx .Users .Select(user => new { User = user, UsersFriends = user.Friends }) .First(); // manually copy the navigation property entry.User.Friends = user.UsersFriends; // Now we don't have any addition queries var friends = entry.User.Friends.Select(x => x.Name).ToList(); -
还将 User 映射到 DB 级别的匿名对象,然后将属性映射到 C# 中的
UserEntity。var entry = _dbCtx .Users .Select(user => new { User = new { Name = user.Name, Friends = user.Friends } }) .Take(1) // Fetch the DB .ToList() .Select(x => new { User = new UserEntity { Name = x.Name, Friends = x.Friends } }) .First(); // Now we don't have any addition queries var friends = entry.User.Friends.Select(x => x.Name).ToList();
所以现在,Friends 有一个 LEFT OUTER JOIN,但两种解决方法都不是很好:
1) 附加属性和副本不是一种干净的方式。
2) 我的 UserEntity 有更多其他属性。此外,每次我们添加新属性时,我们也应该修改这里的选择器。
有没有办法实现导航属性,包括第一个示例?
感谢您的阅读,我希望有人对此有所了解。
编辑:
我将扩展实体和查询以显示一个真实的用例。
实体
public class UserEntity {
public string Name {get;set;}
public int Score {get;set;}
public virtual ICollection<UserEntity> Friends { get; set; }
}
查询
var entry = _dbCtx
.Users
.Include(x => x.Friends)
.Select(user => new {
User = user,
Position = _dbCtx.Users.Count(y => y.Score > user.Score)
})
.First();
【问题讨论】:
标签: c# entity-framework linq-to-sql entity-framework-6