在本文中:https://msdn.microsoft.com/en-us/magazine/dn166926.aspx Julie Lerman通过设置1:n
而不是foreign-key
来解释如何避免在navigation property
关系中将重复实体插入数据库。< / p>
我遇到了同样的问题,但关系m:n
。
问题是,我不能只设置外键id,因为我有一个外键列表。
是否可以使用相同的方法:ICollection<int> TopicIds
?
如何使用此方法处理m:n
关系?
提前致谢
编辑:
以下是实体:
public class Artist : PersistenceEntity
{
public Artist()
{
Genres = new List<Genre>();
}
[Key]
public string ArtistId { get; set; }
public string Name { get; set; }
public virtual ICollection<Genre> Genres { get; set; }
}
public class Genre : PersistenceEntity
{
public Genre()
{
Artists = new List<Artist>();
}
[Key]
public int GenreId { get; set; }
public string Name { get; set; }
public virtual ICollection<Artist> Artist { get; set; }
}
答案 0 :(得分:0)
如果您没有外键字段,则无法使用基于外键的方法。但是你仍然可以使用基于实体状态的方法。即如果您正在创建新艺术家并希望提供一些现有类型,那么首先尝试
var artist = new Artist }
Name = "Offspring",
Genres = new List<Genre> { rockGenre, punkGenre }
};
db.Artists.Add(artist);
db.SaveChanges();
但是这会将整个图形放入添加状态(以及两个类型对象)。所以你应该手动指定类型对象的状态:
db.Genres.Attach(rockGenre);
db.Genres.Attach(punkGenre);
var artist = new Artist { Name = "Offspring" };
db.Artists.Add(artist);
artist.Genres = new List<Genre> { rockGenre, punkGenre };
db.SaveChanges();
或者
var artist = new Artist }
Name = "Offspring",
Genres = new List<Genre> { rockGenre, punkGenre }
};
db.Artists.Add(artist);
db.Entry(rockGenre).State = EntityState.Unchanged;
db.Entry(punkGenre).State = EntityState.Unchanged;
db.SaveChanges();
答案 1 :(得分:0)
使用导航属性更新多对多关系没有任何问题,事实上,如果您正在配置您的relationship作为EF建议(如果不这样做,则避免映射联结表)需要向该表添加其他列是唯一的方法。
因此,如果您有一系列类型ID,并且想要将这些类型与艺术家联系起来,那么您可以这样做。
var genresids=new List<int>(){1,3,6,9};
var genres= context.Genres.Where(g=>genresids.Contains(g.GenreId));
var artist=context.Artists.FirstOrDefault(); //Find an artirst
foreach(var genre in genres)
{
artist.Genres.Add(genre);
}
context.SaveChanges();
现在,如果您决定将联结表映射为实体,则需要创建两个一对多关系以替换多对多配置。您的联结实体将是这样的:
public class GenreArtist
{
[Key,Column(Order=1), ForeignKey("Artist")]
public string ArtistId { get; set; }
[Key,Column(Order=2), ForeignKey("Genre")]
public int GenreId { get; set; }
public virtual Artist Artist { get; set; }
public virtual Genre Genre { get; set; }
}
您必须将集合导航属性的类型更改为GenreArtist
:
public virtual ICollection<GenreArtist> GenreArtists{ get; set; }
使用该模型,您可以通过以下方式将多个类型与艺术家联系起来:
var genresids=new List<int>(){1,3,6,9};
var artist=context.Artists.FirstOrDefault(); //Find the artirst you want to update
foreach(var genreId in genresids)
{
artist.GenreArtists.Add(new GenreArtist{ArtistId=artist.ArtistId, GenereId=genreId});
}
context.SaveChanges();
但我真的相信如果您的联结表不会有更多列,则不需要这样做。无论如何,在这个link中你可以找到很好的理由支持映射该表的想法。