避免在 m:n 关系中使用外键插入重复项
本文关键字:插入 关系 | 更新日期: 2023-09-27 18:32:50
在本文中: Julie Lerman https://msdn.microsoft.com/en-us/magazine/dn166926.aspx 正在解释如何通过设置foreign-key
而不是navigation property
来避免在1:n
关系中插入重复实体。
我有同样的问题,但关系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; }
}
如果没有外键字段,则不能使用基于外键的方法。但是,您仍然可以使用基于实体状态的方法。即,如果您正在创建新的艺术家并希望提供一些现有的流派,那么第一次尝试将是
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();
使用导航属性更新多对多关系没有错,事实上,如果您按照 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();
但我真的相信,如果您的连接表不会有更多列,则没有必要这样做。无论如何,在此链接中,您可以找到支持映射该表的想法的充分理由。