61 votes

Table de correspondance Many-to-many

D'après les exemples que j'ai vus en ligne et dans le livre Programming Entity Framework CodeFirst, lorsque vous avez une collection sur les deux classes, EF créerait une table de correspondance telle que MembersRecipes et la clé primaire de chaque classe serait liée à cette table.

Cependant, lorsque je fais ce qui suit, j'obtiens à la place un nouveau champ dans le champ Recipes table appelée Member_Id et un Recipe_Id dans le Members table.

Cela ne crée que deux relations de type "un vers plusieurs", mais pas de type "plusieurs vers plusieurs". Je pourrais donc avoir le membre 3 lié aux recettes (4, 5, 6) et la recette 4 liée aux membres (1, 2, 3), etc.

Existe-t-il un moyen de créer cette table de correspondance ? Et si oui, comment la nommer autrement, par exemple "livres de cuisine" ?

Merci

    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 : Vous trouverez ci-dessous une autre approche que j'ai essayée, qui n'utilise pas l'API Fluent et remplace la fonction AuthorId & Author en Recipe avec un drapeau de propriétaire, j'ai également renommé l'exemple ci-dessous de Cookbooks a MembersRecipes Cela résout également mon problème de la même manière que la réponse, mais comme mentionné, cela a d'autres implications.

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; }
}

et en Recipe & Member J'ai changé les collections en

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

98voto

Michael Buen Points 20453

Faites ceci sur votre 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");
    });
}

Vous pouvez aussi le faire dans l'autre sens, c'est la même chose, juste un autre côté de la même pièce :

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");
});

Autres exemples :

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

Pour empêcher la référence cyclique sur votre propriété Author, en dehors de ce qui précède, vous devez ajouter ceci :

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

Idée trouvée ici : Code EF Premier avec relation d'auto-référencement de plusieurs à plusieurs

Le point essentiel est que vous devez informer EF que la propriété Author (qui est une instance de Member) n'a pas de collections de recettes (désignée par WithMany() ) ; de cette façon, la référence cyclique pourrait être arrêtée sur la propriété de l'auteur.

Ce sont les tables créées à partir des mappings Code First ci-dessus :

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)
);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X