【问题标题】:EF 5.0 Code First adding new children to existing parentEF 5.0 Code First 向现有父级添加新子级
【发布时间】:2012-10-14 16:50:04
【问题描述】:

概述: 我正在使用 Code First 和 EF 5.0 开发 MVC ASP.Net 应用程序。我有两个表:Scripts 和 ScriptItems。一个脚本可以有多个 ScriptItem。 ScriptItems 也是分层的。 ScriptItems 可以选择性地属于彼此,但谢天谢地,这种关系只有 1 级深。这种关系由 ScriptItem.ParentId 指示。

问题: 使用 ScriptItems 创建一个新的脚本条目就可以了。当我尝试将 ScriptItems 添加到现有脚本时出现问题。如果我尝试添加没有 ParentId 的 ScriptItems,一切正常。一旦我尝试添加具有 ParentId 的 ScriptItem,我就会收到 FK 违规异常。

详情:

脚本类:

public class Script
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string Type { get; set; }
    [ForeignKey("ProcessorId")]
    public Processor Processor { get; set; }
    public int ProcessorId { get; set; }
    public string Owner { get; set; }
    public DateTime Created { get; set; }
    public bool Public { get; set; }

    public List<ScriptItem> Items { get; set; }
    public List<ScriptRun> Runs { get; set; }

    public Script()
    {
        Items = new List<ScriptItem>();
        Created = DateTime.Now;
    }
}

ScriptItem 类:(为简洁起见)

 public class ScriptItem
{
    [Key]
    public int Id { get; set; }

    [ForeignKey("ParentId")]
    public ScriptItem Parent { get; set; }
    public int? ParentId { get; set; }

    public Script Script { get; set; }
    [ForeignKey("Script")]
    public int ScriptId { get; set; }

添加脚本项的函数:

private void addToScript(ScriptModel model, List<int> ids)
    {
        Script script = scriptRepository.GetScriptWithItems(model.ScriptId);
        List<History> historyItems = historyRespository.History.Where(h => ids.Contains(h.Id)).ToList();

        ScriptItem lastScriptItem = script.Items.OrderByDescending(item => item.SortIndex).FirstOrDefault();
        int topSortIndex = lastScriptItem == null ? 0 : lastScriptItem.SortIndex;

        if (script != null)
        {
            List<ScriptItem> newItems = new List<ScriptItem>();
            Mapper.CreateMap<History, ScriptItem>();
            foreach (History h in historyItems)
            {
                ScriptItem scriptItem = new ScriptItem();
                Mapper.Map(h, scriptItem); //Populate new ScriptItem from History entry
                scriptItem.SortIndex = ++topSortIndex;
                scriptItem.ScriptId = model.ScriptId;
                scriptItem.Script = script;

                //Only add an entry if it is NOT the parent of another entry. Otherwise, EF will duplicate the Parent entries
                if (!historyItems.Any(his => his.ParentId == h.Id))
                    newItems.Add(scriptItem);    
            }
            scriptRepository.AddScriptItems(newItems);
        }
    }

最后是 scriptRepository.AddScripItems():

public void AddScriptItems(List<ScriptItem> items)
    {
        items.ForEach(item => context.Entry(item).State = System.Data.EntityState.Added);
        context.SaveChanges();
    }

考虑我将两个 ScriptItems A 和 B 添加到现有脚本的场景。 A 是 B 的父级。当我运行 SQL Server 跟踪时,我看到尝试插入父记录 A,但 ScriptId 为 0,因此出现 FK 违规异常。不知道为什么 ScriptId 为 0。ScriptId 在 ScriptItems 上设置正确,我用调试器验证了这一点。

我没有包含插入新脚本和项目的函数,因为它与上面的 addToScript 函数非常相似。它工作正常。但是如果有人想看,我也可以添加。

比我聪明的人有什么想法吗?谢谢!

【问题讨论】:

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


    【解决方案1】:

    不确定是什么原因造成的。但我认为将新的ScriptItem 添加到script.Items 而不是设置其所有者脚本(即替换)可能会有所帮助

    scriptItem.ScriptId = model.ScriptId;
    scriptItem.Script = script;
    

    通过

    script.Items.Add(scriptItem);
    

    另一个优点是您不必再手动更改它们的状态:更改跟踪器知道何时将新项目添加到跟踪的集合中。我什至想知道在您的脚本中是否有必要这样做,因为设置 Script 也应该足够了。

    也许设置script ScriptId 改变状态过多干扰了EF自身的逻辑并使其偏离轨道。

    【讨论】:

    • 你先生,摇滚!尽管您的答案不是确切的解决方法,但它使我走上了最终解决的道路。可悲的是,我不能赞成你的回答,因为我仍然是一个卑微的菜鸟。感谢您的回复!!!
    【解决方案2】:

    感谢 Gert Arnold 为我指明了正确的方向。这个问题最终源于我如何通过 AutoMapper 构建我的 ScriptItems。我无法解释确切的问题是什么,但这是我修改后的工作代码,以防有人发现它有用。

    private void addToScript(ScriptModel model, List<int> ids)
        {
            Script script = scriptRepository.GetScriptWithItems(model.ScriptId);
            List<History> historyItems = historyRespository.History.Where(h => ids.Contains(h.Id)).ToList();
    
            ScriptItem lastScriptItem = script.Items.OrderByDescending(item => item.SortIndex).FirstOrDefault();
            int topSortIndex = lastScriptItem == null ? 0 : lastScriptItem.SortIndex;
    
            if (script != null)
            {
                Mapper.CreateMap<History, ScriptItem>();
                List<ScriptItem> Parents = new List<ScriptItem>();
                List<History> SourceParents = historyItems
                    .Where(h => historyItems.Any(h2 => h2.ParentId == h.Id)).ToList();
    
                SourceParents.Each(h =>
                {
                    ScriptItem parent = new ScriptItem();
                    Mapper.Map(h, parent);
                    parent.Script = script;
                    Parents.Add(parent);
                });
    
                historyItems.Except(SourceParents).Each(h =>
                {
                    ScriptItem child = new ScriptItem();
                    Mapper.Map(h, child);
                    child.Script = script;
                    if (child.ParentId.HasValue)
                        child.Parent = Parents.SingleOrDefault(p => p.Id == child.ParentId);
                    script.Items.Add(child);
                });
    
                //Todo: Get sortIndex "sorted" out
    
                scriptRepository.SaveScript(script);
            }
        }
    

    scriptRepository.SaveScript 只是将脚本的状态设置为已修改并调用 SaveChanges()。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-26
      • 1970-01-01
      相关资源
      最近更新 更多