Я использую vs2017 с entityframework 6.1.0 и winforms. Что касается сущности, я использую код в первую очередь. Мне нужно сделать приложение для фильма, я сделал для них все классы Movie
, Genre
и Cast
(актеры). Все Genres
предварительно вставляются в базу данных. При использовании update-database создается все, включая объединение таблиц moviegenre и cast cast, а также чужих клавиш. Когда я вставляю объект фильма. он связывает идентификатор из жанра актерского состава и фильмов, но также переустанавливает каждый жанр, что означает, что у меня есть дубликаты. Я хочу только ссылки, конечно. Пока это мой код.
класс фильма:
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>();
}
}
Жанр и состав актеров (одинаковые для обоих классов)
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();
}
Что я делаю не так, что он связывает и вставляет его?
Ваша проблема в том, что вы снова создаете жанры и снова и снова каждый раз, когда добавляете новый фильм, и у вас есть Identity Key, поэтому исключение не выдается.
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 dont exist..
if(genre == null)
{
//Create it
genre = new Genre();
//And set the name
genre.Name = item;
}
//but, if it already exist, you didn't 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();
}
FirstOrDefaultAsync
или даже создавали отдельный метод для получения существующих жанров.