ASP. NET EF CORE: составной ключ, состоящий из двух внешних ключей, которые не оцениваются должным образом - PullRequest
0 голосов
/ 21 февраля 2020

РЕДАКТИРОВАТЬ После некоторого редактирования я теперь могу опубликовать данные, но у меня есть проблемы с созданием структуры. Мой модельер чувствует, что сейчас стало лучше, но что-то все еще не в порядке

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

Я пытаюсь создать веб-приложение с использованием EF Core, которое будет разрешить клиенту владеть любым количеством машин и регистрировать их данные. Каждая машина может быть разного типа, и у каждого типа машины есть уникальная таблица, поскольку они регистрируют разные вещи. Я могу без проблем создать объект «Клиент и машина», но как только я пытаюсь записать данные в свои таблицы данных Machinexxx, у меня возникают проблемы, связанные с использованием составных внешних ключей.

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

Имеет отношение один ко многим с классом 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

Имеет отношение один ко многим с (в настоящее время) двумя возможными типами машин

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

Наконец, мой конструктор моделей выглядит следующим образом (здесь все мои отношения сделаны, я стараюсь не использовать аннотации данных из-за их ограничения)

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

Я хотел бы иметь все строка будет одной записью данных с уникальным составным ключом, состоящим из MachineID, ClientID, Timestamp. Но, как я объясню ниже, в настоящее время это невозможно ...

Как я уже говорил ранее, все операции CRUD для ботов класса Client и Machine работают нормально. Но MachineBob невероятно проблематичен c. Несмотря на то, что дизайн модели видит, что есть составной ключ из трех элементов, я получаю ошибку SQL всякий раз, когда пытаюсь записать в таблицу. Что очень странно, так это то, что я могу писать, как и ожидалось, при условии, что я использовал ClientID = 1, MachineID = 1 и уникальную метку времени, которая мне нужна. Но как только я пытаюсь добавить еще одну строку или другой экземпляр этой машины BOB, написав Client ID = X, начинают возникать проблемы.

Вот исключение SQL, которое, похоже, имеет проблему только с ClientId не быть уникальным. Но это часть составного ключа, поэтому проблема не должна возникать в любом случае:

SqlException: оператор INSERT конфликтует с ограничением FOREIGN KEY "FK_MachineBobs_Clients_ClientID". Конфликт произошел в базе данных «as pnet -ProcessCloudApp-B3DBF3A9-F26 C -41F4-B7D6-CC2D2782C266», таблица «dbo.Clients», столбец «ID». Утверждение было прекращено.

Я хотел бы получить некоторую помощь, касающуюся моего моделестроения, поскольку я чувствую себя наиболее потерянным с этим.

Часть меня чувствует, что проблема может также заключаться в том, как я Я думаю об этой модели данных "MachineBob". Возможно, было бы лучше вместо этого иметь отношение один к одному между «Машиной» и «Машинным бобом» и иметь все свойства типа ICollection<T> или List<T>

Спасибо за вашу помощь.

1 Ответ

0 голосов
/ 21 февраля 2020

Мне удалось решить проблему (заняло всего неделю). Я соответственно изменил свои модели, но также избавился от «клиента клиента publi c» в MachineBOB. Даже если мне нужен ClientID, объекты не связаны напрямую друг с другом. Вот код для ссылки на любого другого, кто считает, что стоит критиковать его дальше или для собственного использования в этих полусложных отношениях.

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

и класс

[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; }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...