ten*_*its 7 c# entity-framework linq-to-sql entity-framework-6
我在我的查询中包含导航属性Include,以便以后不会延迟加载.但是,当我使用Select投影创建一个匿名的包装器对象时,它不起作用.
让我展示一下简化的例子. 实体:
public class UserEntity {
public string Name {get;set;}
public virtual ICollection<UserEntity> Friends { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
查询:
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();
Run Code Online (Sandbox Code Playgroud)
我也从生成的SQL中看到,导航属性不包括在内:
SELECT
[Limit1].[Name] AS [Name],
FROM ( SELECT TOP (1)
[Extent1].[Name] AS [Name]
FROM [dbo].[Users] AS [Extent1]
) AS [Limit1]
Run Code Online (Sandbox Code Playgroud)
在这种情况下是否可以Include使用导航属性Friends,以便User在没有延迟加载的情况下获取数据?
我也期待这个工作:
var entry = _dbCtx
.Users
.Select(user => new {
User = user
})
.Include(x => x.User.Friends)
.First();
Run Code Online (Sandbox Code Playgroud)
但得到一个例外:
InvalidOperationException:查询的结果类型既不是EntityType,也不是具有实体元素类型的CollectionType.只能为具有这些结果类型之一的查询指定包含路径.
我遇到了一些解决方法,但它们有些棘手:
在我们的匿名对象中添加add属性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();
Run Code Online (Sandbox Code Playgroud)也将用户映射到数据库级别的匿名对象,然后将属性映射到UserEntityC#.
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();
Run Code Online (Sandbox Code Playgroud)所以现在有一个LEFT OUTER JOINfor Friends,但两种解决方法都不太好:
1)附加属性和副本不是一种干净的方式.
2)我的UserEntity还有更多其他属性.另外,每次添加新属性时,我们都应该在这里修改选择器.
有没有办法实现导航属性,包括从第一个样本?
感谢您阅读,我希望有人知道这一点.
编辑:
我将扩展实体和查询以显示真实的用例.
实体
public class UserEntity {
public string Name {get;set;}
public int Score {get;set;}
public virtual ICollection<UserEntity> Friends { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
查询
var entry = _dbCtx
.Users
.Include(x => x.Friends)
.Select(user => new {
User = user,
Position = _dbCtx.Users.Count(y => y.Score > user.Score)
})
.First();
Run Code Online (Sandbox Code Playgroud)
不是_为什么_的答案,但想要更好的代码格式......
我真的很惊讶它是这样运作的。也许 EF 检测到您没有Friends直接在投影中使用该属性,因此会忽略它。如果将对象封装在 EF 查询之外会怎样:
var entry = _dbCtx
.Users
.Include(x => x.Friends)
.Take(1); // replicate "First" inside the EF query to reduce traffic
.AsEnumerable() // shift to linq-to-objects
// Select here is simplified, but it shows the wrapping
.Select(user => new {
User = user
})
.First()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1142 次 |
| 最近记录: |