多对一关系导致DbUpdateException

时间:2016-07-29 09:23:43

标签: c# entity-framework entity-framework-6 one-to-many

我有以下问题:

我有一个班级Foo,其中包含IBar个列表。由于它是一个接口,并且可能有许多实现,因此实体框架无法将此属性本身保存到数据库中。为了解决这个问题,我刚刚创建了另一个不同类型的列表属性(BarDatabaseObject),它很容易序列化。我们的想法是IBar的具体实现/实例只是序列化到数据库中的单个字段,而此表中唯一的其他字段是Id

然而,这不起作用。我得到UpdateException

System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details.
---> System.Data.SqlClient.SqlException: Violation of PRIMARY KEY constraint 'PK_dbo.BarDatabaseObject'.
Cannot insert duplicate key in object 'dbo.BarDatabaseObject'.
The duplicate key value is (a3450574-2d93-4c90-bcdf-88779d18068c).

我100%肯定我没有重复的密钥,因为我只在列表中添加了一个IBar对象,之前数据库是空的。

经过一番调查后,我发现实体框架多次调用属性BarsDatabaseObjects。由于我总是使用新对象创建一个新列表(但具有完全相同的值!),实体框架在第一次访问属性时并没有意识到它是同一个对象并假设它必须是一个新的BarDatabaseObject,因此也尝试将其添加到数据库中。

我该如何解决这个问题?这个场景对我来说似乎很简单(甚至不是#34;特别")。

感谢您的帮助。

internal class Program
{
  private static void Main(string[] args)
  {
    var dbContext = ....;
    Foo foo = ...; //initialize it, with all properties
    dbContext.Foos.Add(foo); //exception occurs here!
    dbContext.SaveChanges();
  }
}

public class Foo
{
  public Guid Id { get; set; }

  //cannot be saved by entity framework, because it's an interface
  [NotMapped]
  public List<IBar> Bars { get; set; }

  public virtual List<BarDatabaseObject> BarsDatabaseObjects
  {
    get
    {
      return Bars.Select(c => new BarDatabaseObject
      {
        Id = c.Id,
        ImplementationsAsJson = JsonSerializer.Serialize(c)
      }).ToList();
    }
    set
    {
      Bars = value.Select(c => JsonSerializer.Deserialize<IBar>(c.ImplementationsAsJson))
                  .ToList();
    }
  }

  // many implementations of this interface exists
  public interface IBar
  {
    Guid Id { get; }
  }

  public class BarDatabaseObject
  {
    public Guid Id { get; set; }

    public string ImplementationsAsJson { get; set; }

    public Guid? FooId { get; set; }

    [ForeignKey(nameof(FooId))]
    public virtual Foo Foo { get; set; }
  }

0 个答案:

没有答案