我的应用程序使用Code First Entity Framework来管理" Scripts"。脚本可以有多个"标签"与他们相关联。
public class Tag
{
public Guid TagId { get; set; }
public string Name { get; set; }
public ICollection<Script> Scripts { get; set; }
}
public class Script
{
public Guid ScriptId { get; set; }
public string Title { get; set; }
...
public ICollection<Tag> Tags { get; set; } = new List<Tag>();
}
当应用程序启动时,它会加载所有标记的列表并保留对它们的引用。当用户编辑脚本时,他们可以在脚本上添加和删除标记。当用户添加标签时,我只需使用script.Tags.Add(tag)
添加引用。当我保存脚本时,第一次一切正常,但在后续脚本上,它最终会保存旧脚本的多个副本并创建重复的标签。
我确切地知道它为什么会发生。当我调用Context.SaveChanges
时,它会修复引用并将脚本添加到标记的脚本集合中,然后该集合将持续进行下一次保存。我不知道的是,防止这种情况发生的正确方法是什么?
我提出了一些有效的解决方案,但它们似乎都不是理想的,而且其中一些有严重的缺点。随着应用程序的增长,它们也将开始变得越来越复杂和容易出错,我开始有更多这样的关联。我觉得我必须遗漏一些明显的东西。
.Scripts
的{{1}}属性。Tag
的新副本重新加载到用于保存Tag
的上下文中。Script
。适当的&#34;实体框架方式&#34;处理这种模式?
答案 0 :(得分:1)
我认为最简单的解决方案是将联结类绘制到类模型中:
public class Tag
{
public Guid TagId { get; set; }
public string Name { get; set; }
}
public class ScriptTag
{
public Guid ScriptId { get; set; }
public Guid TagId { get; set; }
public virtual Script Script { get; set; }
public virtual Tag Tag { get; set; }
}
public class Script
{
public Guid ScriptId { get; set; }
public string Title { get; set; }
...
public virtual ICollection<ScriptTag> ScriptTags { get; set; }
= new List<ScriptTag>();
}
现在,您可以直接操作脚本标记关联,而无需将单个Tag
对象加载到执行作业的上下文中。用户可以从预加载的标签中进行选择,您只需相应地创建/删除这些轻量级ScriptTag
实体。
假设您有一个包含所选标签的viewModel
对象,这是一种方法:
var script = db.Scripts.Include(s => s.ScriptTags)
.Single(s => s.ScriptId == scriptId);
// Simply replace the `ScriptTags` collection.
script.ScriptTags.Clear();
script.ScriptTags.AddRange(viewModel.Tags.Select(t => new ScriptTag
{
ScriptId = scriptId,
TagId = t.TagId
});
db.SaveChanges();
这是如何获取脚本的所有标记:
from script in db.Scripts
where script.ScriptId == scriptId
from scriptTag in script.ScripTags
select scriptTag.Tag.Name