如何使用EF核心定义层次表



在我正在开发的应用程序中,我们有一个用户表TblUser。此表中的用户可能属于单个父用户。一个父用户可能有多个子用户。

这种关系在一个名为TblUserMapping的表中维护,该表有两列,ParentUserId和ChildUserId与父级和子级的TblUser.Id值相对应。TblUser.Id是一个自动递增的值。

我如何在EF Core中定义这一点,是否可以将ChildUser插入TblUser并使用自动生成的Id值来创建TblUserMapping记录?

现在我有:

[Table("TblUser")]
public class TblUser
{
public TblUser()
{        
ChildUsers            = new List<TblUserMapping>();
}
public int Id { get; set; }
public string UserName { get; set; }

public virtual ICollection<TblUserMapping> ChildUsers { get; set; }
public virtual TblUserMapping ParentUser { get; set; }
}
[Table("TblUserMapping")]
public class TblUserMapping
{
public TblUserMapping()
{
}
public int ChildUserId { get; set; }
public int ParentUserId { get; set; }

public virtual TblUser ChildUser { get; set; }
public virtual TblUser ParentUser { get; set; }
}
public class TblUserMapping : IEntityTypeConfiguration<TblUser>
{
public void Configure(EntityTypeBuilder<TblUser> entity)
{
entity.Property(e => e.Id).ValueGeneratedOnAdd();
entity.Property(e => e.UserName)
.IsRequired()
.IsUnicode(false);
}
}
public class TblUserMappingMapping : IEntityTypeConfiguration<Entities.TblUserMapping>
{
public void Configure(EntityTypeBuilder<Entities.TblUserMapping> entity)
{
entity.HasKey(e => e.ChildUserId);
entity.Property(e => e.ChildUserId)
.IsRequired();
entity.Property(e => e.ParentUserId)
.IsRequired();


entity.HasOne(e => e.ParentUser)
.WithMany(e => e.ChildUsers)
.HasForeignKey(e => e.ParentUserId);
entity.HasOne(e => e.ChildUser)
.WithOne(e => e.ParentUser)
.HasForeignKey<TblUser>(e => e.Id);
}
}

但这并没有像我希望的那样奏效:

var userInformation = await _context
.Users
.Include(entity => entity.ChildUsers)
.ThenInclude(entity => entity.ChildUser)
.Where(s => s.UserName == userName)
.FirstOrDefaultAsync();
var ChildUser = new TblUser
{
UserName = userModel.UserName,
ParentUser = new TblUserMapping()
{
ParentUser = userInfo
}
};
_context.Users.Add(ChildUser);
await _context.SaveChangesAsync();

您可以附加导航属性,实体框架在创建id时会自动填充这些属性。你给的例子应该有效,你可能需要向我们展示你是如何获得userInfo的,然后我们才能看到发生了什么。

话虽如此,我不会保留一个单独的映射表,而是让每个子用户直接引用他们的父用户:

[Table("TblUser")]
public class TblUser
{
public int Id { get; set; }
public string UserName { get; set; }
public int? ParentId { get; set; }
public TblUser Parent { get; set; }    
// Lazy-loading is not enabled by default in EF Core, so you don't need the 'virtual' keyword
// Also, if the initialization of a member does not depend on constructor arguments, I
// prefer this syntax instead of doing it in the constructor
public ICollection<TblUser> Children { get; set; } = new List<TblUser>();
}

您可以在模型中使用InverseProperty属性:

[Table("TblUser")]
public class TblUser
{
public TblUser()
{        
ChildUsers            = new List<TblUserMapping>();
}
public int Id { get; set; }
public string UserName { get; set; }
[InverseProperty("ChildUser")]
public virtual ICollection<TblUserMapping> ChildUsers { get; set; }
[InverseProperty("ParentUser")]
public virtual TblUserMapping ParentUser { get; set; }
}

在其他型号中:

[Table("TblUserMapping")]
public class TblUserMapping
{
public TblUserMapping()
{
}
public int ChildUserId { get; set; }
public int ParentUserId { get; set; }
[ForeignKey("ChildUserId")]
public virtual TblUser ChildUser { get; set; }
[ForeignKey("ParentUserId")]
public virtual TblUser ParentUser { get; set; }
}

正如您所看到的,我用属性定义了这些关系,这意味着不需要出现在您的配置中。

最新更新