D'après des exemples que j'ai vus en ligne et dans un livre CodeFirst Framework of Programming Entity, lorsque vous avez une collection sur les deux classes, EF crée une table de mappage telle que MembersRecipes
et la clé primaire de chaque classe est liée à cette table. .
Cependant, lorsque je fais ce qui suit, je reçois plutôt un nouveau champ dans la table Recipes
appelée Member_Id
et un Recipe_Id
dans la table Members
.
Ce qui crée seulement deux relations un-à-plusieurs, mais pas plusieurs-à-plusieurs, de sorte que le membre 3 puisse être lié aux recettes (4,5,6) et la recette 4 liée aux membres (1,2,3), etc.
Est-il possible de créer cette table de mappage? et si oui comment appelez-vous quelque chose d'autre tel que "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; }
}
PDATE: Voici une autre approche que j'ai essayée, qui n'utilise pas l'API Fluent et remplace le AuthorId
& Author
sur Recipe
par un propriétaire flag, j’ai également renommé l’exemple ci-dessous, de Cookbooks
à MembersRecipes
, cela corrige également le problème, tout comme la réponse, mais avec des implications supplémentaires.
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 dans les classes Recipe
et Member
, j'ai modifié les collections en
public virtual IList<MembersRecipes> MembersRecipes { get; set; }
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, mais 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
[~ # ~] met à jour [~ # ~]
Pour éviter toute référence cyclique sur votre propriété Author, à part ce qui précède, vous devez ajouter ceci:
modelBuilder.Entity<Recipe>()
.HasRequired(x => x.Author)
.WithMany()
.WillCascadeOnDelete(false);
Idée fournie ici: Code EF d'abord avec une relation d'auto-référencement multiple à multiple
Le principal est que vous devez informer EF que la propriété Author (qui est une instance de membre) ne contient aucune collection de recettes (notée WithMany()
); De cette façon, la référence cyclique pourrait être arrêtée sur la propriété Author.
Voici les tables créées à partir des mappages 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)
);