【问题标题】:DbContext.Save on parent with child objects throws "Conflicting changes detected"带有子对象的父对象上的 DbContext.Save 会引发“检测到冲突更改”
【发布时间】:2014-11-27 22:12:33
【问题描述】:

我有一个父/子层次结构,我想将新的父级插入到 DbContext 中并让它自动保留子对象。这种关系是一对多的,每个父级可以在 0 列或更多列。

但每当我调用 DbContext.Save(parent) 时,我都会收到“检测到冲突更改”。尝试插入具有相同键的多个实体时可能会发生这种情况。当我剥离子列的父级时,它可以节省罚款,所以我假设这与没有设置主键的子对象有关。如何告诉 EntityFramework 正确保存我的层次结构?

我的课:

public class ExcelTemplate
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int FirstDataRow { get; set; }
    public virtual ICollection<TemplateColumn> Columns { get; set; }

    public ExcelTemplate()
    {
        Columns = new List<TemplateColumn>();
    }
}

public class TemplateColumn
{
    public int Id { get; set; }
    public int Index { get; set; }
    public int MetricTypeId { get; set; }
    public virtual MetricType MetricType { get; set; }

    public int TemplateId { get; set; }
    public virtual ExcelTemplate Template { get; set; }
}

以及配置:

public class ExcelTemplateConfiguration : EntityTypeConfiguration<ExcelTemplate>
{
    public ExcelTemplateConfiguration()
    {
        HasKey(t => t.Id)
            .Property(t => t.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        Property(t => t.Name)
            .IsRequired();

        HasMany(t => t.Columns)
            .WithRequired(c => c.Template)
            .HasForeignKey(c => c.TemplateId);
    }
}

public class TemplateColumnConfiguration : EntityTypeConfiguration<TemplateColumn>
{
    public TemplateColumnConfiguration()
    {
        HasKey(c => c.Id)
            .Property(c => c.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        HasRequired(tpl => tpl.MetricType)
            .WithRequiredDependent();
    }
}

【问题讨论】:

    标签: c# entity-framework-6


    【解决方案1】:
    1. ExcelTemplate.IdTemplateColumn.Id 是否有身份规范?您是否正确设置了Id 属性?

    2. 您是否将TemplateColumn 对象的ExcelTemplate 属性设置为ExcelTemplate 父对象?

    类似:

    ExcelTemplate t = new ExcelTemplate();
    //init template code...skip
    
    TemplateColumn c = new TemplateColumn();
    //init template column code...skip
    c.ExcelTemplate = t;//this is the line I am asking if you are doing. 
    

    【讨论】:

    • ExcelTemplate.Id 和 TemplateColumn.Id 都设置为 DatabaseGeneratedOption.Identity(见上面我的 sn-p 中的配置,这是代码的最后一位)。在我的 ExcelTemplateRepository.Save() 中,我遍历所有列并设置父对象: foreach (var c in tpl.Columns) c.Template = tpl;
    • 我目前使用了一些技巧来完成这项工作,但这远非理想。我在 DbContext 中添加了一个 DbSet 并且当前首先插入父项,然后是子项,但这是不可取的,因为它需要做更多的工作,而且有一个 ORM 映射器。
    • 您是否尝试在一个仅包含 EF6 上下文和一些创建实体的代码的简单项目中重现这一点?你得到了同样的结果吗?
    • 我现在有,我可以安全地断定问题仍然存在。我有点假设我以某种方式在我的配置中做了一个 booboo 并且混淆了 EF,但我不知道我做错了什么。
    • 也许值得注意的是,我使用 MySQL 作为主机来与之交谈。
    【解决方案2】:

    我通过反复试验发现了罪魁祸首,因为当我仅尝试单独存储 TemplateColumn 时问题仍然存在。

    问题是从TemplateColumn配置中去掉这行代码,让实体框架按照约定映射:

    HasRequired(tpl => tpl.MetricType)
        .WithRequiredDependent();
    

    知道为什么这不起作用吗?

    【讨论】:

    • 也许您可以将其移至您的问题,因为实际上它缩小了您的原始问题。如果您显示进行更改的代码,我们很有可能解决这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-03
    • 2014-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多