全局变量可以在dbcontext范围中使用

时间:2014-12-10 03:45:39

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

我想在我的dbcontext中覆盖我的覆盖SaveChanges()中的一些数据而不传递任何参数。有什么建议?我正在使用MVC4和Entity Framework Database-First。

public partial class Entities : DbContext
{
    public override int SaveChanges()
    {
        // i want to get user info from MVC model but no need to pass any parameters when call SaveChanges()
        var UserInfo = userInfo;

        // Call the original SaveChanges(), which will save both the changes made and the audit records
        return base.SaveChanges();
    }
}

1 个答案:

答案 0 :(得分:1)

解决方案1:依赖注入

此解决方案具有相当的可扩展性,但您必须修改存储库和控制器中的代码才能使用注入的依赖项,而不是使用new创建新实例。

  1. 安装Ninject。在Visual Studio中,找到程序包管理器控制台并在其中运行Install-Package Ninject.MVC4 -dependencyVersion Highest

  2. 添加构造函数注入。修改控制器,以便在其构造函数中获取存储库的实例。修改您的存储库,以便它在其构造函数中获取实体上下文的实例。在私有字段中缓存依赖项。示例代码:

    // In your controller:
    public MyController(MyRepository repo)
    {
        this.repo = repo;
    }
    
    // In your repository:
    public MyRepository(Entities context)
    {
        this.context = context;
    }
    
    // In your entities:
    public Entities(UserInfo userInfo)
    {
        this.userInfo = userInfo;
    }
    
  3. 添加UserInfo提供程序。我们需要告诉Ninject从哪里获取UserInfo。我们可以在这里使用提供者界面:

    public class UserInfoProvider : Provider<UserInfo>
    {
        protected override UserInfo CreateInstance(IContext context)
        {
            UserInfo UserInfo = new UserInfo();
    
            // Do some complex initialization here.
    
            return userInfo;
        }
    }
    
  4. 添加绑定。我们需要告诉Ninject使用提供程序。我们还希望将UserInfo实例和实体上下文的生命周期绑定到MVC的请求周期。更新App_Start \ NinjectWebCommon.cs:

    private static void RegisterServices(IKernel kernel)
    { 
        kernel.Bind<Entities>()
              .ToSelf()
              .InRequestScope();
    
        kernel.Bind<UserInfo>()
              .ToProvider<UserInfoProvider>()
              .InRequestScope();
    }
    
  5. 运行您的应用。 Ninject应该使用您的构造函数并提供请求的依赖项。

  6. 有关详细信息,请访问Ninject Wiki


    解决方案2:线程本地上下文

    这不需要修改您的存储库,但它使代码不易测试,并且以某种方式类似于反模式。如果您的控制器调用多线程代码,这将无法工作。

    1. 添加上下文类。

      public class UserInfoContext : IDisposable
      {
          private static readonly ThreadLocal<UserInfo> UserInfos = new ThreadLocal<UserInfo>();
      
          public static UserInfo Current
          {
              get 
              {
                  if (UserInfos == null)
                  {
                      throw new InvalidOperationException("UserInfoContext has not been set.");
                  }
      
                  return UserInfos.Value;
              }
          }
      
          public static UserInfoContext Create(UserInfo userInfo)
          {
              if (userInfo == null)
              {
                  throw new ArgumentNullException("userInfo");
              }
      
              if (UserInfos.Value != null)
              {
                  throw new InvalidOperationException("UserInfoContext should not be nested.");
              }
      
              UserInfos.Value = userInfo;
      
              return new UserInfoContext();
          }
      
          private UserInfoContext() { }
      
          public void Dispose()
          {
              UserInfos.Value = null;
          }
      }
      
    2. 包装您的控制器代码。示例:

      public ActionResult Index()
      {
          using (UserInfoContext.Create(myUserInfo))
          {
              // do stuff that calls your repositories
      
              return View();
          }
      }
      
    3. 更新您的实体类。

      public partial class Entities : DbContext
      {
          public override int SaveChanges()
          {
              var UserInfo = UserInfoContext.Current;
      
              // Call the original SaveChanges(), which will save both the changes made and the audit records
              return base.SaveChanges();
          }
      }