2017-06-06 42 views
2

我有一个EF核心分贝以下型号和一对多的关系EF核心添加相关实体(通用库)

public class AttributeType 
{ 
    public int AttributeTypeId { get; set; } 
    public string Name { get; set; } 

    public List<Attribute> AttributeList { get; set; } 
} 

public class Attribute 
{ 
    public int AttributeId { get; set; } 
    public string Name { get; set; } 

    public int AttributeTypeId { get; set; } 
    public AttributeType AttributeType { get; set; } 
} 

如果我会尝试以这种方式它的工作添加属性:

using (var db = new SampleDbContext()) 
      { 
       var attributeType = db.AttributeTypes.FirstOrDefault(); 

       Attribute attribute = new Attribute 
       { 
        Name = "bbb", 
        AttributeTypeId = attributeType.AttributeTypeId, 
        AttributeType = attributeType 
       }; 
       var item = db.Attributes.Add(attribute); 
       db.SaveChanges(); 
      } 

(在真实的属性类型将来自于组合框和文本框的名字,但现在让我们绝对保持代码的简洁)

,但是当我尝试使用一个通用的方法,如下列 在Microsoft.EntityFrameworkCore.dll DbService插入异常 'Microsoft.EntityFrameworkCore.DbUpdateException':代码,不工作

 AttributeType attributeType; 

       using (var db = new SampleDbContext()) 
       { 
        attributeType = db.AttributeTypes.FirstOrDefault(); 
       } 

       Attribute attribute = new Attribute 
       { 
        Name = "eee", 
        AttributeType = attributeType, 
        AttributeTypeId = attributeType.AttributeTypeId 
       }; 

       DbService.Insert(attribute); 

public static bool Insert<T>(T item) where T : class 
     { 
      try 
      { 
       using (var db = new SampleDbContext()) 
       { 
        db.Add(item); 
        db.SaveChanges(); 
       } 
       return true; 
      } 
      catch (Exception exception) 
      { 
       Debug.WriteLine($"DbService Insert Exception: {exception}"); 
       return false; 
      } 

,我得到以下异常

抛出异常Microsoft.EntityFrameworkCore。 DbUpdateException:更新条目时发生错误。详情请参阅内部例外。 ---> Microsoft.Data.Sqlite.SqliteException:SQLite错误19:'UNIQUE约束失败:AttributeTypes.AttributeTypeId'。 Microsoft.Data.Sqlite.Interop.MarshalEx.ThrowExceptionForRC(Int32 rc,Sqlite3Handle db) at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior) at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection连接,字符串executeMethod,IReadOnlyDictionary 2 parameterValues, Boolean closeConnection) at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary 2的parameterValues) 在Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(在Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute IRelationalConnection连接) ---内部异常堆栈跟踪的结尾--- ( IRelationalConnection连接) at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(Tuple 2 parameters) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList 1 entriesToSave) 在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(布尔acceptAllChangesOnSuccess) 在Microsoft.EntityFrameworkCore.DbContext.SaveChanges(布尔acceptAllChangesOnSuccess) 在UwpSamples.Services.DbService.Insert [T](T项)

但如果我没有通过属性类型或我将它设置为null,如下面的代码,它的工作原理:

AttributeType attributeType; 

     using (var db = new SampleDbContext()) 
     { 
      attributeType = db.AttributeTypes.FirstOrDefault(); 
     } 

     Attribute attribute = new Attribute 
     { 
      Name = "ddd", 
      AttributeType = null, 
      AttributeTypeId = attributeType.AttributeTypeId 
     }; 

     DbService.Insert(attribute); 

-

AttributeType attributeType; 

     using (var db = new SampleDbContext()) 
     { 
      attributeType = db.AttributeTypes.FirstOrDefault(); 
     } 

     Attribute attribute = new Attribute 
     { 
      Name = "ddd", 
      AttributeTypeId = attributeType.AttributeTypeId 
     }; 

     DbService.Insert(attribute); 

谢谢

+1

我很困惑 - 您问题中的最后两个代码块与您的失败代码块完全相同,但您说它在这些情况下有效? –

+1

我认为这与EF无法解决项目应该去的事实有关。我建议将你的'List <>'类型改为'ICollection <>'并将该属性设为'virtual'。这将允许EF使用它的'HashSet <>'类型作为'ICollection <>'的实现,然后它可以跟踪子元素的'父'Id。然而,这可能已经在EF核心中发生了变化... –

+1

简单地不要在EF中使用通用存储库 - 它不适合包含相关实体(简单或集合)的实体。例如'Add'方法将尝试添加实体**和**所有相关数据。 –

回答

2

您正在实例化两个单独的上下文。一个检索AttributeType的地方,执行插入的存储库中的第二个上下文将遍历实体,并且认为AttributeType是新的,并尝试插入它。我建议每个请求使用单个上下文(假定这是在Web请求后面)。有一些解决方法会涉及将实体标记为未更改,但您必须每次都重复该解决方法,并且它对每个模型都非常具体。

通常,您可以使用Container或IoC框架为每个请求检索Context,或者您将在存储库的构造器中传递上下文。通过这种方式,您可以跨不同的存储库进行多次呼叫,并且更改跟踪将在呼叫之间起作用。它还简化了跨越对不同存储库的调用打开交易范围的场景。

1

根据失败,attributeType.AttributeTypeId的值已经存在于数据库中。你能检查这个值是什么,如果它确实是唯一的? 我想这个值必须是唯一的,因为你使用它作为主键。

如果您没有设置值或显式将其设置为空,则ID由数据库自动生成,这说明了它的工作原理。

希望它有帮助。