Вопрос по sql-server, c#, .net, entity-framework – Соотношение между многими и многими со ссылкой на внешний ключ

6

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

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

[FooBar]      [Foo]          [Bar]

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

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

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

POCO Models:

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; }
}
Поскольку у вас есть свойство (IsRead) в отношении FooBar, которое вы, вероятно, хотите установить из кода, как Foo, так и Bar необходимо, чтобы их связанные коллекции были FooBars. Как только вы отобразите свойства на обоих концах (то есть виртуальные коллекции в Foo и Bar) в FooBar EF, вы должны правильно создать отношение. Используйте HasMany (). WithRequired () для сопоставления каждого класса с FooBar. Morten Mertner

Ваш Ответ

1   ответ
8

FooId вBar который относится к отношениям, определяемымFoo.BrideBars. 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 entity необходимо явно определить ключ, потому что имена свойств не соответствуют соглашениям (нет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    

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

В этом вопросе - Сначала создайте код, многие ко многим, с дополнительными полями в таблице ассоциации - подробнее о том, как работать с таким типом отношений. (Иногда люди называют это «отношениями многих ко многим с полезной нагрузкой "(theIsRead свойство - это «полезная нагрузка» в вашем примере модели), но на самом деле это не много ко многим.)

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

Похожие вопросы