处理缓存的实体

时间:2016-02-01 14:56:21

标签: c# .net entity-framework ef-code-first

我的应用程序使用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}}属性。
  • 在保存之前,将标记标记为&#34;不更改&#34;在上下文中,所以它不会尝试保存它们。
  • 将每个Tag的新副本重新加载到用于保存Tag的上下文中。
  • 在应用程序的整个生命周期中使用单个Script

适当的&#34;实体框架方式&#34;处理这种模式?

1 个答案:

答案 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