Entity framework 防止添加重复的值

Entity framework 防止添加重复的值,entity-framework,Entity Framework,在我的应用程序中,我想指定导演的电影。当然,存储重复的控制器毫无意义,因此我需要以某种方式防止添加重复的行 我记得以前玩sql server的时候玩得很开心,这就成功了: 1. Get Director Id 1a. If director exist return existing director Id 1b. If director not exist add new and return added director Id 2. Add new Movie with di

在我的应用程序中,我想指定导演的电影。当然,存储重复的控制器毫无意义,因此我需要以某种方式防止添加重复的行

我记得以前玩sql server的时候玩得很开心,这就成功了:

1. Get Director Id
    1a. If director exist return existing director Id
    1b. If director not exist add new and return added director Id
2. Add new Movie with directorId assigned.
我只是在学习
实体框架
,我不能这样做。我必须改变将数据库视为集合的方式。因此,我将
导演
添加到
电影
。我不确定我的解释是否正确,因此我认为最好显示代码:

class Program {
        static void Main(string[] args) {
            Movie firstMovie = new Movie() { Name = "Titanic" };
            Movie secondMovie = new Movie() { Name = "Pulp Fiction" };
            Movie thirdMovie = new Movie() { Name = "Matrix" };

            Director director = new Director() { Name = "Warner Bros" };

            firstMovie.Director = director;
            secondMovie.Director = director;
            thirdMovie.Director = director;

            Db.AddMovie(firstMovie);
            Db.AddMovie(secondMovie);
            Db.AddMovie(thirdMovie);
        }
    }

    public class Movie {
        public int Id { get; set; }
        public string Name { get; set; }

        public int DirectorId { get; set; }
        [ForeignKey("DirectorId")]
        public virtual Director Director { get; set; }
    }

    public class Director {
        public int Id { get; set; }
        public string Name { get; set; }

        public virtual List<Movie> Movies { get; set; }

        public Director() {
            Movies = new List<Movie>();
        }
    }

    public class Db {
        public static int AddMovie(Movie movie) {
            using (var context = new MovieContext()) {
                    context.Movies.Add(movie);
                    context.SaveChanges();
                    return movie.Id;
                }
            }
    }

    public class MovieContext : DbContext {
        public DbSet<Movie> Movies { get; set; }
        public DbSet<Director> Directories { get; set; }
    }
这是我的新方法,它将返回
Director
(如果需要,还可以添加)

那么这是最好的方法吗?我不确定添加新的
控制器
是否正确编码。你有什么建议吗

我的数据库中有3倍于同一个控制器

我想你有三个不同的董事,他们的身份证会不同

如果你只想有一个导演,你需要让DataContext知道他。也许您可以添加一个AddDirector方法,并在使用该方法之前将其添加到数据库中。
然后,当您这样做时:

firstMovie.Director = director;
secondMovie.Director = director;
thirdMovie.Director = director;
DataContext会知道导演,你的三部电影也会知道

我的意思是我无法检查是否已经有同名目录, 因为我不是手动添加它们。实体框架正在添加新的 目录,不是我。那么,我能用它做什么呢

对于实体框架,两个没有ID值的控制器是两个不同的控制器让它知道您要使用同一个控制器的唯一方法是使用具有ID值的控制器。
所以你可以:
-使用名称和id创建您的导演新导演{id=1,name=“Warner Bros”}

-使用数据库中存在的控制器(实体框架知道他,他有一个ID)

你可以从另一边走。 只需将
电影
对象添加到您的
导演
对象集合中即可。然后将
Director
对象保存到数据库中,它应该可以正常工作

仅作为示例代码:

Movie firstMovie = new Movie { Name = "Titanic" };
Movie secondMovie = new Movie { Name = "Pulp Fiction" };
Movie thirdMovie = new Movie { Name = "Matrix" };

// here you should take one from data context or create it, if it does not exist
Director director = new Director { Name = "Warner Bros" }; 

director.Movies.Add(firstMovie);
director.Movies.Add(secondMovie);
director.Movies.Add(thirdMovie);

// add new or update director with new movies
Db.AddOrUpdateDirector(director);

当然,不只是创建一个新的目录,您应该检查目录是否已经存在于datacontext中并使用该目录。

不幸的是,您这样做总是会导致对同一director对象的每个引用都有一个新的director行。为什么?因为它们是在三个不同的上下文中添加的

EF仅通过
DbContext
跟踪对象。它(不幸的是,也许)不会试图从对象的属性中收集关于图形中对象状态的任何信息。因此,第二次使用与第一次相同的导演保存
电影
,EF只会发现它对该
导演
一无所知,并继续将其作为新对象添加到图形中。调用
SaveChanges()
时,会将其适当地添加到数据库中

SaveChanges()
之前,您可以通过查看
Director
参考的
DbEntry
来观察这种情况,您还可以看到
Director.Id
每次都会更改

有几种策略可用于缓解这种行为:

  • 在单个上下文中添加所有内容
  • 添加导演,然后对于每部电影,仅从
    director.Id
    设置
    DirectorId
  • 添加导演,为每部电影手动将导演对象的输入状态设置为“未更改”
  • 在上下文中,首先执行
    context.Directors.Find(movie.Director.Id)
    以确保导演在添加电影之前已经在上下文中

  • 我不能那样做。当我添加新导演并在最后将该导演分配给所有电影时,我在数据库中获得了3个导演。工作原理是添加新的导演,但按id分配:
    firstMovie.director.id=director.id。我的问题是-为什么我不能通过引用指定?谢谢。第二种策略对我来说似乎是最明智的。
    
    firstMovie.Director = director;
    secondMovie.Director = director;
    thirdMovie.Director = director;
    
    Movie firstMovie = new Movie { Name = "Titanic" };
    Movie secondMovie = new Movie { Name = "Pulp Fiction" };
    Movie thirdMovie = new Movie { Name = "Matrix" };
    
    // here you should take one from data context or create it, if it does not exist
    Director director = new Director { Name = "Warner Bros" }; 
    
    director.Movies.Add(firstMovie);
    director.Movies.Add(secondMovie);
    director.Movies.Add(thirdMovie);
    
    // add new or update director with new movies
    Db.AddOrUpdateDirector(director);