多对一关系,不需要的 JOIN
Many to one relationship, unwanted JOIN
我的模型中定义了多对一关系:
Project.CreatedBy = ApplicationUser.Id:
class Project{
[Required]
public ApplicationUser CreatedBy {get; set;}
}
有映射:
modelBuilder.Entity<Project>().HasOptional(i => i.CreatedBy).WithOptionalDependent().WillCascadeOnDelete(false);
不幸的是,当我尝试通过以下方式从 DbContext 检索所有用户时:
var users = context.Users;
生成的 SQL 看起来像:
SELECT
[...]
FROM [dbo].[AspNetUsers] AS [Extent1]
LEFT OUTER JOIN [dbo].[Projects] AS [Extent4] ON ([Extent4].[CreatedBy_Id] IS NOT NULL) AND ([Extent1].[Id] = [Extent4].[CreatedBy_Id])
所以当某个用户创建了10个项目时,用户实体乘以10倍。这让我无法通过他的用户名查找该用户:
context.Users.Single(u => u.Username == "test")
因为它会给我 Sequence contains more than one element 异常。
你知道如何避免额外的连接吗?
我怀疑它与 modelBuilder 声明有关。我一直在谷歌搜索这个,但从未找到任何解决方案。
任何关于 modelBuilder 和定义与它的关系的材料也将不胜感激。
使用
.FirstOrDefault()
而不是单一。
此方法将 return 第一个对象,如果未找到对象,则返回 null。如果选择了多个元素,单一方法将抛出异常。
您也可以使用
.First()
但是如果没有找到元素,这个方法会抛出异常。
PS 不知道是不是打错了,不过你得用双等号,像这样:
context.Users.Single(u => u.Username == "test")
请记住,通常在这些情况下会创建 LoweredUsername 列并用于比较:
context.Users.Single(u => u.LoweredUsername == providedUsername.ToLower())
这样做的原因:
- 有人可以输入 John 而不是 john
- 在 SQL 服务器端建立索引在这种情况下有效
我想在 ApplicationUser 中你有
public virtual ICollection<Project> Projects { get; set; }
请参阅 MSDNturn off lazy loading for all entities
或者 turning off lazy loading for specific navigation properties 使项目 属性 非虚拟
映射...
modelBuilder.Entity<Project>()
.HasOptional(i => i.CreatedBy)
.WithOptionalDependent()
...将其表示为 1:1 关联,而不是您想要的 1:n 关联。
所以把映射改成一对多:
modelBuilder.Entity<Project>()
.HasOptional(p => p.CreatedBy)
.WithMany()
.HasForeignKey(p => p.CreatedBy_Id);
我不确定为什么当您查询 User
时 EF 加入 Project
,因为关联是可选的),但是适当的 1:n 映射会阻止它。
我的模型中定义了多对一关系: Project.CreatedBy = ApplicationUser.Id:
class Project{
[Required]
public ApplicationUser CreatedBy {get; set;}
}
有映射:
modelBuilder.Entity<Project>().HasOptional(i => i.CreatedBy).WithOptionalDependent().WillCascadeOnDelete(false);
不幸的是,当我尝试通过以下方式从 DbContext 检索所有用户时:
var users = context.Users;
生成的 SQL 看起来像:
SELECT
[...]
FROM [dbo].[AspNetUsers] AS [Extent1]
LEFT OUTER JOIN [dbo].[Projects] AS [Extent4] ON ([Extent4].[CreatedBy_Id] IS NOT NULL) AND ([Extent1].[Id] = [Extent4].[CreatedBy_Id])
所以当某个用户创建了10个项目时,用户实体乘以10倍。这让我无法通过他的用户名查找该用户:
context.Users.Single(u => u.Username == "test")
因为它会给我 Sequence contains more than one element 异常。
你知道如何避免额外的连接吗?
我怀疑它与 modelBuilder 声明有关。我一直在谷歌搜索这个,但从未找到任何解决方案。
任何关于 modelBuilder 和定义与它的关系的材料也将不胜感激。
使用
.FirstOrDefault()
而不是单一。
此方法将 return 第一个对象,如果未找到对象,则返回 null。如果选择了多个元素,单一方法将抛出异常。
您也可以使用
.First()
但是如果没有找到元素,这个方法会抛出异常。
PS 不知道是不是打错了,不过你得用双等号,像这样:
context.Users.Single(u => u.Username == "test")
请记住,通常在这些情况下会创建 LoweredUsername 列并用于比较:
context.Users.Single(u => u.LoweredUsername == providedUsername.ToLower())
这样做的原因:
- 有人可以输入 John 而不是 john
- 在 SQL 服务器端建立索引在这种情况下有效
我想在 ApplicationUser 中你有
public virtual ICollection<Project> Projects { get; set; }
请参阅 MSDNturn off lazy loading for all entities
或者 turning off lazy loading for specific navigation properties 使项目 属性 非虚拟
映射...
modelBuilder.Entity<Project>()
.HasOptional(i => i.CreatedBy)
.WithOptionalDependent()
...将其表示为 1:1 关联,而不是您想要的 1:n 关联。
所以把映射改成一对多:
modelBuilder.Entity<Project>()
.HasOptional(p => p.CreatedBy)
.WithMany()
.HasForeignKey(p => p.CreatedBy_Id);
我不确定为什么当您查询 User
时 EF 加入 Project
,因为关联是可选的),但是适当的 1:n 映射会阻止它。