我正在使用.net core 2 mvc,我尝试在Users
和Steps
之间建立多对多关系。
关系是这样的,但当我查询记录时,我得到了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?
答案 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执行查询时,无论是多对多,一对多还是一对一关系,查询几乎总是可以使用集合而不是连接来创建。它们看起来更简单,它们更容易理解,因此更好地维护。