具有自身 parentId 的实体框架核心嵌套对象
Posted
技术标签:
【中文标题】具有自身 parentId 的实体框架核心嵌套对象【英文标题】:entity framework core nested object with self parentId 【发布时间】:2022-01-08 20:11:43 【问题描述】:我有一个树表结构,这些数据来自前端。 在这个树形表结构中,有 IssueActivity 和 IssueActivityDetail 来了解这个问题的细节。 现在我的问题是,这个 IssueActivity 字段可以添加多个 IssueActivityDetail 字段。如何在 c# ef 核心方面做到这一点? 我试图用 ParentId 的逻辑来做。我的实体结构如下。 FluenApi中没有添加parentId,因为我没有完全理解。
我的 IssueActivity 表。
public partial class IssueActivitiy
public int Id get; set;
public int IssueId get; set;
public byte Type get; set;
public short SubActivityNo get; set;
public string SubActivityTitle get; set;
public virtual Issue Issue get; set;
public virtual List<IssueActivitiyDetail> IssueActivitiyDetails get; set;
我的 IssueActivityDetail 表。
public partial class IssueActivitiyDetail
public int Id get; set;
public int IssueActivityId get; set;
public short LineNo get; set;
public string Definition get; set;
public byte RoleId get; set;
public byte Medium get; set;
public string Explanation get; set;
public int? ParentId get; set;
public virtual IssueActivitiy IssueActivity get; set;
FluentApi 配置。
public void Configure(EntityTypeBuilder<IssueActivitiy> modelBuilder)
modelBuilder.ToTable("IssueActivitiy");
modelBuilder.HasKey(a => a.Id);
modelBuilder.Property(e => e.SubActivityNo).HasComment("Sıra No");
modelBuilder.Property(e => e.SubActivityTitle).HasMaxLength(256).IsUnicode(false);
modelBuilder.Property(e => e.Type).HasDefaultValueSql("((1))").HasComment("1) Temel Aktivite\r\n2) Alternatif Aktivite\r\n3) İşlem İptal Aktivite");
modelBuilder.HasOne(d => d.Issue).WithMany(p => p.IssueActivitiys).HasForeignKey(d => d.IssueId).OnDelete(DeleteBehavior.ClientSetNull).HasConstraintName("FK_Issue_IssueActivitiy_Id");
public void Configure(EntityTypeBuilder<IssueActivitiyDetail> modelBuilder)
modelBuilder.ToTable("IssueActivitiyDetail");
modelBuilder.Property(e => e.Definition).IsRequired().HasMaxLength(2048).IsUnicode(false).HasComment("Açıklama");
modelBuilder.Property(e => e.Explanation).HasMaxLength(2048).IsUnicode(false).HasComment("Açıklama");
modelBuilder.Property(e => e.IssueActivityId).HasComment("Konu Id");
modelBuilder.Property(e => e.LineNo).HasComment("Sıra No");
modelBuilder.Property(e => e.Medium).HasComment("Ortam (Excel, Mail vb.)");
modelBuilder.Property(e => e.RoleId).HasComment("Rol");
modelBuilder.Property(e => e.ParentId);
modelBuilder.HasOne(d => d.IssueActivity).WithMany(p => p.IssueActivitiyDetails).HasForeignKey(d => d.IssueActivityId).OnDelete(DeleteBehavior.ClientSetNull).HasConstraintName("FK_IssueActivitiy_IssueActivitiyDetail_");
Web Api也是我尝试接收和处理数据的地方,但是玩了很多,都做不好。
var vIssueActivity = issueInfo.IssueActivitiyInfos
.Select(a => new IssueActivitiy
Type = a.Type,
SubActivityNo = a.SubActivityNo,
SubActivityTitle = a.SubActivityTitle,
IssueActivitiyDetails = a.IssueActivitiyDetailInfos
.Select(x => new IssueActivitiyDetail
LineNo = x.LineNo,
Definition = x.Definition,
RoleId = vUser.RoleId,
Medium = x.Medium,
Explanation = x.Explanation,
IssueActivityDetail = new List<IssueActivitiyDetail>
).ToList()
);
【问题讨论】:
【参考方案1】:您无需将ParentId
属性保留在IssueActivityDetail
中。
public partial class IssueActivitiy
...
public virtual List<IssueActivitiyDetail> IssueActivitiyDetails get; set;
public partial class IssueActivitiyDetail
...
public virtual IssueActivitiy IssueActivity get; set;
您的配置看起来没有错。
也许你可以在从数据库上下文中获取实体时使用Include
。
var issueActivity = context.IssueActivities.Include(x => x.IssueActivityDetails).FirstOrDefault();
【讨论】:
【参考方案2】:您可以通过从数据库中检索所有条目来完成此操作。然后选择 Root 节点,然后让 EF Core 映射完成剩下的工作。
public class TreeNode
public bool IsRoot get; set;
public int? ParentNodeId get; set;
public virtual List<TreeNode> ChildNodes get; set;
public class TreeNodeRepository
public async Task<TreeNode> GetTreeStructure()
var allNodes = await _context.TreeNodes.ToListAsync();
return allNodes.FirstOrDefault(t => t.IsRoot);
您可以争辩说ParentId == null
也暗示它是一个父节点。这只是让 imo 给出的示例更加直观。
您应该考虑性能,有多少节点会成为一个问题,它是否通过 web-api 公开并且迭代节点会更有效。因此,您不必每次都将整个 Tree 加载到内存中,而是让客户端来处理。
【讨论】:
以上是关于具有自身 parentId 的实体框架核心嵌套对象的主要内容,如果未能解决你的问题,请参考以下文章