2012-06-02 2 views
6

Это должен быть простой вопрос для хорошо знакомого пользователя EF.Сопоставление многих во многих отношениях с использованием внешнего ключа

У меня есть следующая схема (в моей голове) о том, как должны выглядеть отношения между таблицами.

[FooBar]  [Foo]   [Bar] 

FooId PK,FK Id PK   Id PK 
BarId PK,FK BarId FK  Name 
IsRead  Name   Description 
       Description  

Хотя, когда я пытаюсь генерировать схему с использованием EF-кодом первым он не интерпретировать отношения между сущностями, как я интерпретировал их (добавляет внешний ключ FooId к [bar] таблице) и не чтобы полностью создать таблицу моста [FooBar].

Если кто-то может направить меня на то, как достичь вышеуказанной схемы, используя код EF4, я бы очень признателен. Независимо от того, связано ли решение с атрибутами на моих моделях POCO, плавные конфигурации или гибрид обоих, не имеет большого значения - до тех пор, пока создается желаемая схема базы данных.


POCO Модели:

public class Foo 
{ 
    public int Id { get; set; } 
    public string Text { get; set; } 
    public string Description { get; set; } 
    public int BarId { get; set; } 

    public Bar Bar { get; set; } /* bar entity */ 

    public virtual ICollection<Bar> BridgedBars { get; set; } 

    public Foo() 
    { 
     Bars = new List<Bar>(); 
    } 
} 

public class Bar 
{ 
    public int Id { get; set; } 
    public string Text { get; set; } 
    public string Description { get; set; } 

    public virtual ICollection<Foo> Foos { get; set; } 
    public virtual ICollection<Foo> BridgedFoos { get; set; } 

    public Bar() 
    { 
     Foos = new List<Foo>(); 
     BridgedFoos = new List<Foo>(); 
    } 
} 

public class FooBar 
{ 
    public int FooId { get; set; } 
    public int BarId { get; set; } 

    public virtual Foo Foo { get; set; } 
    public virtual Bar Bar { get; set; } 

    public bool IsRead { get; set; } 
} 
+0

Как вы имеют свойство (IsRead) в отношении FooBar, которое вы, вероятно, хотите установить из кода, и Foo, и Bar нуждаются в том, чтобы их связанные коллекции были FooBars. Как только вы наберете свойства с обоих концов (т. Е. Виртуальные коллекции в Foo и Bar) в FooBar EF, необходимо правильно создать отношение. Используйте HasMany(). WithRequired(), чтобы сопоставить каждый класс с FooBar. –

ответ

8

Ваша модель действительно будет создавать в Bar, которая принадлежит к отношениям, определяемой Foo.BrideBars внешнего ключа FooId. EF не связывает это свойство навигации с одним из свойств ICollection<Foo> в Bar, потому что есть два из них:, а EF не может однозначно определить правильную пару. В результате создается связь для Foo.BrideBars без свойства навигации на другом конце. Так сказать, есть невидимое свойство Bar.Foo, которое вызывает внешний ключ.

Схема базы данных, которую вы хотите сопоставить с моделью, на самом деле не представляет отношения «многие ко многим», а вместо этого имеет два отношения «один ко многим» с промежуточным «мостовым» объектом FooBar. Вы должны использовать этот класс в свойствах навигации, чтобы определить правильные отношения. Это будет выглядеть так:

public class Foo 
{ 
    public int Id { get; set; } 
    public string Text { get; set; } 
    public string Description { get; set; } 

    public int BarId { get; set; } 
    public Bar Bar { get; set; } 

    public virtual ICollection<FooBar> FooBars { get; set; } 
} 

public class Bar 
{ 
    public int Id { get; set; } 
    public string Text { get; set; } 
    public string Description { get; set; } 

    public virtual ICollection<Foo> Foos { get; set; } 
    public virtual ICollection<FooBar> FooBars { get; set; } 

} 

public class FooBar 
{ 
    [Key, Column(Order = 0)] 
    public int FooId { get; set; } 
    [Key, Column(Order = 1)] 
    public int BarId { get; set; } 

    public virtual Foo Foo { get; set; } 
    public virtual Bar Bar { get; set; } 

    public bool IsRead { get; set; } 
} 

Правильные отношения будут обнаружены соглашениями об именах в этой модели. Только для объекта FooBar необходимо явно определить ключ, потому что имена свойств не соответствуют соглашениям (нет Id и не FooBarId). В этой модели имеет смысл использовать составной ключ в FooBar.

Я думаю, ваши настоящие классы и свойства не имеют названия Foo и Bar. Если ваши настоящие имена не следуют соглашениям вы, возможно, должны определить отношения с аннотациями - или Fluent API:

modelBuilder.Entity<Foo>() 
    .HasRequired(f => f.Bar) 
    .WithMany(b => b.Foos) 
    .HasForeignKey(f => f.BarId); 

modelBuilder.Entity<FooBar>() 
    .HasKey(fb => new { fb.FooId, fb.BarId }); // replaces the [Key] annotations 

modelBuilder.Entity<FooBar>() 
    .HasRequired(fb => fb.Foo) 
    .WithMany(f => f.FooBars) 
    .HasForeignKey(fb => fb.FooId); 

modelBuilder.Entity<FooBar>() 
    .HasRequired(fb => fb.Bar) 
    .WithMany(b => b.FooBars) 
    .HasForeignKey(fb => fb.BarId); 

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

[FooBar]  [Foo]   [Bar] 

FooId PK,FK Id PK   Id PK 
BarId PK,FK BarId FK  Name 
IsRead   Name   Description 
       Description  

Но наличие PK в FooBar необходимо, потому что каждый объект в EF-модели должен иметь определенное свойство ключа - одно или комбинированное, которое сопоставляется с первичным ключом в таблице базы данных.

В этом вопросе - Create code first, many to many, with additional fields in association table - более подробно, как работать с таким типом отношений. (Иногда люди также называют это отношением «многие ко многим» с полезной нагрузкой »(свойство IsRead - это« полезная нагрузка »в вашей примерной модели), но на самом деле это не многие-ко-многим.)

+0

именно то, что я искал, и да, имея сложный первичный ключ на FooBar, был моим намерением - просто забыл упомянуть об этом! Спасибо за отличный ответ и объяснение! как только мой профиль достигнет * 15 очков *, я обязательно вернусь и проголосую. – culturalanomoly

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