多对多关系-实体框架正在创建新对象

本文关键字:新对象 对象 创建 关系 实体 框架 | 更新日期: 2023-09-27 18:01:08

我使用的是代码优先的实体框架(6.1.3(。我有一部模型类电影和一个模型类标签,看起来像这样:

public class Movie
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Tag> Tags { get; set; }
}
public class Tag
{
    public int Id { get; set; }
    public string Name { get; set; }
}

在DbContext中,我覆盖了OnModelCreating方法来设置一对多关系,如下所示:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Movie>()
                .HasMany(a => a.Tags)
                .WithMany()
                .Map(x =>
                {
                    x.MapLeftKey("Movie_Id");
                    x.MapRightKey("Tag_Id");
                    x.ToTable("MovieTags");
                });
    base.OnModelCreating(modelBuilder);
}

如果我试图用一些标签将电影插入数据库,我会遇到创建不需要的标签的问题。

例如,我已经在数据库中有两个标签"Foo"(Id:1(和"Bar"(Id:2(。现在我创建了一个新的Movie对象,并将现有的标签"Foo"(从数据库加载(和新的标签"Foobar"插入到对象的Collection中。在我将这部电影添加到DbContext并调用方法"SaveChanges"之后,我的数据库中有两个新标签。

为什么实体框架在我的数据库中插入现有标记?如果只插入缺少的Tag,我需要做些什么?

第1版:这是我添加标签并保存的控制器代码

List<Tag> tagList = new List<Tag>();
// ViewModel.Tags either contains the Tag-Id or the Tag-Name (if it is new)
foreach (string tag in viewModel.Tags)
{
    if (IsDigitsOnly(tag))
    {
        // Load the existing Tag from the DbContext and add to List
        tagList.Add(TagService.Get(int.Parse(tag)));
    }
    else
    {
        // Create new Tag
        tagList.Add(new Tag() { Name = tag });
    }
}
Movie movie = new Movie();
movie.Name = viewModel.Name;
movie.Tags = tagList;
MovieService.Insert(movie);

这是插入的MovieService代码

public void Insert(Movie movie)
{
    Context.Movie.Add(movie);
    Context.SaveChanges();
}

第2版:我发现了问题!这是我如何设置项目的问题。我将Ninject用于DI,并且没有将DbContext绑定到请求(InRequestScope(。所以每次调用我的一个服务时,它都使用不同的DbContext,因此它不知道已经加载的标签。

多对多关系-实体框架正在创建新对象

您能提供添加Tag的代码吗?

与此同时,我认为它有点像

Movie.Tags.Add(new Tag { Name = "foo" });

你可能想添加一个现有的标签如下:

Movie.Tags.Add(ctx.Tags.First(T => T.Name == "foo"));

或者从上下文中获取Tag的等效代码。

此外,你可能想让Tags ICollection成为虚拟的,这样代理就可以覆盖它。这也可能是一个很难找到的错误来源。