【发布时间】:2015-02-16 15:44:31
【问题描述】:
我有一个Language 模型定义如下:
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();
}
}
这在模型Movie 中用作ICollection<Language> SpokenLanguages。我正在使用我收集的信息播种我的数据库。当多部电影使用同一种语言时,我显然想重用Languages 表中的现有条目。
以下内容通过重用现有类型并添加新类型来实现:
var localLanguages = context.Languages.ToList();
var existingLanguages = localLanguages.Union(movie.SpokenLanguages);
var newLanguages = localLanguages.Except(existingLanguages).ToList();
newLanguages.AddRange(existingLanguages);
movie.SpokenLanguages = newLanguages;
这可行,但显然这很丑陋且不适合 EF。我正在考虑将现有模型附加到 EF 并让它自动重新使用它,但我似乎无法让它工作——我最终收到以下错误消息:
附加类型为“
Models.Movies.Language”的实体失败,因为同一类型的另一个实体已经具有相同的主键值。如果图中的任何实体具有冲突的键值,则在使用“Attach”方法或将实体的状态设置为“Unchanged”或“Modified”时,可能会发生这种情况。这可能是因为某些实体是新实体,尚未收到数据库生成的键值。在这种情况下,使用“Add”方法或“Added”实体状态来跟踪图形,然后将非新实体的状态设置为“Unchanged”或“Modified”视情况而定。
有问题的代码是这样的:
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;
}
}
将状态设置为Unchanged 或Modified 没有区别。我收到的 JSON 响应是
{
"iso_639_1": "en",
"name": "English"
}
这些值与数据库中存在的值完全相同,两个字段。
数据库中的每次插入都会创建一个新的上下文并处理它。
如何让 EF 重新使用现有的语言条目,而不必自己筛选它们?
【问题讨论】:
-
语言与
MovieLanguages表中定义的电影具有多对多关系。如果我简单地省略一个语言条目,它将不会记录在此表中,这是在我的Movie模型中拥有该导航属性的全部意义。
标签: c# entity-framework entity-framework-6