2016-12-26 2 views
0

я не знаю, как настроить следующие соотношения в EF:Entity Framework моделирование один-ко-многим

Представьте мне нужно создать какой-то язык словаря модели. У меня есть элемент (например, слово) на одном языке и на другом языке. Между этими двумя элементами существует некоторая связь.

Например: «Пёс» (на немецком языке) -> «собака» (на английском языке), тип отношения «Перевести»

public enum Language 
{ 
    English, 
    German, 
} 

public class Item 
{ 
    public long ID { get; set; } 
    [Required] 
    public string Value { get; set; } 
    [Required] 
    public Language Language { get; set; } 

    public virtual ICollection<ItemRelation> ItemRelations { get; set; } 
} 

public enum ItemRelationType 
{ 
    Translate, 
    Synonym, 
} 

public class ItemRelation 
{ 
    public long ID { get; set; } 

    [ForeignKey("ItemID")] 
    public Item Item { get; set; } 

    [ForeignKey("RelativeItemID")] 
    public Item RelativeItem { get; set; } 

    [Required] 
    public ItemRelationType Type { get; set; } 
} 

EF стандартная миграция есть ошибку в одном случае или создает столбцы или FKS I не привычка (Item_ID и т. д.) в другом.

Я думаю, мне нужно настроить некоторые свободно API - но я не знаю, как ...

+0

"некоторый язык словарь модели", "некоторые отношение "," некоторая ошибка "," один случай - другой случай "- все это довольно расплывчато. –

ответ

1

Вы не хватает фактических полей FK ItemID и RelativeItemID:

и настроить свойство навигации вы можете использовать атрибут InverseProperty, наряду с отключением немного EF конвенции (как показано ниже).

public class ItemRelation 
{ 
    public long ID { get; set; } 

    public long ItemID { get; set; } // Missing 
    [ForeignKey("ItemID")] 
    [InverseProperty("ItemRelations")] 
    public virtual Item Item { get; set; } 

    public long RelativeItemID { get; set; } // Missing 
    [ForeignKey("RelativeItemID")] 
    [InverseProperty("RelativeItemRelations")] 
    public virtual Item RelativeItem { get; set; } 

    [Required] 
    public ItemRelationType Type { get; set; } 
} 

Декларация выше использует virtual так, что ленивые погрузочные работы. Это не обязательно, и вы можете удалить его. Следствием этого является то, что ленивая загрузка не будет работать, и это тоже нормально.

Предполагая, что вы хотите, свойство навигации для второго соотношения необходимо добавить свойство:

public class Item 
{ 
... 
    public virtual ICollection<ItemRelation> RelativeItemRelations { get; set; } 
... 
} 

А затем отключить каскадное удаление конвенции путем переопределения OnModelCreating, если вы уже не имеете, в вашем контексте класса следующим образом:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
... 
    modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 
... 

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

Второй способ добиться того, что вы хотите, чтобы просто использовать свободно API следующим образом:

Добавить второе свойство навигации к вашему Item объекта:

public class Item 
{ 
... 
    public virtual ICollection<ItemRelation> RelativeItemRelations { get; set; } 
... 
} 

ItemRelation объект отсутствует в FKs, так что вот оно:

общественный класс ItemRelation { public long ID {get; задавать; }

public long ItemID { get; set; } // Missing 
    public virtual Item Item { get; set; } 

    public long RelativeItemID { get; set; } // Missing 
    public virtual Item RelativeItem { get; set; } 

    [Required] 
    public ItemRelationType Type { get; set; } 
} 

и настроить свойство навигации, и избежать проблем каскадных, вы просто определить отношения с использованием свободно API:

public TheContext : DbContext 
{ 
    public DbSet<Item> Items { get; set; } 
    public DbSet<ItemRelation> ItemRelations { get; set; } 

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

     modelBuilder.Entity<ItemRelation>() 
       .HasRequired(e => e.Item) 
       .WithMany(t => t.ItemRelations) 
       .HasForeignKey(e => e.ItemID) 
       .WillCascadeOnDelete(false); 

     modelBuilder.Entity<ItemRelation>() 
       .HasRequired(e => e.RelatedItem) 
       .WithMany(t => t.RelativeItemRelations) 
       .HasForeignKey(e => e.RelativeItemID) 
       .WillCascadeOnDelete(false);  


     // Uncomment the following if you want to disable all cascading deletes and automatic fk creation conventions 
     // modelBuilder.Conventions.Remove<ForeignKeyIndexConvention>(); 
     // modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 
     // modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); 

    ... 
    } 
} 

Read here for an opinion on why you might consider disabling those conventions.

+0

Да. Но таким образом у меня есть следующая ошибка: «Представляем ограничение FOREIGN KEY» FK_dbo.ItemRelations_dbo.Items_RelativeItemID »в таблице« ItemRelations »может вызывать циклы или несколько каскадных путей. Укажите ON DELETE NO ACTION или ON UPDATE NO ACTION или измените другой FOREIGN KEY Ограничения. Не удалось создать ограничение или индекс. См. предыдущие ошибки. " Возможно, мне просто нужно установить cascadeDelete в false - я не знаю этих свойств. – Petr

+0

@Petr. Одно из решений - отключить каскадное удаление, а другое - использовать свободный api для настройки отношения. Я добавил оба ответа. – Klinger

1

Я думаю, вы могли бы уйти с этим:

public class ItemRelation 
{ 

    public long Id { get; set; } 

    [ForeignKey("PrimaryItemId")] 
    public Item Item { get; set; } 
    public long PrimaryItemId { get; set; } 

    [ForeignKey("RelatedItemId")] 
    public Item RelatedItem { get; set; } 
    public long RelatedItemId { get; set; } 

    public ItemRelationType RelationType; 
} 

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

Просмотрите этот ответ как подталкивание на другом треке. Изучите эту тему, чтобы узнать, подходит ли она вашему прецеденту.

Смежные вопросы