2016-02-12 61 views
5

我利用我的ASP.NET应用程序此刻的MVC模式(使用实体框架)的方式ASP.NET MVC的指导方针如下:静态类数据库访问

1)我Models文件夹包含所有的EF实体,以及我的ViewModels

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

我经常遇到意见的类型,使得“不使用静态类,静态类是邪恶的,等等” 。这是否适用于这种情况?如果是,为什么?有没有更好的“结构”我的应用程序应遵循的最佳实践和避免这种陷阱?

+0

只要它有意义*,静态类没有任何问题。这个课程是否需要一个实例?它是否需要延长课程或延长课程?但总的来说,随着需求的变化,对自己的手腕没有任何意义。 –

+1

你见过[这个SO问题](http://stackoverflow.com/questions/21413726/why-would-i-use-static-methods-for-database-access) – markpsmith

回答

7

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

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

UPDATE

助手

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容器注入的一切。代码完全取决于你最终选择哪个容器,所以我不能真正帮助你。不过,这通常很简单。只需阅读容器的文档。您需要将对象的生命周期范围设置为请求。再次,不同的容器是不同的,但它们都会有某种请求范围。

+0

谢谢,你能展示一个虚拟的例子这个?这有时让我感到困惑,我记得我在MSDN博客上看到了一些例子,这些博客是我基于我的方法。 – globetrotter

+0

查看上面的更新。 –

+1

此外,FWIW,您不需要异步并等待您的个人帮手方法,除非他们正在等待一个以上的呼叫。只需返回'Task '并在控制器中等待。这是一个小的优化,但它消除了一层开销。 –

1

我正在考虑给ChrisPratt的回答添加评论,但结果太长了,所以让我添加单独的答案。

基本上,这不是一个生/死的选择。当然,静态方法不如用于数据库访问的类灵活。但是他们不坏本身。每个请求一个DbContext是一个东西旨在。这不是绝对必要的。它是kinda like dependency injection - 您获得更多的灵活性,从而增加代码的复杂性。

看看这三个问题进行解答,以考虑到他们所说的一切事件,我敢肯定,你就可以自己回答你的问题:

编辑:克里斯在我的答案留下了很好的评论,我已经改变了答案一点,以考虑到他说的话。

+1

为了安全起见,每个请求的一个上下文是过分简化的。实际上,每个离散操作只需要一个上下文,但由于通常请求涉及一组离散操作,因此生成请求范围更简单。然而,说这只是一个“建议”而已。创建一个方法范围的上下文,就像OP所做的* will *会在各种情况下导致异常。如果你试图用这种方式关联两个对象,或者尝试延迟加载关系,* BOOM * - 你的应用程序爆炸。 –

+0

好吧,这样做 - 你应该针对每一组行动的背景,而不是混淆 - 我同意。令我担心的是,其中一个DbContext用于不同的操作集 - 最终生成多个db.SaveChanges()的代码,或者一个SaveChanges具有意外结果,因为DbContext与其他一些对象纠缠在一起。无论如何,我会编辑我的答案,指出您的评论,谢谢你离开它。 – kape123

+0

那里没有问题。使用相同的上下文执行多个事务没有任何不利之处,尽管为不同事务创建上下文在技术上并不是错误的,但除了向堆中添加另一个对象和创建它的CPU时间之外,它没有其他用途。也许,最好说明,虽然每个请求并不仅仅需要一个上下文,但以任何其他方式做它都没有意义。 –

0

你的想法是正确的,我总是使用它。但是风格是这样的: 1)对于每个实体(即User),我们在Providers文件夹内有一个静态类。这节课,我们可以做的一般方法(即创造,获取,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)我们有另一个类,是不是static.It是内部模型文件夹中。这是我们可以访问到实体的实例的地方:

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

}

0

我使用已在上下文中注入一个静态构造函数加载数据的高速缓存的目的的静态类这很少改变。它(应该)是线程安全的。我希望这可以帮助你,在我的经验中非常方便:

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