EF Core添加相关实体(通用存储库)

时间:2017-06-06 16:35:00

标签: c# uwp entity-framework-core

我有一个具有以下模型和一对多关系的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;
            }

我得到以下异常

  

抛出异常:&#39; Microsoft.EntityFrameworkCore.DbUpdateException&#39;在Microsoft.EntityFrameworkCore.dll中   DbService插入异常:Microsoft.EntityFrameworkCore.DbUpdateException:更新条目时发生错误。有关详细信息,请参阅内部异常---&GT; Microsoft.Data.Sqlite.SqliteException:SQLite错误19:&#39; UNIQUE约束失败:AttributeTypes.AttributeTypeId&#39;。   在Microsoft.Data.Sqlite.Interop.MarshalEx.ThrowExceptionForRC(Int32 rc,Sqlite3Handle db)   在Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior行为)   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection,String executeMethod,IReadOnlyDictionary 2 parameterValues, Boolean closeConnection) at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary 2 parameterValues)   在Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection连接)   ---内部异常堆栈跟踪结束---   在Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection连接)   在Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(元组2 parameters) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList 1 entriesToSave)   在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)   在Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)   在UwpSamples.Services.DbService.Insert [T](T item)

但是如果我没有传递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);

由于

2 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

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

当您未设置值或明确将其设置为null时,数据库会自动生成ID,这解释了它的工作原理。

希望它有所帮助。