ASP.NET 用于数据库访问的静态类的 MVC 指南
本文关键字:静态类 指南 MVC 访问 NET 用于 数据库 ASP | 更新日期: 2023-09-27 18:34:26
我在 ASP.NET 应用程序中使用MVC模式的方式(使用实体框架(如下:
1( 我的 Models
文件夹包含所有 EF 实体,以及我的视图模型
2(我有一个Helpers
文件夹,用于存储为特定应用程序目的创建的类。
3(在我的Helpers
文件夹中,我有一个名为MyHelper
的静态类,其中包含使用EF访问数据库的方法。
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( 然后,我的控制器在必要时调用这些函数:
namespace myApp.Controllers
{
public class ProductController : Controller
{
[HttpGet]
public async Task<ActionResult> Index(int productId)
{
var productVM = await MyHelper.GetProductAsync(productId);
return View(productVM);
}
}
}
我通常在 SO 中遇到"不要使用静态类,静态类是邪恶的等"类型的评论。这是否适用于这种情况?如果是,为什么?我的应用是否应该遵循更好的"结构"来获得最佳实践并避免此类陷阱?
您实际上不能为此使用静态类。实体框架上下文的每个请求应有一个且只有一个实例。您在此处的方法为每个方法实例化一个新的上下文,这将导致实体框架出现大量问题。
一般概念很好,但MyHelper
类应该是普通类。 添加一个采用上下文实例的构造函数,然后使用 DI 容器将上下文注入帮助程序类,并将帮助程序类注入控制器。
更新
助手
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();
}
}
}
控制器
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 容器来注入所有内容。该代码完全取决于您最终使用的容器,因此我无法进一步帮助您。不过,这通常非常简单。只需阅读容器的文档。您需要将对象的生存期范围设置为请求。同样,对于不同的容器,情况有所不同,但它们都有某种请求范围。
我想在克里斯普拉特的答案中添加注释,但结果太长了,所以让我添加单独的答案。
基本上,这不是生死抉择。当然,静态方法不如数据库访问类灵活。但它们本身并不坏。每个请求一个 DbContext 是一个目标。这不是绝对必须的。这有点像依赖注入 - 您可以获得更大的灵活性,从而增加代码复杂性。
看看这三个问题和他们的答案,考虑到他们所说的一切,我相信你自己就能回答你的问题:
- 为什么要使用静态方法进行数据库访问
- 何时在 C# 中使用静态类
- 每个 Web 请求一个 DbContext...为什么?
编辑:克里斯对我的回答留下了很好的评论,我已经改变了答案,以考虑到他说的话。
你的想法是正确的,我总是使用它。但风格是这样的:1(对于每个实体(即用户(,我们在提供者文件夹中都有一个静态类。在此类中,我们可以执行一般方法(即创建,获取,GetAll,..(
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(我们有另一个非静态的类。它位于"模型"文件夹中。这是我们可以访问实体实例的地方:
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)
{
...
}
...
}
我使用一个静态类,该类将上下文注入到静态构造函数中,目的是加载很少更改的数据缓存。它(应该(是线程安全的。我希望这对您有所帮助,根据我的经验,这非常方便:
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");
}