【问题标题】:Many to one relationship, unwanted JOIN多对一关系,不需要的 JOIN
【发布时间】:2015-02-28 18:54:45
【问题描述】:

我的模型中定义了多对一关系: 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")

因为它会给我序列包含多个元素异常。

你知道如何避免额外的加入吗?

我怀疑它与模型生成器声明有关。我一直在谷歌上搜索,但从未找到任何解决方案。

任何关于模型构建器和定义与它的关系的材料也将不胜感激。

【问题讨论】:

    标签: asp.net asp.net-mvc entity-framework entity-framework-6


    【解决方案1】:

    映射...

    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 映射会阻止这种情况。

    【讨论】:

    • 谢谢,它看起来工作正常。我假设,“WithMany”指的是用户创建的许多项目,对吧?能推荐一些关于modelBuilder的资料吗?
    • 是的。如果ApplicationUser 有一个属性Projects 它应该是WithMany(u =&gt; u.Projects)
    【解决方案2】:

    使用

    .FirstOrDefault()
    

    而不是单一的。

    如果找不到对象,此方法将返回第一个对象或 null。如果选择了多个元素,单个方法将引发异常。

    你也可以使用

    .First()
    

    但是如果没有找到元素,这个方法会抛出异常。

    PS 我不确定这是否是一个错字,但你必须使用双等号,就像这样:

    context.Users.Single(u => u.Username == "test")
    

    请记住,在这些情况下,通常会创建 LoweredUsername 列并用于比较:

    context.Users.Single(u => u.LoweredUsername == providedUsername.ToLower())
    

    原因:

    • 有人可以输入 John 而不是 john
    • 在这种情况下,SQL 服务器端的索引可以正常工作

    【讨论】:

    • 不幸的是,这并不能解决主要问题 - 不需要的连接。当我想检索 ApplicationUser 实体时,我认为没有理由加入所有相关实体,但感谢您指出 LoweredUsername。
    【解决方案3】:

    我想你有 ApplicationUser

    public virtual ICollection<Project> Projects { get; set; }
    

    请参阅 MSDN 中的turn off lazy loading for all entities

    turning off lazy loading for specific navigation properties 将 Projects 属性设为非虚拟

    【讨论】:

      猜你喜欢
      • 2011-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多