Сначала я пытаюсь создать модель данных компаний с отношениями к одному типу в коде 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 или мне нужно перепроектировать мою модель?
Свободная конфигурация
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);
который именно вы хотите.
Что касается исключений, которые вы получаете, они могут быть связаны с вашими экспериментами с базой данных. Обязательно начинайте с чистой базы данных или удаляйте объект Company
(и CompanyCustomer
если он там), соответствующий DbSet
и DbSet
конфигурации, обновляйте базу данных, чтобы очистить предыдущий беспорядок и повторите попытку.
Вы можете сделать это только с помощью атрибутов. Ваша проблема заключается в том, что вы используете [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; }
HasMany - WithMany
должны быть в порядке.many-to-many
(с.HasMany(c => c.Customers).WithMany()
, делали ли вы то же самое для других отношенийCompanySuppliers
? Когда я это делаю и смотрю на сгенерированный миграция, это именно то, что вы хотите.