如何解决EF Core子实体未与父实体一起加载
数据库
我正在使用带有两个表的SQL Server数据库:INVOICE_HEADER
和INVOICE_ROW
。
INVOICE_HEADER
有两个字段:
-
INTERNAL_ID
,键入int
和主键, -
INV_NUM
,键入varchar(13)
,这对于每个业务逻辑而言都是唯一的,但对于每个数据库结构而言都是唯一的。
INVOICE_ROW
具有三个:
-
INTERNAL_ID
,键入int
和主键, -
INV_NUM
,键入varchar(13)
, -
INV_ROW_NUM
,键入int
,每个业务逻辑也要唯一。
来自INVOICE_ROW
的行与INV_NUM
的行具有相同的INVOICE_HEADER
值,因此在业务逻辑方面构成相同的发票,因此INVOICE_HEADER.INV_NUM
和({{1 }},INVOICE_ROW.INV_Num
)就我们的查询而言实际上是主键。
在INVOICE_ROW.INV_ROW_NUM
中找到的值与在INVOICE_HEADER.INTERNAL_ID
中找到的值不同,并且两个表中的任何字段似乎都不具有与另一个表中INVOICE_ROW.INTERNAL_ID
对应的值。
因此,没有实际的外键将任何一个表链接到另一个表。
我是否需要提及数据库来自第三方,其结构是固定的,具有更多表以及INTERNAL_ID
和INVOICE_HEADER
都具有更多字段?好吧,无论如何我还是这么做的。
实际上,INVOICE_ROW
甚至几乎没有出现在描述数据库结构的文档中(逐字段,仅针对其他一些表)。
使用Entity Framework Core访问数据库
由于上述原因,我无法使用数据库中定义的主键。
所以我创建了两个类:
INTERNAL_ID
和上下文:
public class InvoiceHeader
{
public int InternalId { get; set; }
public string InvoiceNum { get; set; }
public virtual List<InvoiceRow> InvoiceRows { get; set; }
}
public class InvoiceRow
{
public int InternalId { get; set; }
public string InvoiceNum { get; set; }
public int? RowNum { get; set; }
public virtual InvoiceHeader InvHeader { get; set; }
}
我觉得用 public DbSet<InvoiceHeader> RepoInvHeader { get; set; }
public DbSet<InvoiceRow> RepoInvRow { get; set; }
protected override void OnModelCreating(ModelBuilder p_mbuModel)
{
base.OnModelCreating(p_mbuModel);
// Table name
p_mbuModel.Entity<InvoiceHeader>().ToTable("INVOICE_HEADER");
// Primary key
p_mbuModel.Entity<InvoiceHeader>().HasKey(t => new { t.InternalId }).
HasName("PK_INTERNAL_ID_INVOICE_HEADER");
// Fields
p_mbuModel.Entity<InvoiceHeader>().Property(t => t.InternalId).IsRequired();
p_mbuModel.Entity<InvoiceHeader>().Property(t => t.InternalId).HasColumnType("int");
p_mbuModel.Entity<InvoiceHeader>().Property(t => t.InvoiceNum).HasColumnName("INV_NUM");
p_mbuModel.Entity<InvoiceHeader>().Property(t => t.InvoiceNum).HasColumnType("varchar(13)");
p_mbuModel.Entity<InvoiceHeader>().Property(t => t.InvoiceNum).HasMaxLength(13);
// Foreign keys
p_mbuModel.Entity<InvoiceHeader>().HasMany(h => h.InvoiceRows).
WithOne(r => r.InvHeader).
HasPrincipalKey(h => h.InvoiceNum).
HasForeignKey(r => r.InvoiceNum);
// Table name
p_mbuModel.Entity<InvoiceRow>().ToTable("INVOICE_ROW");
// Primary key
p_mbuModel.Entity<InvoiceRow>().HasKey(t => new { t.InternalId }).
HasName("PK_INTERNAL_ID_INVOICE_ROW");
// Fields
p_mbuModel.Entity<InvoiceRow>().Property(t => t.InternalId).IsRequired();
p_mbuModel.Entity<InvoiceRow>().Property(t => t.InternalId).HasColumnType("int");
p_mbuModel.Entity<InvoiceRow>().Property(t => t.InvoiceNum).HasColumnName("INV_NUM");
p_mbuModel.Entity<InvoiceRow>().Property(t => t.InvoiceNum).HasColumnType("varchar(13)");
p_mbuModel.Entity<InvoiceRow>().Property(t => t.RowNum).HasColumnName("INV_ROW_NUM");
p_mbuModel.Entity<InvoiceRow>().Property(t => t.RowNum).HasColumnType("int");
// Foreign keys
p_mbuModel.Entity<InvoiceRow>().HasOne(r => r.InvHeader).
WithMany(h => h.InvoiceRows).
HasForeignKey(r => r.InvoiceNum).
HasPrincipalKey(h => h.InvoiceNum);
}
,HasMany
进行的所有提及都是有必要的,以弥补缺乏真正的,可用的主键。
结果
我尝试了以下操作:
WithOne
在调试时, InvoiceHeader z_objHeader = z_dbcContexteSage.repoInvHeader.Include(h => h.InvoiceRows).FirstOrDefault(h => h.Piece == "XXXX");
的值应为z_objHeader
中字段的期望值,但其INVOICE_HEADER
属性为InvoiceRows
。 (我也尝试过null
:它抛出了foreach (InvoiceRow z_objRow in z_objHeader.InvoiceRows)
。)
现在,如果我添加并运行它,
NullReferenceException
查看 InvoiceRow z_objRow = z_dbcContexteSage.repoInvRow.FirstOrDefault(r => r.Piece == "XXXX");
表示它现在包含一个 z_objHeader.InvoiceRows
。
跑步后甚至更好
InvoiceRow
List<InvoiceRow> z_lisRows = z_dbcContexteSage.repoInvRow.Where(r => r.Piece == "XXXX").ToList();
现在具有所有我期望的行。
所以我可以使用它,但是我仍然觉得那些从z_objHeader.InvoiceRows
显式加载的命令不是必需的,甚至是有用的。
我在网络上看了很多遍,似乎找不到我忽略或遗忘的地方。
我想抓住的可能是那些官方但无法使用的主键/事实上的主键东西。
有什么想法吗?
解决方法
这不是我忘记输入的东西,而是我(或其他人)在某些时候输入的东西。
有一个
using System.Data.Entity;
在测试类中,显然弄乱了Update()
方法。现在它已经不存在了,属性InvoiceRows
已正确加载。
感谢所有花时间阅读问题的人!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。