2

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

问题: 使用 ScriptItems 创建一个新的脚本条目就可以了。当我尝试将 ScriptItems 添加到现有脚本时出现问题。如果我尝试添加没有 ParentId 的 ScriptItems,一切正常。一旦我尝试添加具有 ParentId 的 ScriptItems,我就会收到 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。在 ScriptItems 上正确设置了 ScriptId,我用调试器验证了这一点。

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

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

4

2 回答 2

3

不知道是什么原因造成的。但我认为添加新ScriptItem的而script.Items不是设置他们的所有者脚本可能会有所帮助,即替换

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

经过

script.Items.Add(scriptItem);

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

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

于 2012-10-14T20:55:22.877 回答
0

感谢 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()。

于 2012-10-15T00:50:04.740 回答