EF用户实例中的多对多关系为NULL

时间:2018-01-09 12:50:17

标签: c# .net entity-framework model-view-controller core

我正在使用.net core 2 mvc,我尝试在UsersSteps之间建立多对多关系。 关系是这样的,但当我查询记录时,我得到了user = null

Hier是我的代码:

(applicationUser model):

 public class ApplicationUser : IdentityUser
{
    public string Name { get; set; }
    public List<StepsUsers> StepUser { get; set; }
}

(步骤模型):

public class Steps
{
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
    public List<StepsUsers> StepUser { get; set; }

}

StepsUsers模型:

public class StepsUsers : IAuditable
{
    public int StepId { get; set; }
    public Steps Step { get; set; }

    public string UserId { get; set; }
    public ApplicationUser User { get; set; }
}

在DbContext中我这样做了:

protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);           
        builder.Entity<StepsUsers>()
        .HasKey(s => new { s.StepId, s.UserId });

        builder.Entity<StepsUsers>()
        .HasOne(su => su.Step)
        .WithMany(s => s.StepUser)
        .HasForeignKey(su => su.StepId);

        builder.Entity<StepsUsers>()
        .HasOne(su => su.User)
        .WithMany(s => s.StepUser)
        .HasForeignKey(su => su.UserId);
    }
public DbSet<MyApp.Models.StepsUsers> StepsUsers { get; set; }

现在,当我查询具有特定StepsUsers的{​​{1}}实例时,除StepId字段为User

外,我的所有字段都正确无误
null

我为另外两张表做了相同的代码并且工作正常,我不知道为什么会这样,有什么建议1?

1 个答案:

答案 0 :(得分:1)

您的问题的原因是您忘记将您的To-many关系声明为虚拟。另一个改进是将它们声明为虚拟 ICollection 而不是List。毕竟,ApplicationUser.StepUser [4]意味着什么?

如果根据the entity framework conventions for many-to-many,配置多对多关系,则无需提及联结表(StepsUsers)。实体框架将识别多对多,并将为您创建联结表。如果你坚持code first conventions,你甚至不需要流畅的API来配置多对多。

在您的设计中,每个ApplicationUser都有零个或多个Steps,而每个Step都由零个或多个ApplicationUsers完成。

class ApplicationUser
{
    public int Id {get; set;}

    // every ApplicationUser has zero or more Steps:
    public virtual ICollection<Step> Steps {get; set;}

    public string Name {get; set;}
    ...
}

class Step
{
    public int Id {get; set;}

    // every Step is performed by zero or more ApplicationUsers:
    public virtual ICollection<ApplicationUser> ApplicationUsers {get; set;}

    public string Name {get; set;}
    ...
}

public MyDbContext : DbContext
{
    public DbSet<ApplicationUser ApplictionUsers {get; set;}
    public DbSet<Step> Steps {get; set;}
}

这是所有实体框架需要知道的,以识别您配置了多对多关系。实体框架将为您创建联结表,并为联结表创建外键。您不需要声明联结表。

但是,如果我没有联结表,我怎么想加入?

答案是:不要加入。请改用集合。

如果你想要所有的ApplicationUsers ......以及他们所有的步骤......你通常会在联结表中进行内部联接,并做一些分组来获取应用程序用户。曾经试过method syntax to join three tables?它们看起来很丑陋,难以理解,容易出错,难以维护。

在实体框架中使用集合,您的查询会更简单:

var result = myDbContext.ApplicationUsers
    .Where(applicationUser => applicationUser.Name == ...)
    .Select(applicationUser => new
    {
         // select only the properties you plan to use:
         Name = applicationUser.Name,
         Steps = applicationUser.Steps
             .Where(step => step.Name == ...)
             .Select(step => new
             {
                 // again fetch only Step properties you  plan to use
                 Name = step.Name,
                 ...
             })
             .ToList(),
     });

实体框架将识别需要与联结表联接并为您执行。

如果你想要步骤......和他们的ApplicationUsers一起......你会做类似的事情:

var result = myDbContext.Steps
   .Where(step => ...)
   .Select(step => new
    {
        Name = step.Name,
        ... // other properties
        ApplicationUsers = step.ApplicationUsers
            .Where(applicationUser => ...)
            .Select(applicationUser => new
            {
               ...
            })
            .ToList(),
    });

根据我的经验,每当我想到使用实体框架使用DbSets执行查询时,无论是多对多,一对多还是一对一关系,查询几乎总是可以使用集合而不是连接来创建。它们看起来更简单,它们更容易理解,因此更好地维护。