ASP.NET MVC guidelines for static classes for database access
我目前在ASP.NET应用程序(使用实体框架)中使用MVC模式的方式如下:
1)我的
2)我有一个
3)在我的
1 2 3 4 5 6 7 8 9 10 11 12 13 | namespace myApp.Helpers { public static class MyHelper { public static async Task<ProductVM> GetProductAsync(int productId) { using (var context = new myEntities()) { return await context.vwxProducts.Where(x => x.ProductId == productId).Select(x => new ProductVM { A = x.A, B = x.B }).FirstOrDefaultAsync(); } } } } |
4)我的控制器在必要时调用这些功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 | namespace myApp.Controllers { public class ProductController : Controller { [HttpGet] public async Task<ActionResult> Index(int productId) { var productVM = await MyHelper.GetProductAsync(productId); return View(productVM); } } } |
我通常会遇到这样的评论类型"不要使用静态类,静态类是邪恶的,等等"。这在这种情况下适用吗?如果是,为什么?有没有更好的"结构"我的应用程序应该遵循最佳实践和避免这样的陷阱?
对于这个,您不能真正使用静态类。每个请求实体框架上下文应该只有一个实例。这里的方法为每个方法实例化一个新的上下文,这将导致实体框架出现大量问题。
一般的概念是好的,但是你的
更新
帮手
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | namespace myApp.Helpers { public class MyHelper { private readonly DbContext context; public MyHelper(DbContext context) { this.context = context; } public async Task<ProductVM> GetProductAsync(int productId) { return await context.vwxProducts.Where(x => x.ProductId == productId).Select(x => new ProductVM { A = x.A, B = x.B }).FirstOrDefaultAsync(); } } } |
控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | namespace myApp.Controllers { public class ProductController : Controller { private readonly MyHelper myHelper; public ProductController(MyHelper myHelper) { this.myHelper = myHelper; } [HttpGet] public async Task<ActionResult> Index(int productId) { var productVM = await myHelper.GetProductAsync(productId); return View(productVM); } } } |
然后,您只需要设置一个DI容器来注入所有内容。它的代码完全取决于您最终要使用哪个容器,所以我不能进一步帮助您。不过,这通常是相当直接的。只需阅读容器的文档即可。您需要将对象的生命周期范围设置为请求。同样,对于不同的容器来说是不同的,但是它们都有某种请求范围。
我本来想在克里斯普拉特的回答中加上评论,但结果太长了,所以让我再加一个单独的答案。
基本上,这不是生死抉择。当然,静态方法不如用于DB访问的类那么灵活。但它们本身并不坏。每个请求一个dbContext是一个目标。这不是绝对必要的。这有点像依赖注入——您获得了更多的灵活性,从而增加了代码的复杂性。
看看这三个问题及其答案,考虑到他们所说的每一句话,我相信你能自己回答你的问题:
- 为什么要使用静态方法访问数据库
- 何时在C中使用静态类#
- 每个Web请求一个dbContext…为什么?
编辑:克里斯对我的回答留下了很好的评价,我已经改变了一些回答,考虑到他说的话。
我使用一个静态类,该类将上下文注入静态构造函数,以便加载很少更改的数据缓存。而且它应该是线程安全的。我希望这对你有帮助,这在我的经验中非常有用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | public static class StaticCache<T> where T: class { private static List<T> dbSet; public static Dictionary<string, List<T>> cache = new Dictionary<string, List<T>>(); private static readonly object Lock = new object(); public static void Load(DbContext db, string connStr, string tableName) { lock (Lock) { try { if (connStr != null) { using (db) { dbSet = db.Set<T>().ToList(); cache.Add(tableName, dbSet); } } } catch { } } } } void Testit() { var context = new YourContextSubClass(connStr); StaticCache<TableEntity>.Load(context, connstr,"tableEntityNameString"); } |
你的想法是正确的,我总是用它。但风格是这样的:1)对于每个实体(即用户),我们在providers文件夹中都有一个静态类。在这个类中,我们可以执行一般的方法(即create、get、getall等)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public static class Users { public static IEnumerable<kernel_Users> GetAll() { Kernel_Context db = new Kernel_Context(); return db.kernel_Users; } public static kernel_Users Get(int userId) { Kernel_Context db = new Kernel_Context(); return db.kernel_Users.Where(c => c.UserId == userId).FirstOrDefault(); } ... } |
2)我们还有一个非静态类,它在models文件夹中。这是我们可以访问实体实例的位置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public partial class kernel_Users { [Key] public int UserId { get; set; } public string Username { get; set; } public string Password { get; set; } [NotMapped] public string FullName { get { return FirstName +"" + LastName; } } public bool Delete(out string msg) { ... } ... |
}