Thursday, 19 September 2013

EF Inserting/Updating navigational properties vs assigning Id's performance?

EF Inserting/Updating navigational properties vs assigning Id's performance?

Let's assume we have a model/database tables like below (not well laid out
but fits my question). Let's also assume one movie has always only one
director and one producer.
Genre
Id
Name
SubGenre
Id
Name
GenreId
Genre (navigational property)
Director
Id
Name
List<Movie> (navigational property)
Producer
Id
Name
List<Movie> (navigational property)
Actors
Id
Name
List<Movie> (there is many-many table in db) (navigational property)
Movie
Id
Name
SubGenreId
DirectorId
ProducerId
List<Actor> (navigational property)
Director (navigational property)
Producer (navigational property)
SubGenre (navigational property)
MovieActors (table)
MovieId
ActorId
Now, let's assume, we are already in the data layer (so there will be not
be major change-tracking on objects except for the id's). We have the data
in the movie object that needs to be persisted. If it exists, it needs to
be updated, if not inserted.
Movie object (movieDTO) that's sent to DataLayer.
MovieName
GenreName
SubGenreName
DirectorName
ProducerName
List ActorNames
Let's also assume there are millions of Directors/Producers/Actors/Movies
(basically huge amounts of data in each table) and the names of
directors/producers/actors/movie are unique for simplicity purpose. So the
logic would be, if the SubGenre exists use that, otherwise create SubGenre
record. Similarly look for if Genre exists, use that otherwise create it.
Likewise for the director, producer and actors.
Finally, the questions are
Which of these would be faster and why? (or) Are they same even while
taking millions of records into consideration?
Is it likely to change between Sql Server and Oracle? (With oracle, I am
using Devart as the provider)
Approach 1:
using (MovieDBContext context = new MovieDBContext())
{
Movie movie;
movie = context.Movies.Where(a => a.Name ==
movieDTO.MovieName).SingleOrDefault();
if (movie == null)
movie = new Movie() { Name = movieDTO.MovieName };
var subGenre = context.SubGenres.Where(a => a.Name ==
movieDTO.SubGenreName).SingleOrDefault();
if (subGenre == null)
{
movie.SubGenre = new SubGenre() { Name =
movieDTO.SubGenreName };
// Check if Genre exists.
var genre = context.Genres.Where(a => a.Name ==
movieDTO.GenreName).SingleOrDefault();
if (genre == null)
{
movie.SubGenre.Genre = new Genre() { Name =
movieDTO.GenreName };
}
else
{
movie.SubGenre.Genre = genre;
}
}
else
movie.SubGenre = subGenre;
var director = context.Directors.Where(a => a.Name ==
movieDTO.DirectorName).SingleOrDefault();
if (director == null)
movie.Director = new Director() { Name =
movieDTO.DirectorName };
else
movie.Director = director;
var producer = context.Producers.Where(a => a.Name ==
movieDTO.ProducerName).SingleOrDefault();
if (producer == null)
movie.Producer = new Producer() { Name =
movieDTO.ProducerName };
else
movie.Producer = producer;
// I am skipping the logic of deleting all the actors if the
movie is existing.
foreach (var name in movieDTO.Actors)
{
var actor = context.Actors.Where(a => a.Name ==
name).SingleOrDefault();
if (actor == null)
movie.Actors.Add(new Actor() { Name = name });
else
movie.Actors.Add(actor);
}
// Finally save changes. All the non-existing entities are
added at once.
// EF is keeping track if the entity exists or not.
context.SaveChanges();
}
Approach 2:
using (MovieDBContext context = new MovieDBContext())
{
var genre = context.Genres.Where(a => a.Name ==
movieDTO.GenreName).SingleOrDefault();
if (genre == null)
{
genre = new Genre() { Name = movieDTO.GenreName };
context.Genres.Add(genre); // genre.Id is populated with
the new id.
context.SaveChanges();
}
var subGenre = context.SubGenre.Where(a => a.Name ==
movieDTO.SubGenreName).SingleOrDefault();
if (subGenre == null)
{
subGenre = new SubGenre() { Name = movieDTO.SubGenreName };
context.SubGenres.Add(subGenre); // subGenre.Id is
populated with the new id.
context.SaveChanges();
}
var director = context.Directors.Where(a => a.Name ==
movieDTO.DirectorName).SingleOrDefault();
if (director == null)
{
director = new Director() { Name = movieDTO.DirectorName };
context.Directors.Add(director); // director.Id is
populated with the new id.
context.SaveChanges();
}
var producer = context.Producers.Where(a => a.Name ==
movieDTO.ProducerName).SingleOrDefault();
if (producer == null)
{
producer = new Producer() { Name = movieDTO.ProducerName };
context.Producers.Add(producer); // director.Id is
populated with the new id.
context.SaveChanges();
}
// Similarly for actors, add them if they don't exist.
foreach (var name in movieDTO.Actors)
{
var actor = new Actor() { Name = movieDTO.name };
context.Actors.Add(actor);
context.SaveChanges();
}
// Lastly movie.
Movie movie = context.Movies.Where(a => a.Name ==
movieDTO.MovieName).SingleOrDefault();
if (movie == null)
{
movie = new Movie() { Name = movieDTO.MovieName };
}
// This works for update as well.
// The id's are added/updated instead of actual entities.
movie.DirectorId = director.Id;
movie.SubGenreId = subGenre.Id;
movie.ProducerId = producer.Id;
// I am skipping the logic of deleting all the actors if the
movie is existing.
foreach (var name in movieDTO.Actors)
{
var actor = context.Actors.Where(a => a.Name ==
name).SingleOrDefault(); // Actors always exist now
because we added them above.
movie.Actors.Add(actor);
}
// Finally save changes. Here only Movie object is saved as
all other objects are saved earlier.
context.SaveChanges();
}

No comments:

Post a Comment