关于c#:用于数据库访问的静态类的ASP.NET MVC指南

ASP.NET MVC guidelines for static classes for database access

我目前在ASP.NET应用程序(使用实体框架)中使用MVC模式的方式如下:

1)我的Models文件夹包含所有ef实体以及我的视图模型。

2)我有一个Helpers文件夹,用于存储为特定应用程序而创建的类。

3)在我的Helpers文件夹中,有一个名为MyHelper的静态类,其中包含使用ef访问db的方法。

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);
        }
    }
}

我通常会遇到这样的评论类型"不要使用静态类,静态类是邪恶的,等等"。这在这种情况下适用吗?如果是,为什么?有没有更好的"结构"我的应用程序应该遵循最佳实践和避免这样的陷阱?


对于这个,您不能真正使用静态类。每个请求实体框架上下文应该只有一个实例。这里的方法为每个方法实例化一个新的上下文,这将导致实体框架出现大量问题。

一般的概念是好的,但是你的MyHelper类应该是普通类。添加一个获取上下文实例的构造函数,然后使用DI容器将上下文注入helper类,并将helper类注入控制器。

更新

帮手

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)
    {
        ...
    }
    ...

}