Несколько списков одного класса в Entity Framework

2

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

public class Company {
    [Key]
    public string Id { set; get; }
    public string Name { set; get; }

    public virtual ICollection<Company> Customers { set; get; }
    public virtual ICollection<Company> Suppliers { set; get; }
}

Когда я обновляю базу данных таким образом, я получаю одну таблицу соединений, называемую "CompanyCompanies".

CompanyCompanies

| Company_Id | Company_Id1 |
|------------|-------------|
| 1234       | 1234        |

Я хочу создать две таблицы для подключения этих значений, например:

CompanyCustomers

| Company_Id | Customer_Id |
|------------|-------------|
| 1234       | 1234        |

CompanySuppliers

| Company_Id | Supplier_Id |
|------------|-------------|
| 1234       | 1234        |

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

modelBuilder.Entity<Company>()
    .HasMany(c => c.Customers)
    .WithMany()
    .Map(m =>
    {
        m.ToTable("CompanyCustomer");
        m.MapLeftKey("CompanyId");
        m.MapRightKey("CustomerId");
    });

Номер ошибки: -2, состояние: 0, класс: 11 Истекло время ожидания выполнения.
Период ожидания истекает до завершения операции или сервер не отвечает.

Когда я пытаюсь с CompanyCustomer и CompanySupplier, я получаю antoher-ошибку

Либо параметр @objname неоднозначен, либо заявленный код @objtype (COLUMN) ошибочен.

Я также пытался создать новый объект для отношения и иметь объект Company, содержащий список CompanyCustomers, но когда я обновил базу данных, я получил таблицу соединений с тремя столбцами.

public class CompanyCustomer
{
    [Key, Column(Order = 0)]
    [ForeignKey("Company")]
    public string CompanyId { set; get; }
    [Key, Column(Order = 1)]
    [ForeignKey("Customer")]
    public string CustomerId { set; get; }

    public virtual Company Company { set; get; }
    public virtual Company Customer { set; get; }
}

компанииОбслуживание

| CompanyId | CustomerID | Company_Id |
|-----------|------------|------------|
| 1234      | 1234       | 1234       |

Я не понимаю, как я могу создать несколько типов отношений между одним и тем же объектом. Могу ли я сделать это с помощью беглого api или мне нужно перепроектировать мою модель?

  • 1
    Тайм-аут не означает, что модель неверна, просто миграция занимает много времени при выполнении операторов DDL. Технически, две из этих конфигураций HasMany - WithMany должны быть в порядке.
  • 1
    Когда вы говорите, что выполняли неявную конфигурацию « many-to-many.HasMany(c => c.Customers).WithMany() , делали ли вы то же самое для других отношений CompanySuppliers ? Когда я это делаю и смотрю на сгенерированный миграция, это именно то, что вы хотите.
Показать ещё 3 комментария
Теги:
entity-framework
ef-fluent-api

2 ответа

2
Лучший ответ

Свободная конфигурация

modelBuilder.Entity<Company>()
    .HasMany(c => c.Customers)
    .WithMany()
    .Map(m =>
    {
        m.ToTable("CompanyCustomer");
        m.MapLeftKey("CompanyId");
        m.MapRightKey("CustomerId");
    });

действительно правильный способ настройки первых отношений. Вам нужно сделать аналогичное для второго:

modelBuilder.Entity<Company>()
    .HasMany(c => c.Suppliers)
    .WithMany()
    .Map(m =>
    {
        m.ToTable("CompanySupplier");
        m.MapLeftKey("CompanyId");
        m.MapRightKey("SupplierId");
    });

который в моей чистой тестовой среде EF (последний EF6.1.3, если это имеет значение), производит следующую миграцию:

CreateTable(
    "dbo.Company",
    c => new
        {
            Id = c.String(nullable: false, maxLength: 128),
            Name = c.String(),
        })
    .PrimaryKey(t => t.Id);

CreateTable(
    "dbo.CompanyCustomer",
    c => new
        {
            CompanyId = c.String(nullable: false, maxLength: 128),
            CustomerId = c.String(nullable: false, maxLength: 128),
        })
    .PrimaryKey(t => new { t.CompanyId, t.CustomerId })
    .ForeignKey("dbo.Company", t => t.CompanyId)
    .ForeignKey("dbo.Company", t => t.CustomerId)
    .Index(t => t.CompanyId)
    .Index(t => t.CustomerId);

CreateTable(
    "dbo.CompanySupplier",
    c => new
        {
            CompanyId = c.String(nullable: false, maxLength: 128),
            SupplierId = c.String(nullable: false, maxLength: 128),
        })
    .PrimaryKey(t => new { t.CompanyId, t.SupplierId })
    .ForeignKey("dbo.Company", t => t.CompanyId)
    .ForeignKey("dbo.Company", t => t.SupplierId)
    .Index(t => t.CompanyId)
    .Index(t => t.SupplierId);

который именно вы хотите.

Что касается исключений, которые вы получаете, они могут быть связаны с вашими экспериментами с базой данных. Обязательно начинайте с чистой базы данных или удаляйте объект CompanyCompanyCustomer если он там), соответствующий DbSet и DbSet конфигурации, обновляйте базу данных, чтобы очистить предыдущий беспорядок и повторите попытку.

0

Вы можете сделать это только с помощью атрибутов. Ваша проблема заключается в том, что вы используете [ForeignKey] для неправильного свойства - он должен находиться в свойствах навигации.

[ForeignKey(nameof(CompanyId))]
public virtual Company Company { set; get; }

[ForeignKey(nameof(CustomerId))]
public virtual Company Customer { set; get; }

Кроме того, вы можете добавить [InverseProperty] к коллекциям модели. Это помогает понять реляционную навигацию.

[InverseProperty(nameof(CompanyCustomer.Company))]
public virtual ICollection<Company> Customers { set; get; }
  • 0
    Спасибо, но я действительно хочу избежать создания нового класса только для отношений. Это можно обойти?
  • 0
    Зачем избегать нового класса? Лично мне легче понять и расширить, чем использовать свободный API.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню