避免在m:n关系中使用ForeignKey插入重复项?

时间:2016-02-02 14:12:21

标签: c# entity-framework-6

在本文中: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; }
}

2 个答案:

答案 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中你可以找到很好的理由支持映射该表的想法。