6

我有一个使用 Entity Framework 5 的 MVC 应用程序。在少数地方我有一个创建或更新实体的代码,然后必须对更新的数据执行某种操作。其中一些操作需要访问导航属性,我无法让它们刷新。

这是示例(我拥有的简化代码)

楷模

class User : Model
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

class Car : Model
{
    public Guid Id { get; set; }
    public Guid DriverId { get; set; }
    public virtual User Driver { get; set; }

    [NotMapped]
    public string DriverName
    {
        get { return this.Driver.Name; }
    }
}

控制器

public CarController
{
    public Create()
    {
       return this.View();
    }

    [HttpPost]
    public Create(Car car)
    {
        if (this.ModelState.IsValid)
        {
            this.Context.Cars.Create(booking);
            this.Context.SaveChanges();

            // here I need to access some of the resolved nav properties
            var test = booking.DriverName;
        }

        // error handling (I'm removing it in the example as it's not important)
    }
}

上面的示例是针对 Create 方法的,但我也有与 Update 方法相同的问题,它非常相似,它只是从上下文中获取对象并使用方法来GET存储它。UpdatePOST

public virtual void Create(TObject obj)
{
    return this.DbSet.Add(obj);
}

public virtual void Update(TObject obj)
{
    var currentEntry = this.DbSet.Find(obj.Id);
    this.Context.Entry(currentEntry).CurrentValues.SetValues(obj);
    currentEntry.LastModifiedDate = DateTime.Now;
}

现在,我尝试了几种不同的方法,这些方法在 Google 上搜索或在堆栈上找到,但似乎没有什么对我有用。

在我最近的尝试中,我尝试在调用SaveChanges方法并重新查询数据库中的数据后强制重新加载。这就是我所做的。

我已经覆盖了SaveChanges保存后立即刷新对象上下文的方法

public int SaveChanges()
{
    var rowsNumber = this.Context.SaveChanges();
    var objectContext = ((IObjectContextAdapter)this.Context).ObjectContext;
    objectContext.Refresh(RefreshMode.StoreWins, this.Context.Bookings);

    return rowsNumber;
}

我尝试通过在SaveChanges调用我的HTTP CreateUpdate操作后立即添加这行代码来获取更新的对象数据:

car = this.Context.Cars.Find(car.Id);

不幸的是,导航属性仍然​​是null. 如何在修改数据后立即正确刷新 DbContext?

编辑

我忘了最初提到我知道一种解决方法,但它很难看,我不喜欢它。每当我使用导航属性时,我都可以检查它是否存在null,如果是,我可以手动创建新的 DbContext 并更新数据。但我真的很想避免这样的黑客攻击。

class Car : Model
{    
    [NotMapped]
    public string DriverName
    {
        get
        {
            if (this.Driver == null)
            {
                using (var context = new DbContext())
                {
                    this.Driver = this.context.Users.Find(this.DriverId);
                }
            }

            return this.Driver.Name;
         }
    }
}
4

2 回答 2

4

问题可能是由于您添加到上下文中的项目没有包含proxy延迟加载的所有必要组件。即使在调用SaveChanges()该项目后也不会转换为代理实例。

我建议您尝试使用 DbSet.Create() 方法并复制您通过网络接收到的实体中的所有值:

public virtual TObject Create(TObject obj)
{
    var newEntry = this.DbSet.Create();
    this.Context.Entry(newEntry).CurrentValues.SetValues(obj);
    return newEntry;
}

更新

如果SetValues()出现问题,那么我建议您尝试使用automapper将数据从传入的实体传输到创建的代理,然后再将Add新的代理实例传输到DbSet. 像这样的东西:

private bool mapCreated = false;
public virtual TObject Create(TObject obj)
{
    var newEntry = this.DbSet.Create();

    if (!mapCreated)
    {
        Mapper.CreateMap(obj.GetType(), newEntry.GetType());
        mapCreated = true;
    }
    newEntry = Mapper.Map(obj, newEntry);

    this.DbSet.Add(newEntry;
    return newEntry;
}
于 2013-07-05T11:09:19.983 回答
0

我使用下一个解决方法:分离实体并再次加载

public T Reload<T>(T entity) where T : class, IEntityId
{
    ((IObjectContextAdapter)_dbContext).ObjectContext.Detach(entity);
    return _dbContext.Set<T>().FirstOrDefault(x => x.Id == entity.Id);
}
于 2015-03-21T04:20:01.923 回答