多对一的关系,不受欢迎的JOIN

时间:2015-02-28 18:54:45

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

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

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

您是否知道如何避免额外加入?

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

关于modelBuilder的任何材料以及与它的定义关系都会非常感激。

3 个答案:

答案 0 :(得分:0)

使用

.FirstOrDefault()

而非单身。

此方法将返回第一个对象,如果未找到对象,则返回null。如果选择了多个元素,则单个方法抛出异常。

您也可以使用

.First()

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

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

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

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

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

原因:

  • 有人可以输入John代替john
  • 在这种情况下SQL服务器端的索引工作

答案 1 :(得分:0)

我想在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属性非虚拟

答案 2 :(得分:0)

映射......

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);

我不确定为什么EF在查询Project时加入User,因为关联是可选的),但是正确的1:n映射会阻止它。