实体框架仅保存新实体的导航属性,而不保存更新

时间:2017-08-04 17:47:55

标签: c# entity-framework entity-framework-6 navigation-properties

我尝试使用Include首先加载导航属性,并确保已加载子项。

对于新项目,我可以添加没有问题的子导航集。对于更新的项目,我试图传入一个全新的集合来覆盖列表,但我读到我需要使用已加载的集合。即使在清除了收藏并添加之后,我也看不到任何反映。

对于我项目中的所有实体,我调用的是一个泛型方法,它包含这些行和一些错误处理逻辑,但不会抛出任何错误:

Save()方法:

context.Set<T>().AddOrUpdate(entities);
context.SaveChanges();

使用:

    var entities = repository.LoadWithIncludes(x =>.Subset1);
    var entity = entities.FirstOrDefault(x => x.ID == id) ?? new Entity{ID = id};

    entity.Subset1.Clear();

    var IDs = GetIDs(id) ?? Array.Empty<int?>();
    foreach (var id in IDs)
       {
           entity.Subset1.Add(new Subset
             {
               ParentId = id,
               Value = part1;
             });
        }

// then I pass the new and updated items into an array and call the Save() method above

LoadWithIncludes方法取自此答案:https://stackoverflow.com/a/18805096/7096114

2 个答案:

答案 0 :(得分:1)

AddOrUpdate方法

在为数据库播种时应该使用此方法。这让我觉得你会有一些不良行为。

让我们开始纠正您更新背景的方式...

public void Edit(Entity entity)
{
    var db = context
        .Include(i => i.Subset1)
        .Where(i => i.ID == id)
        .Single();

    // update entity
    context.Entry(db).CurrentValues.SetValues(entity);

    // delete / clear subset1 from database
    foreach (var dbSubset1 in db.Subset1.ToList())
    {
        if (!entity.Subset1.Any(i => i.ID == dbSubset1.ID))
            context.Subset1.Remove(dbSubset1);
    }

    foreach (var newSubset1 in entity.Subset1)
    {
        var dbSubset1 = db.Subset1.SingleOrDefault(i => i.ID == newSubset1.Id);
        if (dbSubset1 != null)
            // update Subset1
            context.Entry(dbSubset1).CurrentValues.SetValues(newSubset1);
        else
            db.Subset1.Add(newSubset1);
    }

    // save
    db.SaveChanges();
}

有一篇很棒的文章介绍了如何以更清晰的方式完成这项工作,其中包括创建一个方法来处理Microsoft Docs here中的导航属性(看看大约3/4的方式)下面的文章为例子)。

这也是文档的引用。

  

对于大多数关系,可以通过更新外键字段或导航属性来完成。对于多对多关系,实体框架不会直接公开连接表,因此您可以在相应的导航属性中添加和删除实体。

答案 1 :(得分:0)

从书中: 编程实体框架-DbContext

让你的实体实现IObjectWithState

public interface IObjectWithState
{
    ObjectState ObjectState { get; set; }
}


public enum ObjectState
{
    Unchanged,
    Added,
    Modified
    Deleted
}

人是一个失去联系的实体。

当您更改,删除,添加...设置正确状态:

Person.Name = "Foo";
Person.ObjectState = ObjectState.Modified;

Phone toBeDeleted = myObject.Phones.FirstOrDefault(x => x.Number == "555");
if(toBeDeleted!=null)
    toBeDeleted.ObjectState = ObjectState.Deleted;

Phone toBModified = myObject.Phones.FirstOrDefault(x => x.Number == "444");
if(toBModified!=null)
{
    toBModified.Number = "333";
    toBeDeleted.ObjectState = ObjectState.Modified;
}


ApplyChanges(myObject);

private void ApplyChanges<TEntity>(TEntity root) where TEntity : class, IObjectWithState
{
    using (var context = new MyContext(connectionString))
    {
        context.Set<TEntity>().Add(root);

        CheckForEntitiesWithoutStateInterface(context);

        foreach (var entry in context.ChangeTracker.Entries<IObjectWithState>())
        {
            IObjectWithState stateInfo = entry.Entity;
            entry.State = ConvertState(stateInfo.ObjectState);
        }
        context.SaveChanges();
    }
}

private System.Data.Entity.EntityState ConvertState(ObjectState state)
{
    switch (state)
    {
        case ObjectState.Added:
            return System.Data.Entity.EntityState.Added;
        case ObjectState.Modified:
            return System.Data.Entity.EntityState.Modified;
        case ObjectState.Deleted:
            return System.Data.Entity.EntityState.Deleted;
        default:
            return System.Data.Entity.EntityState.Unchanged;
    }
}

private void CheckForEntitiesWithoutStateInterface(MyContext context)
{
    var entitiesWithoutState = context.ChangeTracker.Entries().Where(x => !(x.Entity is IObjectWithState));
    if (entitiesWithoutState.Any())
    {
        throw new NotSupportedException("All entities must implement IObjectWithState");
    }
}