简体   繁体   English

ASP.NET EF CORE:由两个外键组成的复合键无法正确评估

[英]ASP.NET EF CORE: Composite key composed of two foreign keys not evaluating properly

EDIT After some editing I am now able to post the data but have issues scaffolding the structure.编辑经过一些编辑后,我现在可以发布数据,但在搭建结构时遇到问题。 My model builder feels like it's better now but something is still amiss我的模型构建器现在感觉好多了,但还是有些不对劲

modelBuilder.Entity<Client>().HasMany(x => x.Machines).WithOne(x=>x.Client).HasForeignKey(x=>x.ClientID);
modelBuilder.Entity<Machine>().HasKey(x => new { x.ID, x.ClientID });
modelBuilder.Entity<MachineBob>().HasOne(x => x.Machine).WithMany(x => x.MachineBobData).HasForeignKey(x => new { x.MachineID, x.ClientID }).OnDelete(DeleteBehavior.NoAction);
modelBuilder.Entity<MachineMixer>().HasOne(x => x.Machine).WithMany(x => x.MachineMixerData).HasForeignKey(x => new { x.MachineID, x.ClientID }).OnDelete(DeleteBehavior.NoAction);
modelBuilder.Entity<MachineBob>().HasKey(c => new { c.TimeStamp, c.ClientID, c.MachineID });
modelBuilder.Entity<MachineMixer>().HasKey(x => new { x.TimeStamp, x.MachineID, x.ClientID });

END - EDIT结束 - 编辑

I am attempting to build a web app using EF Core that will allow a Client to own any number of machines and log their data.我正在尝试使用 EF Core 构建一个 Web 应用程序,该应用程序将允许客户端拥有任意数量的机器并记录其数据。 Each machine can be of a different type and every type of machine has a unique table as they log different things.每台机器都可以是不同的类型,并且每种类型的机器都有一个唯一的表,因为它们记录不同的内容。 I am able to create a Client and Machine object without any trouble but as soon as I try to log data into my Machinexxx data tables I run into issues concerning my use of composite foreign keys.我能够毫无困难地创建 Client 和 Machine 对象,但是一旦我尝试将数据记录到我的 Machinexxx 数据表中,我就会遇到有关使用复合外键的问题。

CloudApp.Models CloudApp.Models

public class Client 
{
    [Required]
    [MaxLength(100)]
    public string ClientName { get; set; }
    [MaxLength(100)]
    [Key]
    public int ID { get; set; }
    [MaxLength(100)]
    // TODO: Automatically assign these email addresses as CLAIMS to allow the USER to see the CLIENT
    public List<String> Emails;
    public ICollection<Machine>? Machines { get; set; }
}

Which has a one to many relationship with the Machine class here它与这里的Machine类有一对多的关系

public class Machine
{
    [MaxLength(50)]
    [Key]
    public int ID { get; set; }

    [MaxLength(100)]
    public string Factory { get; set; }
    [MaxLength(50)]
    public string Line { get; set; }

    [MaxLength(50)]
    public string MachineType { get; set; }
    [MaxLength(50)]
    public string MachineName { get; set; }
    [MaxLength(50)]
    public string Country { get; set; }
    [MaxLength(50)]
    public string City { get; set; }
    [MaxLength(25)]
    public int ZipCode { get; set; }
    [MaxLength(50)]
    public string Address { get; set; }

    [MaxLength(50)]
    public int ClientID { get; set; }
    public Client Client { get; set; } // Navivation property
    public List<MachineBob>? MachineBobData { get; set; } // Navivation property
    public List<MachineMixer>? MachineMixerData { get; set; }// Navivation property

Which has a one to many relationship with the (currently) two possible machine types它与(当前)两种可能的机器类型有一对多的关系

public class MachineBob 
{
    [MaxLength(50)]
    [XmlElement("TimeStamp")]
    public DateTime TimeStamp { get; set; }
    [XmlElement("Temperature")]
    [MaxLength(50)]
    public int Temperature { get; set; }
    [MaxLength(50)]
    [XmlElement("Heartbeat")]
    public Boolean Heartbeat { get; set; }

    [MaxLength(50)]
    [ForeignKey("MachineID")]
    public int MachineID { get; set; }
    public Machine Machine { get; set; }
    [MaxLength(50)]
    [ForeignKey("ClientID")]
    public int ClientID { get; set; }
    public Client Client { get; set; }
}

[XmlRoot("Root"),Serializable]
public class MachineMixer 
{
    [MaxLength(50)]
    [XmlElement("TimeStamp")]
    public DateTime TimeStamp { get; set; }
    [XmlElement("Temperature")]
    [MaxLength(50)]
    public int MixingRatio { get; set; }
    [MaxLength(50)]
    [XmlElement("Heartbeat")]
    public Boolean Heartbeat { get; set; }
    [XmlIgnore]

    [MaxLength(50)]
    public int MachineID { get; set; }
    public Machine Machine { get; set; }
    [MaxLength(50)]
    public int ClientID { get; set; }
    public Client Client { get; set; }
}

Lastly my model builder looks like this (all of my relationships are made here I try not to use data annotations due to their limitation)最后我的模型构建器看起来像这样(我的所有关系都在这里建立,由于它们的限制,我尽量不使用数据注释)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
        base.OnModelCreating(modelBuilder);

        foreach (var foreignKey in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
        {
            foreignKey.DeleteBehavior = DeleteBehavior.Cascade;
        }

        modelBuilder.Entity<Client>().HasMany(x => x.Machines);

        modelBuilder.Entity<Machine>().HasOne(x => x.Client).WithMany(x => x.Machines).HasForeignKey(x => x.ClientID);
        modelBuilder.Entity<Machine>().HasKey(x => new { x.ClientID, x.ID });

        modelBuilder.Entity<Machine>().HasMany(x => x.MachineBobData).WithOne(x => x.Machine).HasForeignKey(x => new { x.MachineID, x.ClientID })OnDelete(DeleteBehavior.NoAction); 
        modelBuilder.Entity<Machine>().HasMany(x => x.MachineMixerData).WithOne(x => x.Machine).HasForeignKey(x => new { x.MachineID, x.ClientID }).OnDelete(DeleteBehavior.NoAction);

        modelBuilder.Entity<MachineBob>().HasKey(c => new { c.TimeStamp, c.ClientID, c.MachineID });

        modelBuilder.Entity<MachineMixer>().HasKey(x => new { x.TimeStamp, x.MachineID, x.ClientID });
}

What I would like to do is have every row be one data entry with a unique composite key composed of MachineID, ClientID, Timestamp .我想要做的是让每一行都是一个数据条目,具有一个由MachineID, ClientID, Timestamp组成的唯一复合键。 But as I explain below that is not currently possible...但正如我在下面解释的那样,目前不可能......

As I stated before all CRUD operations for bot the Client and Machine class work fine.正如我之前所说的,客户端和机器类的所有 CRUD 操作都可以正常工作。 But MachineBob is incredibly problematic.但是 MachineBob 是令人难以置信的问题。 Even though the model design sees that there is a composite key of three elements I get a SQL error whenever I attempt to write to the table.即使模型设计看到存在三个元素的复合键,但每当我尝试写入表时,我都会收到 SQL 错误。 What is very strange is that I can write as expected so long as I used ClientID = 1, MachineID = 1, and a unique Timestamp which is what I want.很奇怪的是,只要我使用 ClientID = 1、MachineID = 1 和我想要的唯一时间戳,我就可以按预期编写。 But as soon as I attempt to add another row or another instance of this Machine BOB by writing Client ID=X issues start to arise.但是,一旦我尝试通过写入 Client ID=X 来添加此 Machine BOB 的另一行或另一个实例,问题就会开始出现。

Here is the SQL exception which seems to only have a problem with ClientId not being unique.这是 SQL 异常,它似乎只有 ClientId 不唯一的问题。 But it is part of a composite key so the problem shouldn't be occurring anyway:但它是复合键的一部分,所以无论如何都不应该发生问题:

SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_MachineBobs_Clients_ClientID". SqlException: INSERT 语句与 FOREIGN KEY 约束“FK_MachineBobs_Clients_ClientID”冲突。 The conflict occurred in database "aspnet-ProcessCloudApp-B3DBF3A9-F26C-41F4-B7D6-CC2D2782C266", table "dbo.Clients", column 'ID'.数据库“aspnet-ProcessCloudApp-B3DBF3A9-F26C-41F4-B7D6-CC2D2782C266”、表“dbo.Clients”、“ID”列中发生冲突。 The statement has been terminated.该语句已终止。

I would like some assistance concerning my modelbuilding as I feel most lost with this.我想要一些关于我的模型构建的帮助,因为我对此感到最迷茫。

Part of me feels that the problem may also lay with how I'm thinking about this "MachineBob" data model.我的一部分认为问题也可能在于我如何考虑这个“MachineBob”数据模型。 Perhaps it would be better to instead have a one to one relationship between "Machine" and "MachineBob" and have all properties of type ICollection<T> or List<T>也许最好在“Machine”和“MachineBob”之间建立一对一的关系并拥有ICollection<T>List<T>类型的所有属性

Thank you for your assistance.谢谢您的帮助。

I was able to solve the issue (only took all week).我能够解决这个问题(只花了整周时间)。 I modified my modelbuilders accordingly but also got rid of the "public Client Client" in the MachineBOB.我相应地修改了我的模型构建器,但也摆脱了 MachineBOB 中的“公共客户端客户端”。 Even though I need the ClientID the objects are not directly connected to each other.即使我需要 ClientID,对象也没有直接相互连接。 Here's the code for reference to anyone else who finds it worth critiquing further or for their own use on this semi-complex relationship.这是供其他人参考的代码,他们认为值得进一步批评或供他们自己在这种半复杂关系中使用。

        modelBuilder.Entity<Client>().HasMany(x => x.Machines).WithOne(x=>x.Client).HasForeignKey(x=>x.ClientID);
        modelBuilder.Entity<Client>().HasKey(x => x.ID);
        modelBuilder.Entity<Machine>().HasKey(x => new { x.ID, x.ClientID });
        modelBuilder.Entity<MachineBob>().HasOne(x => x.Machine).WithMany(x => x.MachineBobData).HasForeignKey(x => new { x.MachineID, x.ClientID}).OnDelete(DeleteBehavior.NoAction);
        modelBuilder.Entity<MachineMixer>().HasOne(x => x.Machine).WithMany(x => x.MachineMixerData).HasForeignKey(x => new { x.MachineID, x.ClientID }).OnDelete(DeleteBehavior.NoAction);
        modelBuilder.Entity<MachineBob>().HasKey(c => new { c.TimeStamp, c.ClientID, c.MachineID });
        modelBuilder.Entity<MachineMixer>().HasKey(x => new { x.TimeStamp, x.MachineID, x.ClientID });

and the class和班级

[XmlRoot("Root"),Serializable]
public class MachineBob 
{
    [MaxLength(50)]
    [XmlElement("TimeStamp")]
    public DateTime TimeStamp { get; set; }
    [XmlElement("Temperature")]
    [MaxLength(50)]
    public int Temperature { get; set; }
    [MaxLength(50)]
    [XmlElement("Heartbeat")]
    public Boolean Heartbeat { get; set; }

    [MaxLength(50)]
    [ForeignKey("MachineID")]
    public int MachineID { get; set; }
    public Machine Machine { get; set; }
    [MaxLength(50)]
    [ForeignKey("ClientID")]
    public int ClientID { get; set; }

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

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