繁体   English   中英

EF Core 子实体不与父实体一起加载

[英]The EF Core child entity isn't loaded along with the parent

数据库

我正在处理带有两个表的 SQL Server 数据库: INVOICE_HEADERINVOICE_ROW INVOICE_HEADER有两个字段:

  • INTERNAL_ID ,输入int和主键,
  • INV_NUM ,类型varchar(13) ,它对每个业务逻辑是唯一的,但不是每个数据库结构。

INVOICE_ROW有三个:

  • INTERNAL_ID ,输入int和主键,
  • INV_NUM ,输入varchar(13)
  • INV_ROW_NUM ,类型int ,每个业务逻辑也是唯一的。

INVOICE_ROWINV_NUM值与INVOICE_HEADER的一行具有相同值的INV_NUM业务逻辑术语中构成相同的发票,因此INVOICE_HEADER.INV_NUM和( INVOICE_ROW.INV_NumINVOICE_ROW.INV_ROW_NUM )就我们的查询而言充当事实上的主键担心的。

在找到的值INVOICE_HEADER.INTERNAL_ID是从那些在发现的不同INVOICE_ROW.INTERNAL_ID ,并在两个表中没有字段似乎有对应于该值INTERNAL_ID在其他。

所以没有实际的外键将任一表链接到另一个表。

我需要提到数据库来自第三方,它的结构是固定的,它有更多的表,并且INVOICE_HEADERINVOICE_ROW都有更多的字段? 无论如何,我刚刚做到了。

实际上, INTERNAL_ID甚至几乎没有出现在描述数据库结构的文档中,逐个字段,并且仅用于其他一些表。

使用 Entity Framework Core 访问数据库

由于上述原因,我无法使用数据库中定义的主键。

所以我创建了两个类:

    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);
        }

我觉得所有提到的HasManyWithOne都是必要的,以弥补缺乏真正可用的主键。

结果

我尝试了以下方法:

            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现在拥有我希望它拥有的所有行。

所以我可以使用它,但我仍然觉得那些从INVOICE_ROW显式加载的命令是不需要的,甚至不需要。

我在网络上四处张望,似乎无法找出我忽略或遗漏的内容。

我想问题可能在于官方但无法使用的主键/事实上的主键。

有任何想法吗?

这不是我忘记放入的东西,而是我(或其他人)在某个时候放入的东西。

有一个

using System.Data.Entity;

在测试类中,这显然弄乱了Update()方法。 现在它消失了,属性InvoiceRows已正确加载。

感谢所有花时间阅读问题的人!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM