【问题标题】:Refresh repository after run stored procedure运行存储过程后刷新存储库
【发布时间】:2015-12-11 15:36:33
【问题描述】:

我的 WebAPI 项目中有以下操作,它运行存储过程来更新(和其他一些操作)People 表:

public HttpResponseMessage SetAsMain(int id)
{
    People people = repository.GetById(id);

    if (people == null)
    {
        return ErrorMsg(HttpStatusCode.NotFound, string.Format("No people with ID = {1}", id));
    }

    if (people.IsMain)
    {
        return ReturnMsg(HttpStatusCode.OK, string.Format("{0} is already set as main", people.FullName)); 
    }

    try
    {
        var parameters = new Dictionary<string, string>();
        parameters.Add("PeopleID", id.ToString());                

        repository.ExecProcedure("usp_PeopleSetMain", parameters);
        return Request.CreateResponse(HttpStatusCode.OK, repository.GetById(id)); 
    }
    catch (Exception ex)
    {
        return ErrorMsg(HttpStatusCode.InternalServerError, ex.Message);
    }
}

我在存储过程更新后检索数据时遇到问题。在这个地方:

return Request.CreateResponse(HttpStatusCode.OK, repository.GetById(id));

我得到了与更新前相同的数据。但是当我再次调用这个方法时,就会有一个实际的数据。

如何刷新存储库中的数据?

你能告诉我为什么repository.GetById(id)ExecProcedure 之后从不获取新数据吗? 如果我需要添加更多信息,请告诉我

更新
我的存储库中的方法 GetById:

public T GetById(object id)
{
   return context.Set<T>().Find(id);
}

【问题讨论】:

  • Find 如果实体已存在于上下文中,则立即返回该实体,而无需转到数据存储。您可以重置上下文或分离实体,然后再次执行Find,如果不知道您的存储库如何工作,很难说什么是最好的。
  • 感谢@Crowcoder。我不知道Find。如何分离实体?
  • 您可以将 Find 替换为 FirstOrDefault/SingleOrDefault 这将执行 SQL
  • @MegaTron ObjectContext 有一个 Detach 方法,但它可能更适合 ieaglle 的建议。
  • 还有DbExtensions.AsNoTracking 方法很有用。

标签: c# .net asp.net-mvc entity-framework asp.net-web-api


【解决方案1】:

这是因为实体框架上下文已经包含您的对象。方法Find(id) 始终检查对象是否存在于上下文中,如果存在,实体框架将不会查询数据库。存储过程不会更改上下文对象,因为它们直接针对数据库执行,这就是您在实体中看不到更新值的原因。

您可以通过以下方式之一解决此问题:

  1. 在上下文中停止实体跟踪
  2. 使用AsNoTracking()查询实体而不进行跟踪。
  3. 执行存储过程后使用First(...)FirstOrDefault(...)Single(...)等查询对象。

我建议您使用选项 1 或 2。选项 1:

context.Entry(people).State = EntityState.Detached;

如果你运行早期版本的实体框架,你应该分离对象:

context.People.Detach(people);

(感谢 ieaglle)您还可以查询您的实体立即关闭跟踪(选项 2):

context.People.AsNoTracking().FirstOrDefault(p => p.Id == id);

【讨论】:

  • AsNoTracking IMO 更好,因为它首先不会将实体附加到上下文。在您的示例中,yourEntity 将附加在您的行之前。
  • 非常感谢您的帮助
【解决方案2】:

DbSet.Find 的行为方式如下:

如果上下文中存在具有给定主键值的实体,则立即返回它而不向存储区发出请求。否则,将向存储请求具有给定主键值的实体,如果找到该实体,则将其附加到上下文并返回。如果在上下文或存储中没有找到实体,则返回 null。

所以Find 不会查询数据库以获取新更新的实体,它只会获取缓存的旧实体。

要解决此功能,您有几个选择:

  • 通过使用.FirstOrDefault.SingleOrDefault 或任何其他触发查询执行的方法,显式强制 EF 查询数据库中的新实体;
  • 首先不要使用 DbExtensions.AsNoTracking 将实体附加到上下文。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-13
    • 2015-02-01
    • 1970-01-01
    • 2016-04-04
    • 2018-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多