Подтвердить что ты не робот

Таблица отображения "Множество ко многим"

Из примеров, которые я видел в Интернете и в книге CodeFirst Framework Framework Entity Framework, когда у вас есть коллекция на обоих классах, EF создаст таблицу сопоставления, такую ​​как MembersRecipes, и первичный ключ из каждого класса будет ссылаться на эту таблицу.

Однако, когда я делаю это, я вместо этого получаю новое поле в таблице Recipes с именем Member_Id и a Recipe_Id в таблице Members.

Что создает только два отношения "один ко многим", но не многие из многих, поэтому я мог бы иметь член 3, связанный с рецептами (4,5,6) и рецептом 4, связанным с членами (1,2,3 ) и т.д.

Есть ли способ создать эту таблицу сопоставления? и если да, как вы называете это чем-то другим, например "кулинарные книги"?

Спасибо

    public abstract class Entity {
        [Required]
        public int Id { get; set; }
    }   

    public class Member : Entity {
        [Required]
        public string Name { get; set; }

        public virtual IList<Recipe> Recipes { get; set; }
    }

    public class Recipe : Entity {  
        [Required]
        public string Name { get; set; }

        [ForeignKey("Author")]
        public int AuthorId { get; set; }
        public virtual Member Author { get; set; }

            ....

        public virtual IList<Member> Members { get; set; }
    }

UPDATE: Ниже приведен другой подход, который я использовал, который не использует API Fluent и заменяет флаг AuthorId и Author на Recipe на флаг владельца, я также переименовал приведенный ниже пример из Cookbooks в MembersRecipes, это также фиксирует мою проблему, аналогичную ответу, но, как уже упоминалось, имеет дополнительные последствия.

public class MembersRecipes {

    [Key, Column(Order = 0)]
    [ForeignKey("Recipe")]
    public int RecipeId { get; set; }
    public virtual Recipe Recipe { get; set; }

    [Key, Column(Order = 1)]
    [ForeignKey("Member")]
    public int MemberId { get; set; }
    public virtual Member Member { get; set; }

    public bool Owner { get; set; }
}

и в классах Recipe и Member я сменил коллекции на

public virtual IList<MembersRecipes> MembersRecipes { get; set; }
4b9b3361

Ответ 1

Сделайте это в своем DbContext OnModelCreating:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{    
    modelBuilder.Entity<Recipe>()
        .HasMany(x => x.Members)
        .WithMany(x => x.Recipes)
    .Map(x =>
    {
        x.ToTable("Cookbooks"); // third table is named Cookbooks
        x.MapLeftKey("RecipeId");
        x.MapRightKey("MemberId");
    });
}

Вы можете сделать это наоборот, это то же самое, только другая сторона той же монеты:

modelBuilder.Entity<Member>()
    .HasMany(x => x.Recipes)
    .WithMany(x => x.Members)
.Map(x =>
{
  x.ToTable("Cookbooks"); // third table is named Cookbooks
  x.MapLeftKey("MemberId");
  x.MapRightKey("RecipeId");
});

Другие примеры:

http://www.ienablemuch.com/2011/07/using-checkbox-list-on-aspnet-mvc-with_16.html

http://www.ienablemuch.com/2011/07/nhibernate-equivalent-of-entity.html


UPDATE

Чтобы предотвратить циклическую привязку к свойству Author, помимо вышеперечисленного, вы должны добавить это:

modelBuilder.Entity<Recipe>()
    .HasRequired(x => x.Author)
    .WithMany()
    .WillCascadeOnDelete(false);

Идея, полученная здесь: Код EF Сначала со многими и многими отношениями для самостоятельной привязки

Главное, вам нужно сообщить EF, что свойство Author (которое является экземпляром Member) не имеет коллекций рецептов (обозначается символом WithMany()); Таким образом, циклическая ссылка может быть остановлена ​​на свойстве Author.

Это созданные таблицы из приведенных выше сопоставлений кода:

CREATE TABLE Members(
    Id int IDENTITY(1,1) NOT NULL primary key,
    Name nvarchar(128) NOT NULL
);


CREATE TABLE Recipes(
    Id int IDENTITY(1,1) NOT NULL primary key,
    Name nvarchar(128) NOT NULL,
    AuthorId int NOT NULL references Members(Id)
);


CREATE TABLE Cookbooks(
    RecipeId int NOT NULL,
    MemberId int NOT NULL,
    constraint pk_Cookbooks primary key(RecipeId,MemberId)
);