数据库中的重复项
Duplicates in database
我将 vs2017 与 entityframework 6.1.0 和 winforms 一起使用。至于 entityframework 我使用代码优先。我需要制作一个电影应用程序,我已经为他们 Movie
、Genre
和 Cast
(演员)制作了所有 classes。
所有 Genres
都预先插入到数据库中。使用 update-database 时,会创建所有内容,包括连接表 moviegenre 和 movie cast 以及外键。当我插入电影对象时。它链接了来自类型演员和电影的 ID,但它也重新插入了每个类型,这意味着我有重复项。我当然只想要链接。到目前为止,这是我的代码。
电影class:
public class Movie
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int MovieId { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
//[ForeignKey("GenreId")]
public virtual List<Genre> Genre { get; set; }
//[ForeignKey("CastId")]
public virtual List<Cast> cast { get; set; }
[Required]
public int GenreId { get; set; }
[Required]
public int CastId { get; set; }
[Display(Name = "Release Date")]
public DateTime ReleaseDate { get; set; }
public Movie()
{
Genre = new List<Genre>();
cast = new List<Cast>();
}
}
类型和演员表(classes 相同)
public class Genre
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int GenreId { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
public List<Movie> Movies { get; set; }
}
当然还有我的代码(这段代码来自将电影添加到数据库中的按钮单击事件。):
private void btnAddMovie_Click(object sender, EventArgs e)
{
List<Genre> genrelist = new List<Genre>();
List<Cast> castlist = new List<Cast>();
var movie = new Movie();
movie.Name = txtTitle.Text;
movie.ReleaseDate = released;
//creating lists
foreach (string item in lbgenre2.Items)
{
var genre = new Genre();
genre.Name = item;
genrelist.Add(genre);
}
foreach (string item in lbCast2.Items)
{
var cast = new Cast();
cast.Name = item;
castlist.Add(cast);
}
movie.Genre = genrelist;
movie.cast = castlist;
_context.movies.Add(movie);
Save();
}
private async void Save()
{
await _context.SaveChangesAsync();
}
链接并重新插入它是我做错了什么?
你的问题是因为你要再次创建 Generes,并且每次添加新电影时都要重新创建,并且你有一个身份密钥,所以不会抛出异常。
foreach (string item in lbgenre2.Items)
{
//Here is your problem, you are creating a new Genere instead of using the already created
var genre = new Genre();
genre.Name = item;
genrelist.Add(genre);
}
因此,不要创建,而是使用 ef 获取现有的
foreach (string item in lbgenre2.Items)
{
//try to get the genere from database
var genre = _context.generes.FirstOrDefault(x => x.Name == item);
//if it doesn't exist..
if(genre == null)
{
//Create it
genre = new Genre();
//And set the name
genre.Name = item;
}
//but, if it already exist, you dont create a new one, just use the existing one
genrelist.Add(genre);
}
Entity Framework 无法确定 Genre
或 Cast
是否已经存在,即使您创建了其中之一的实例,其属性与数据库中存在的实例具有相同的属性.相反,您需要从数据库中获取现有类型和演员表并应用它们。并且只创建一个新的实例,如果它是一个全新的类型或演员表,它不在数据库中:
伪代码:
SaveMovie(Movie movie)
{
var existingGenres = GetGenresFromDatabase();
var movieGenres = GetGenresFromListBox();
foreach (var genre in movieGenres)
{
if (genre in existingGenres)
{
existingGenre = existingGenres.Where(genreId = genre.Id);
movie.Genres.Add(existingGenre)
}
else
{
movies.Add(genre)
}
}
dbcontext.Add(movie);
dbcontext.SaveChanges();
}
我将 vs2017 与 entityframework 6.1.0 和 winforms 一起使用。至于 entityframework 我使用代码优先。我需要制作一个电影应用程序,我已经为他们 Movie
、Genre
和 Cast
(演员)制作了所有 classes。
所有 Genres
都预先插入到数据库中。使用 update-database 时,会创建所有内容,包括连接表 moviegenre 和 movie cast 以及外键。当我插入电影对象时。它链接了来自类型演员和电影的 ID,但它也重新插入了每个类型,这意味着我有重复项。我当然只想要链接。到目前为止,这是我的代码。
电影class:
public class Movie
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int MovieId { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
//[ForeignKey("GenreId")]
public virtual List<Genre> Genre { get; set; }
//[ForeignKey("CastId")]
public virtual List<Cast> cast { get; set; }
[Required]
public int GenreId { get; set; }
[Required]
public int CastId { get; set; }
[Display(Name = "Release Date")]
public DateTime ReleaseDate { get; set; }
public Movie()
{
Genre = new List<Genre>();
cast = new List<Cast>();
}
}
类型和演员表(classes 相同)
public class Genre
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int GenreId { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
public List<Movie> Movies { get; set; }
}
当然还有我的代码(这段代码来自将电影添加到数据库中的按钮单击事件。):
private void btnAddMovie_Click(object sender, EventArgs e)
{
List<Genre> genrelist = new List<Genre>();
List<Cast> castlist = new List<Cast>();
var movie = new Movie();
movie.Name = txtTitle.Text;
movie.ReleaseDate = released;
//creating lists
foreach (string item in lbgenre2.Items)
{
var genre = new Genre();
genre.Name = item;
genrelist.Add(genre);
}
foreach (string item in lbCast2.Items)
{
var cast = new Cast();
cast.Name = item;
castlist.Add(cast);
}
movie.Genre = genrelist;
movie.cast = castlist;
_context.movies.Add(movie);
Save();
}
private async void Save()
{
await _context.SaveChangesAsync();
}
链接并重新插入它是我做错了什么?
你的问题是因为你要再次创建 Generes,并且每次添加新电影时都要重新创建,并且你有一个身份密钥,所以不会抛出异常。
foreach (string item in lbgenre2.Items)
{
//Here is your problem, you are creating a new Genere instead of using the already created
var genre = new Genre();
genre.Name = item;
genrelist.Add(genre);
}
因此,不要创建,而是使用 ef 获取现有的
foreach (string item in lbgenre2.Items)
{
//try to get the genere from database
var genre = _context.generes.FirstOrDefault(x => x.Name == item);
//if it doesn't exist..
if(genre == null)
{
//Create it
genre = new Genre();
//And set the name
genre.Name = item;
}
//but, if it already exist, you dont create a new one, just use the existing one
genrelist.Add(genre);
}
Entity Framework 无法确定 Genre
或 Cast
是否已经存在,即使您创建了其中之一的实例,其属性与数据库中存在的实例具有相同的属性.相反,您需要从数据库中获取现有类型和演员表并应用它们。并且只创建一个新的实例,如果它是一个全新的类型或演员表,它不在数据库中:
伪代码:
SaveMovie(Movie movie)
{
var existingGenres = GetGenresFromDatabase();
var movieGenres = GetGenresFromListBox();
foreach (var genre in movieGenres)
{
if (genre in existingGenres)
{
existingGenre = existingGenres.Where(genreId = genre.Id);
movie.Genres.Add(existingGenre)
}
else
{
movies.Add(genre)
}
}
dbcontext.Add(movie);
dbcontext.SaveChanges();
}