【问题标题】:EF Core Add a Related Entity (generic repository)EF Core 添加相关实体(通用存储库)
【发布时间】:2017-11-07 18:55:22
【问题描述】:

我有一个具有以下模型和一对多关系的 EF Core Db

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();
            }

(实际上,attributeType 将来自组合框,名称来自文本框,但现在让我们保持代码简单)

但是当我尝试使用通用方法时,如以下代码,不起作用

     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.dll 中的“Microsoft.EntityFrameworkCore.DbUpdateException” DbService 插入异常:Microsoft.EntityFrameworkCore.DbUpdateException:更新条目时出错。有关详细信息,请参阅内部异常。 ---> Microsoft.Data.Sqlite.SqliteException:SQLite 错误 19:“唯一约束失败:AttributeTypes.AttributeTypeId”。 在 Microsoft.Data.Sqlite.Interop.MarshalEx.ThrowExceptionForRC(Int32 rc,Sqlite3Handle db) 在 Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior 行为) 在 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection 连接,字符串 executeMethod,IReadOnlyDictionary2 parameterValues, Boolean closeConnection) at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary2 参数值) 在 Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection 连接) --- 内部异常堆栈跟踪结束 --- 在 Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection 连接) 在 Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(Tuple2 parameters) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList1 entriesToSave) 在 Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(布尔型 acceptAllChangesOnSuccess) 在 Microsoft.EntityFrameworkCore.DbContext.SaveChanges(布尔型 acceptAllChangesOnSuccess) 在 UwpSamples.Services.DbService.Insert[T](T 项)

但是如果我没有传递 AttributeType 或者我将它设置为 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);

谢谢

【问题讨论】:

  • 我很困惑 - 您问题中的最后两个代码块与您失败的代码块完全相同,但您说它在这些情况下有效?
  • 我认为这与 EF 无法确定项目应该去哪里的事实有关。我建议将您的List&lt;&gt; 类型更改为ICollection&lt;&gt; 并将该属性设为virtual。这将允许 EF 使用其 HashSet&lt;&gt; 类型作为 ICollection&lt;&gt; 的实现,然后它可以跟踪子元素的“父”ID。但是,这可能在 EF 核心中发生了变化...
  • 不要将通用存储库与 EF 一起使用 - 它不适合包含相关实体(简单或集合)的实体。例如Add 方法将尝试添加实体和所有相关数据。
  • @RobertPetz 对不起,你是对的,该死的副本和过去,已修复。谢谢!
  • @MichaelCoxon 有意思,我试试,谢谢

标签: c# uwp entity-framework-core


【解决方案1】:

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

通常,您要么使用容器或 IoC 框架来检索每个请求的上下文,要么在存储库的构造函数中传递上下文。这样,您可以跨不同的存储库进行多次调用,并且更改跟踪将在调用之间起作用。它还简化了在对不同存储库的调用中打开事务范围的场景。

【讨论】:

    【解决方案2】:

    根据失败,attributeType.AttributeTypeId的值已经存在于DB中。你能检查一下这个值是多少,它是否确实是唯一的? 我猜这个值必须是唯一的,因为您将它用作主键。

    当您不设置值或将其显式设置为 null 时,ID 由 DB 自动生成,这解释了它的工作原理。

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-12
      • 2011-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多