SaveChanges之后未更新属性(EF数据库优先)

时间:2015-05-29 08:10:25

标签: c# entity-framework

首先,我想说我已阅读相关帖子(特别是EF 4.1 SaveChanges not updating navigation or reference propertiesEntity Framework Code First - Why can't I update complex properties this way?Entity Framework 4.1 RC (Code First) - Entity not updating over association)。

然而,我无法解决我的问题。我对Entity Framework很新,所以我想我一定是误解了这些帖子的答案。 无论如何,如果有人能帮我理解,我会非常感激,因为我很困惑。

我有两张桌子:

  • Person
  • Item,可以为PersonIdType

项目可以拥有所有者。 因此,Person具有Items属性,该属性是Item的IEnumerable。

一个人只能按类型Item。 如果该人想要改变,他可以用他的物品中任何其他相同类型的物品替换他当前的物品:

public class MyService
{
    private PersonRepo personRepo = new PersonRepo();
    private ItemRepo itemRepo = new ItemRepo();

    public void SwitchItems(Person person, Guid newItemId)
    {
        using (var uof = new UnitOfWork())
        {
            // Get the entities
            Item newItem = itemRepo.Get(newItemId);
            Item oldItem = person.Items.SingleOrDefault(i => i.Type == newItem.Type)

            // Update the values
            newItem.PersonId = person.Id;
            oldItem.PersonId = null;

            // Add or update entities
            itemRepo.AddOrUpdate(oldItem);
            itemRepo.AddOrUpdate(newItem);
            personRepo.AddOrUpdate(person);

            uof.Commit(); // only does a SaveChanges()
        }
    }
}

这是存储库结构和AddOrUpdate方法:

public class PersonRepo : RepositoryBase<Person>
{
    ...
}

public class RepositoryBase<TObject> where TObject : class, IEntity
{
    protected MyEntities entities
    {
        get { return UnitOfWork.Current.Context; }
    }

    public virtual void AddOrUpdate(TObject entity)
    {
        if (entity != null)
        {
            var entry = entities.Entry<IEntity>(entity);

            if (Exists(entity.Id))
            {
                if (entry.State == EntityState.Detached)
                {
                    var set = entities.Set<TObject>();
                    var currentEntry = set.Find(entity.Id);
                    if (currentEntry != null)
                    {
                        var attachedEntry = entities.Entry(currentEntry);
                        attachedEntry.CurrentValues.SetValues(entity);
                    }
                    else
                    {
                        set.Attach(entity);
                        entry.State = EntityState.Modified;
                    }
                }
                else
                    entry.State = EntityState.Modified;
            }
            else
            {
                entry.State = EntityState.Added;
            }
        }
    }
}

这非常有效,旧项目和新项目PersonId属性在数据库中正确更新。 但是,如果我在person.Items之后检查SaveChanges(),旧项目仍然会显示而不是新项目,我需要它才能更正页面的控件值。

虽然我看了同样问题的帖子但我无法解决它... 我尝试了很多东西,特别是调用entities.Entry(person).Collection(p => p.Items).Load()但每次尝试时都有例外。

如果有人有任何想法请随意,我可以根据需要添加更多代码。

非常感谢!

编辑:UnitOfWork

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.Entity.Infrastructure;
using System.Data.Objects;

public class UnitOfWork : IDisposable
{
    private const string _httpContextKey = "_unitOfWork";
    private MyEntities _dbContext;

    public static UnitOfWork Current
    {
        get { return (UnitOfWork)HttpContext.Current.Items[_httpContextKey]; }
    }

    public UnitOfWork()
    {
        HttpContext.Current.Items[_httpContextKey] = this;
    }

    public MyEntities Context
    {
        get
        {
            if (_dbContext == null)
                _dbContext = new MyEntities();

            return _dbContext;
        }
    }

    public void Commit()
    {
        _dbContext.SaveChanges();
    }

    public void Dispose()
    {
        if (_dbContext != null)
            _dbContext.Dispose();
    }
}

两个有效的解决方案

解决方案1(在SaveChanges之后从上下文重新加载)

public partial class MyPage
{
    private MyService service;
    private Person person;

    protected void Page_Load(object sender, EventArgs e)
    {
        service = new MyService();
        person = service.GetCurrentPerson(Request.QueryString["id"]);
        ...
    }

    protected void SelectNewItem(object sender, EventArgs e)
    {
        Guid itemId = Guid.Parse(((Button)sender).Attributes["id"]);

        service.SelectNewItem(person, itemId);

        UpdatePage();
    }

    private void UpdatePage()
    {
        if (person != null)
            person = service.GetCurrentPerson(Request.QueryString["id"]);

        // Update controls values using person's properties here
    }
}

public class MyService
{
    private PersonRepo personRepo = new PersonRepo();
    private ItemRepo itemRepo = new ItemRepo();

    public void SwitchItems(Person person, Guid newItemId)
    {
        using (var uof = new UnitOfWork())
        {
            // Get the entities
            Item newItem = itemRepo.Get(newItemId);
            Item oldItem = person.Items.SingleOrDefault(i => i.Type == newItem.Type)

            // Update the values
            newItem.PersonId = person.Id;
            oldItem.PersonId = null;

            // Add or update entities
            itemRepo.AddOrUpdate(oldItem);
            itemRepo.AddOrUpdate(newItem);
            personRepo.AddOrUpdate(person);

            uof.Commit(); // only does a SaveChanges()
        }
    }
}

解决方案2(更新数据库和属性)

public partial class MyPage
{
    private MyService service;
    private Person person;

    protected void Page_Load(object sender, EventArgs e)
    {
        service = new MyService();
        person = service.GetCurrentPerson(Request.QueryString["id"]);
        ...
    }

    protected void SelectNewItem(object sender, EventArgs e)
    {
        Guid itemId = Guid.Parse(((Button)sender).Attributes["id"]);

        service.SelectNewItem(person, itemId);

        UpdatePage();
    }

    private void UpdatePage()
    {
        // Update controls values using person's properties here
    }
}

public class MyService
{
    private PersonRepo personRepo = new PersonRepo();
    private ItemRepo itemRepo = new ItemRepo();

    public void SwitchItems(Person person, Guid newItemId)
    {
        using (var uof = new UnitOfWork())
        {
            // Get the entities
            Item newItem = itemRepo.Get(newItemId);
            Item oldItem = person.Items.SingleOrDefault(i => i.Type == newItem.Type)

            // Update the values
            newItem.PersonId = person.Id;
            oldItem.PersonId = null;
            person.Items.Remove(oldItem);
            person.Items.Add(newItem);

            // Add or update entities
            itemRepo.AddOrUpdate(oldItem);
            itemRepo.AddOrUpdate(newItem);
            personRepo.AddOrUpdate(person);

            uof.Commit(); // only does a SaveChanges()
        }
    }
}

2 个答案:

答案 0 :(得分:4)

如何刷新上下文以确保在public T Example2(object obj1, object obj2) 方法之后获得最新的数据库更改。在上下文中传递要刷新的实体.SaveChanges()

Refresh

或保留((IObjectContextAdapter)_dbContext).ObjectContext.Refresh(RefreshMode.StoreWins, entityPassed); 方法,并采用更动态的方法:

Commit()

var changedEntities = (from item in context.ObjectStateManager.GetObjectStateEntries( EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged) where item.EntityKey != null select item.Entity); context.Refresh(RefreshMode.StoreWins, changedEntities); 只表示数据库(存储)具有优先级,并将覆盖客户端(内存中)更改。

如果Refresh方法不起作用,您可以考虑以下事项:

RefreshMode.StoreWins

或者,如果所有其他方法都失败了,那么在完成每个事务后(在这种情况下,在public void RefreshEntity(T entity) { _dbContext.Entry<T>(entity).Reload(); } 被调用之后),请保持简单并使用Dispose DbContext。然后,如果您需要在提交后使用结果,请将其视为新事务,并实例化新的DbContext并再次加载必要的数据。

答案 1 :(得分:0)

以Transection为例。 它工作正常。

 public class UnitOfWork : IUnitOfWork
 {

    public readonly DatabaseContext _context;
    private readonly IDbTransaction _transaction;
    private readonly ObjectContext _objectContext;

      public UnitOfWork(DatabaseContext context)
      {
        _context = context as DatabaseContext ?? new DatabaseContext ();
        this._objectContext = ((IObjectContextAdapter)this._context).ObjectContext;
        if (this._objectContext.Connection.State != ConnectionState.Open)
        {
            this._objectContext.Connection.Open();
            this._transaction = _objectContext.Connection.BeginTransaction();
        }
      }             

    public int Complete()
    {
        int result = 0;
        try
        {
            result = _context.SaveChanges();
            this._transaction.Commit();
        }
        catch (Exception ex)
        {
            Rollback();
        }
        return result;
    }
    private void Rollback()
    {
        this._transaction.Rollback();

        foreach (var entry in this._context.ChangeTracker.Entries())
        {
            switch (entry.State)
            {
                case System.Data.Entity.EntityState.Modified:
                    entry.State = System.Data.Entity.EntityState.Unchanged;
                    break;
                case System.Data.Entity.EntityState.Added:
                    entry.State = System.Data.Entity.EntityState.Detached;
                    break;
                case System.Data.Entity.EntityState.Deleted:
                    entry.State = System.Data.Entity.EntityState.Unchanged;
                    break;
            }
        }
    }
    public void Dispose()
    {
        if (this._objectContext.Connection.State == ConnectionState.Open)
        {
            this._objectContext.Connection.Close();
        }
        _context.Dispose();
    }
}