I have a Language
model defined as such:
public class Language
{
[JsonProperty("iso_639_1")]
public string Iso { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
public override bool Equals(object obj)
{
if (!(obj is Language))
{
return false;
}
return ((Language)obj).Iso == Iso;
}
public override int GetHashCode()
{
return Iso.GetHashCode();
}
}
This is used in a model Movie
as ICollection<Language> SpokenLanguages
. I am seeding my database using the information I gather. When multiple movies use the same language, I obviously want to re-use the existing entry in the Languages
table.
The following achieves that by re-using the existing types and adding new ones:
var localLanguages = context.Languages.ToList();
var existingLanguages = localLanguages.Union(movie.SpokenLanguages);
var newLanguages = localLanguages.Except(existingLanguages).ToList();
newLanguages.AddRange(existingLanguages);
movie.SpokenLanguages = newLanguages;
This works but obviously this is rather ugly and not EF-friendly. I'm looking into attaching the existing models to EF and have it automatically re-use it but I can't seem to get it to work -- I end up with this error message:
Attaching an entity of type '
Models.Movies.Language
' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach
' method or setting the state of an entity to 'Unchanged
' or 'Modified
' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add
' method or the 'Added
' entity state to track the graph and then set the state of non-new entities to 'Unchanged
' or 'Modified
' as appropriate.
The code in question is this:
var localLanguages = context.Languages.ToList();
foreach (var language in movie.SpokenLanguages)
{
if (localLanguages.Contains(language))
{
context.Languages.Attach(language);
// no difference between both approaches
context.Entry(language).State = EntityState.Unchanged;
}
}
Setting the state as Unchanged
or Modified
does not make a difference. The JSON response I receive is
{
"iso_639_1": "en",
"name": "English"
}
These values are exactly the same as those existing in the database, both fields.
Each insertion in the database creates a new context and disposes of it.
How can I get EF to re-use the existing language entries instead of having to sift through them myself?