【问题标题】:How to define a hierarchal table using EF core如何使用 EF 核心定义层次表
【发布时间】:2021-03-13 17:47:29
【问题描述】:

在我正在开发的应用程序中,我们有一个用户表 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();

【问题讨论】:

  • 您需要TblUserMapping 来获取任何具体信息吗?为什么不在TblUser 中有一个属性Parent
  • 我可能不需要它,这听起来像是一个更好的解决方案,正如 Andrew 也提到的那样,如果不需要的话。

标签: c# entity-framework-core fluent


【解决方案1】:

您可以附加导航属性,Entity Framework 将在创建它们时自动填充 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>();
}

【讨论】:

    【解决方案2】:

    您可以在模型中使用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; }
     }
    

    如您所见,我使用属性定义了这些关系,这意味着您无需进入配置。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-20
      • 2020-09-15
      • 1970-01-01
      • 2022-06-29
      • 1970-01-01
      相关资源
      最近更新 更多