我的上下文用于两个控制器(AdminController
,它们可以查看和添加一些数据,HomeController
只能查看数据。
我可以让我的上下文类只是我的控制器类中的字段吗?或者我应该把它变成单身?或者我应该创建一个额外的单例类,它在我的网站中存储所有DbContext
类?该如何正确完成?
答案 0 :(得分:3)
我相信ASP.NET MVC的最佳方式是每个请求使用1个DbContext。您将受益于此方法,因为:
当然你可以使用IoC容器,但我不喜欢开销,因为你可以自己轻松编写所有必要的逻辑。
所以我们需要DbContext
的包装器。它会将您的EF上下文保留在HttpContext项中。在ASP.NET MVC应用程序中,您可以将初始化放在基本控制器中:
public class DbContextHelper : IDbContextHelper // interface for testing if you need it
{
private const string contextKey = "MyContext";
public MyContext GetContext()
{
if (HttpContext.Current.Items[contextKey] == null)
{
HttpContext.Current.Items.Add(contextKey, new MyContext());
}
return (MyContext) HttpContext.Current.Items[contextKey];
}
public void DisposeContext()
{
if (HttpContext.Current.Items[contextKey] != null)
{
var context = (MyContext) HttpContext.Current.Items[contextKey];
context.Dispose();
}
}
}
现在要完成设置,我们需要将DisposeContext
调用注入End_Request事件。这取决于您使用的ASP.NET版本。通常我会创建一个处理上下文的ActionFilter。并在全球注册。
public class DisposeDbContextFilterAttribute : ActionFilterAttribute
{
private static readonly DbContextHelper contextHelper = new DbContextHelper();
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
contextHelper.DisposeContext();
}
}
现在,当所有设置完成后,只需享受使用它:
var user = contextHelper.GetContext().Users.Find(userId);
答案 1 :(得分:1)
这是一个很好的架构问题,这是一个很好的资源,你可以查看:
就个人而言,我倾向于允许您的IoC容器管理为您创建连接并将它们注入您的控制器。或者,如果您使用存储库或类似的体系结构,则可以将上下文直接注入到这些类中,并将存储库注入控制器。
如果对于您的应用程序而言过于复杂,则使用示例链接中的任何其他方法都不会出现严重的性能问题。实体将利用连接池,因此没有那么多的开销。
我不希望我的上下文成为单例,因为我希望每个Web请求都包含自己的上下文对象。这有很多原因,如果你继续跟踪,其中最重要的是性能。单例上下文也可能为奇怪的事务问题敞开大门 - 请记住,Web是一个多线程环境。
请记住,没有正确或错误的答案,因为您提出的是架构问题而不是一个架构适用于每个应用程序。如果您的解决方案易于理解,易于维护并采用最佳实践,那么您就可以做得很好。
希望这些信息有所帮助,祝你好运!
答案 2 :(得分:0)
我可以让我的上下文类只是我的控制器类中的字段吗?
不确定。您可以在控制器中创建一个私有字段来保留db上下文类的实例。
你不需要单身。来到您的AdminController和HomeController的请求是2个不同的HTTP请求,它应该创建&为每个http请求使用DbContext类的新对象..
public class AdminController
{
private YourDbContext db;
public AdminController()
{
db = new YourDbContext();
}
public ActionResult Users()
{
var list=db.Users.ToList();
//use list as needed now
}
}
使用这种方法,只有问题是,即使您请求的动作方法没有使用任何数据,也会创建YourDbContext的对象。
如果需要,您可以创建一个YourBaseController并在那里创建DbContext对象初始化,并且两个控制器都可以从中继承。
public class MyBaseController : Controller
{
protected YourDbContext db;
public MyBaseController ()
{
db = new YourDbContext();
}
}
public class AdminController : MyBaseController
{
}
由于你没有从内存中处理DbContext对象,我们将依赖点网垃圾收集器。
但是如果你愿意,你可以创建一个DbContext类的对象,使用它并在使用后通过使用using
关键字
public ActionResult View()
{
var name= new List<string>();
using(var db=new YourDbContext())
{
name=db.Users.Select(s=>s.Name);
}
//to do : return something
}
使用表达式,框架将在它退出using { }
此外,查看dependency injection可能是一个好主意,这样您就不会手动使用new
关键字创建对象,但框架会为您注入这些对象。这将有助于您使代码更适合单元测试。