c# - EF 5.0 Code First 将新子项添加到现有父项

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

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

问题: 使用 ScriptItems 创建新的脚本条目效果很好。当我尝试将 ScriptItem 添加到现有脚本中时,就会出现问题。如果我尝试添加没有 ParentId 的 ScriptItem,则一切正常。一旦我尝试添加具有 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();
    }

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

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

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

最佳答案

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

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

script.Items.Add(scriptItem);

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

也许设置scriptScriptId改变状态对EF本身的逻辑干扰太大,把它偏离轨道。

关于c# - EF 5.0 Code First 将新子项添加到现有父项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12884382/

相关文章:

entity-framework - 先映射私有(private)属性 Entity Framework 代码

c# - 在 Debug模式下跳过 While 循环

c# - 如何在 C# 中使用正则表达式获取某个特定单词之前的数字?

c# - 简单的 asp.net 标记帮助器列表 <> 问题

c# - 建立数据库连接的最佳方法是什么(静态、抽象、按请求……)?

c# - ObjectContext.ExecuteStoreCommand,如何在调用之间清除参数?

c# - 在 ASP.net MVC Entity Framework 代码中创建外键关系

c# - 使用类将数据存储到列表中

c# - 如何映射具有延迟加载属性的实体(不会导致它们加载)?

c# - EF Code First 外键必须映射到一些在概念方面参与外键关联的 AssociationSet 或 EntitySet