【问题标题】:How do I properly define the relationship between these classes created by EF Core?如何正确定义 EF Core 创建的这些类之间的关系?
【发布时间】:2020-01-22 12:06:15
【问题描述】:

首先很抱歉,这是一个菜鸟问题。

我正在尝试编写一个连接到现有数据库并根据用户输入更改某些值的 c# 程序。 (我知道这听起来可能是个坏主意,但我们有自己的理由……)我决定使用 ef core 连接到数据库。

我使用Scaffold-DbContext 将数据库结构放入我的程序中。 构建成功,但是每当我尝试运行我的程序时,我都会收到以下错误消息:

System.InvalidOperationException: '无法确定 'Dad.DadCmu' 和 'DadCmu.IddadNavigation' 之间的一对一关系的子/依赖方。要识别关系的子/依赖方,请配置外键属性。如果这些导航不应该是同一关系的一部分,请在不指定相反的情况下配置它们。有关详细信息,请参阅http://go.microsoft.com/fwlink/?LinkId=724062。'

所以我猜这种关系没有很好地定义。那么让我们看看这些类:

    public partial class DadCmu
    {
        public int Iddad { get; set; }
        public byte UnitNo { get; set; }

        public virtual Dad IddadNavigation { get; set; }
    }

所以 IddadNavigation 是 Dad 类型:

public partial class Dad
    {
        public Dad()
        {
            DadCh = new HashSet<DadCh>();
            DadConnection = new HashSet<DadConnection>();
        }

        public int Iddad { get; set; }
        public string Name { get; set; }
        public int? DadType { get; set; }
        public short? Active { get; set; }
        public DateTime? LastUpdate { get; set; }
        public byte? SynchronizationStatus { get; set; }

        public virtual DadCmu DadCmu { get; set; }
        public virtual DadMasCon DadMasCon { get; set; }
        public virtual DadOpc DadOpc { get; set; }
        public virtual ICollection<DadCh> DadCh { get; set; }
        public virtual ICollection<DadConnection> DadConnection { get; set; }
    }

并且它们的关系应该在OnModelCreating内定义:

protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
        …
        modelBuilder.Entity<DadCmu>(entity =>
            {
                entity.HasKey(e => e.Iddad);

                entity.ToTable("DadCMU");

                entity.Property(e => e.Iddad)
                    .HasColumnName("IDDad")
                    .ValueGeneratedNever();

                entity.HasOne(d => d.IddadNavigation)
                    .WithOne(p => p.DadCmu)
                    .HasForeignKey<DadCmu>(d => d.Iddad)
                    .HasConstraintName("FK_DadCMU_Dad");
            });
        …
        modelBuilder.Entity<Dad>(entity =>
            {
                entity.HasKey(e => e.Iddad);

                entity.Property(e => e.Iddad).HasColumnName("IDDad");

                entity.Property(e => e.LastUpdate).HasColumnType("datetime");
            });
        …
        }

所以在modelBuilder.Entity&lt;DadCmu&gt; 中,它确实明确提到了一个外键,所以我不太确定问题出在哪里? 我必须在modelBuilder.Entity&lt;Dad&gt; 内做同样的事情吗?

该代码会是什么样子?

还是我完全误解了这个问题?

这是可以自动完成的事情吗?带有scaffold-dbcontext 的参数? (我的数据库有 180 个表,其中许多表出现相同的错误。)

在不改变数据库本身结构的情况下,这一切都可能吗?

非常感谢您提前!同样,这是我第一次使用数据库,如果这真的很明显,我深表歉意。

编辑: cmets中出现的DadOpc类:

    public partial class DadOpc
    {
        public int Iddad { get; set; }
        public string Computer { get; set; }
        public string OpcserviceName { get; set; }
        public float? ScanInterval { get; set; }
        public byte? ServerType { get; set; }
        public byte? UseSecurity { get; set; }

        public virtual Dad IddadNavigation { get; set; }
    }

编辑 2:(关于 jcruz 的解决方案)

错误信息:

System.InvalidOperationException: '无法确定 'DadMasCon.IddadNavigation' 和 'Dad.DadMasCon' 之间的一对一关系的子/依赖方。要识别关系的子/依赖方,请配置外键属性。如果这些导航不应该是同一关系的一部分,请在不指定相反的情况下配置它们。有关详细信息,请参阅http://go.microsoft.com/fwlink/?LinkId=724062。'

班爸爸:

public partial class Dad
    {
        public Dad()
        {
            DadCh = new HashSet<DadCh>();
            DadConnection = new HashSet<DadConnection>();
        }

        //user added Id-Fields:
        public int DadCmuId { get; set; }
        public int DadOpcId { get; set; }
        public int DadMasConId { get; set; }


        public int Iddad { get; set; }
        public string Name { get; set; }
        public int? DadType { get; set; }
        public short? Active { get; set; }
        public DateTime? LastUpdate { get; set; }
        public byte? SynchronizationStatus { get; set; }

        public virtual DadCmu DadCmu { get; set; }
        public virtual DadMasCon DadMasCon { get; set; }
        public virtual DadOpc DadOpc { get; set; }
        public virtual ICollection<DadCh> DadCh { get; set; }
        public virtual ICollection<DadConnection> DadConnection { get; set; }
    }

DadMasCon 班:

        public DadMasCon()
        {
            DadModbusRegConfig = new HashSet<DadModbusRegConfig>();
        }

        public int Iddad { get; set; }
        public int UnitNo { get; set; }
        public byte? Model { get; set; }
        public DateTime? RefTimeOffset { get; set; }
        public float? TimeoutComm { get; set; }
        public int? Port { get; set; }
        public float? ConnectionInterval { get; set; }
        public byte? ExternalComm { get; set; }
        public string Mvbparameters { get; set; }
        public byte? ModbusBps { get; set; }
        public byte? ModbusParity { get; set; }
        public byte? ModbusStopBits { get; set; }
        public byte? ModbusMode { get; set; }
        public byte? ModbusSlaveAddress { get; set; }
        public byte? CardType0 { get; set; }
        public byte? CardType1 { get; set; }
        public byte? CardType2 { get; set; }
        public byte? CardType3 { get; set; }
        public string LastIp { get; set; }
        public string HiddenParameter { get; set; }
        public int? SerialNo { get; set; }
        public int? LastSequence { get; set; }
        public int? TcppackageErrors { get; set; }
        public byte? UsePrivateFirmware { get; set; }
        public byte? ConfigurationLock { get; set; }
        public byte? IecclientOn { get; set; }
        public string IecclientAddress { get; set; }
        public string IecclientDomain { get; set; }
        public byte? IecsrvOn { get; set; }
        public byte? IecsrvNrOfClents { get; set; }
        public string IecsrvAuthentication { get; set; }
        public string Iecmmsparam { get; set; }
        public float? IecclientPollInterval { get; set; }
        public byte? NtpserverType { get; set; }
        public string Ntpipaddress { get; set; }
        public string IecmmsparamFileName { get; set; }
        public string ModbusTcpaddress { get; set; }
        public int? ModbusTcpportNr { get; set; }
        public byte? ModbusByteOrder { get; set; }
        public byte? ModbusClientValueType { get; set; }
        public string Macaddress { get; set; }
        public byte? MonitorInitiate { get; set; }

        public virtual Dad IddadNavigation { get; set; }
        public virtual ICollection<DadModbusRegConfig> DadModbusRegConfig { get; set; }
    }

OnModelCreating:

modelBuilder.Entity<DadMasCon>(entity =>
            {
                entity.HasKey(e => e.Iddad)
                    .HasName("PK_DadMasCon16");

                entity.Property(e => e.Iddad)
                    .HasColumnName("IDDad")
                    .ValueGeneratedNever();

                entity.Property(e => e.IecclientAddress).HasColumnName("IECClientAddress");

                entity.Property(e => e.IecclientDomain).HasColumnName("IECClientDomain");

                entity.Property(e => e.IecclientOn).HasColumnName("IECClientOn");

                entity.Property(e => e.IecclientPollInterval).HasColumnName("IECClientPollInterval");

                entity.Property(e => e.Iecmmsparam).HasColumnName("IECMMSParam");

                entity.Property(e => e.IecmmsparamFileName).HasColumnName("IECMMSParamFileName");

                entity.Property(e => e.IecsrvAuthentication).HasColumnName("IECSrvAuthentication");

                entity.Property(e => e.IecsrvNrOfClents).HasColumnName("IECSrvNrOfClents");

                entity.Property(e => e.IecsrvOn).HasColumnName("IECSrvOn");

                entity.Property(e => e.Macaddress).HasColumnName("MACAddress");

                entity.Property(e => e.ModbusTcpaddress)
                    .HasColumnName("ModbusTCPAddress")
                    .HasMaxLength(50);

                entity.Property(e => e.ModbusTcpportNr).HasColumnName("ModbusTCPPortNr");

                entity.Property(e => e.Mvbparameters).HasColumnName("MVBParameters");

                entity.Property(e => e.Ntpipaddress).HasColumnName("NTPIPAddress");

                entity.Property(e => e.NtpserverType).HasColumnName("NTPServerType");

                entity.Property(e => e.RefTimeOffset).HasColumnType("datetime");

                entity.Property(e => e.TcppackageErrors).HasColumnName("TCPPackageErrors");

                //user generated:
                entity.HasOne(d => d.IddadNavigation)
                    .WithOne(p => p.DadMasCon)
                    .HasForeignKey<Dad>(d => d.DadMasConId);

                //original:
                //entity.HasOne(d => d.IddadNavigation)
                //    .WithOne(p => p.DadMasCon)
                //    .HasForeignKey<DadMasCon>(d => d.Iddad)
                //    .HasConstraintName("FK_DadMasCon_Dad");
            });

【问题讨论】:

  • Fluent 配置看起来不错。什么是 EF Core 版本?
  • @IvanStoev 3.1.0
  • 你可以在不改变数据库的情况下做任何事情。 [Key] [Column("IdDad")] public int Id { get;放;这是可以达到相同效果的其他语法,也许你会更幸运
  • 无法复制。从帖子中复制类和流畅的配置,将导航属性注释掉到帖子中未包含的实体,并且一切(迁移、查询)都正常工作(没有例外)。是否有一些自定义未在此处显示(部分类扩展中的附加属性、派生类等)?
  • 很多?根据模型,只有DadChDadConnection 类应该有这样的导航属性。而DadMasConDadOpc 应该具有ICollection&lt;Dad&gt; 类型的属性。对吗?

标签: c# entity-framework-core


【解决方案1】:

由于您尝试定义一对一关系,因此您需要在 Dad 模型上明确定义反向引用 ID,以确保它映射到单个 DadCmu 记录。

public partial class Dad
{
    public int DadCmuId { get; set; }
    public virtual DadCmu DadCmu { get; set; }
}

然后您可以像这样使用 fluent API 进行配置:

modelBuilder.Entity<DadCmu>(entity =>
{
    entity.HasOne(d => d.IddadNavigation)
          .WithOne(p => p.DadCmu)
          .HasForeignKey<Dad>(d => d.DadCmuId);
});

HTH

【讨论】:

  • 只要确保我理解:与您的答案相比,基本上 EF Core 的脚手架缺少您手动添加的 id(DadCmuId)。第二部分是通过 HasOne...WithOne... 语法定义关系。您的解决方案对我来说很有意义,我只是不确定为什么 EF Core 的代码是错误的?无论如何,我已经实现了这个,现在我得到了一个不同的错误(好吧,同样的错误,但属于不同的类)所以我会继续这样做。如果这解决了我的问题,我会接受你的回答。不过可能要等到周二。
  • 更新:将其应用于 7 个不同的类后,错误消息现在保持不变,属于我已经“修复”的类,所以除非我在某个地方搞砸了,否则这似乎不起作用。将类添加到 OP。
  • @RD 您的导航属性/关系仍然缺少配置。由于DadCmuId 被明确定义,我只能认为它是另一面。可能是标准 EF 约定(例如:IddadNavigation => IddadNavigation_Id)与您的设置不匹配。 IddadNavigation 的键是什么列名或属性?
  • IddadNavigation 的类型为 Dad,其主键为 Iddad。我不太了解DadDadMasCon 之间的关系中缺少什么。 Dad 包含 DadMasConDadMasConId 类型的属性。 DadMasCon 包含 Dad 类型的属性。在OnModelCreating 中,entity.HasOne(d =&gt; d.IddadNavigation) .WithOne(p =&gt; p.DadMasCon) .HasForeignKey&lt;Dad&gt;(d =&gt; d.DadMasConId); 行现在应该将DadMasConId 定义为外键,对吧?
猜你喜欢
  • 2012-03-21
  • 2021-06-15
  • 2021-01-06
  • 2019-02-09
  • 1970-01-01
  • 1970-01-01
  • 2021-09-28
  • 1970-01-01
  • 2021-03-01
相关资源
最近更新 更多