MVC 3/EF存储库模式和正确的数据访问

S9D*_*gns 1 sql asp.net-mvc repository disconnected-environment

作为MVC 3和EF的新手,我正在努力了解为我的公司开发应用程序的最佳架构方法.该应用程序将是一个大型应用程序,可能同时处理数百个用户,所以我想确保我理解并遵循正确的程序.到目前为止,我已经确定一个简单的存储库模式(例如Controller - > Repository - > EF)方法是最好和最容易实现的,但我不确定这是否是最好的做事方式.应用程序基本上会返回在devexpress网格中向用户显示的数据,并且可以修改此数据/添加到其中等.

我发现这篇文章,这对我来说相当混乱,所以我想知道是否有任何理由尝试使用断开连接的EF以及为什么你甚至想要这样做:http://www.codeproject .COM /用品/ 81543 /最后的实体框架-工作-在-全disconne?味精= 3717432#xx3717432xx

总结一下我的问题:

  • 代码是否可以接受?
  • 它应该适用于大规模的MVC应用吗?
  • 有没有更好的办法?
  • 与EF的不必要的SQL连接是否仍然打开?(即使在using语句退出后,SQL事件探查器也会让它保持打开状态)
  • 断开连接的框架理念是否更好?为什么你甚至想要这样做?我不相信我们需要跨层级跟踪数据......

注意:存储库实现IDisposable并具有下面列出的dispose方法.它在存储库构造函数中创建实体上下文的新实例.

用法示例:

控制器(使用自定义成员资格提供程序登录):

if (MembershipService.ValidateUser(model.UserName, model.Password))
{
    User newUser = new User();                    

    using (AccountRepository repo = new AccountRepository())
    {
         newUser = repo.GetUser(model.UserName);
         ...
    }
}
Run Code Online (Sandbox Code Playgroud)

成员资格提供者ValidateUser:

public override bool ValidateUser(string username, string password)
{
    using (AccountRepository repo = new AccountRepository())
    {
        try
        {
            if (string.IsNullOrEmpty(password.Trim()) || string.IsNullOrEmpty(username.Trim()))
                return false;

            string hash = FormsAuthentication.HashPasswordForStoringInConfigFile(password.Trim(), "md5");

            bool exists = false;

            exists = repo.UserExists(username, hash);

            return exists;
        }catch{
            return false;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

GetUser和UserExists的帐户存储库方法:

获取用户:

public User GetUser(string userName)
    {
        try
        {
            return entities.Users.SingleOrDefault(user => user.UserName == userName);
        }
        catch (Exception Ex)
        {
            throw new Exception("An error occurred: " + Ex.Message);
        }           
    }
Run Code Online (Sandbox Code Playgroud)

用户存在:

 public bool UserExists(string userName, string userPassword)
 {
        if (userName == "" || userPassword == "")
            throw new ArgumentException(InvalidUsernamePassword);

        try
        {
            bool exists = (entities.Users.SingleOrDefault(u => u.UserName == userName && u.Password == userPassword) != null);
            return exists;
        }
        catch (Exception Ex)
        {
            throw new Exception("An error occurred: " + Ex.Message);
        } 
    }
Run Code Online (Sandbox Code Playgroud)

Repository Snippets(构造函数,Dispose等):

    public class AccountRepository : IDisposable
    {
         private DbContext entities;

         public AccountRepository()
         {
            entities = new DbContext();
         }

         ...

         public void Dispose()
         {
            entities.Dispose();
         }
    }
Run Code Online (Sandbox Code Playgroud)

Kal*_*exx 5

什么是可接受的是非常主观的,但如果你想进行正确的数据访问,我建议你不要使用存储库模式,因为它会因为你的应用程序变得更复杂而崩溃.

最大的原因是最小化数据库访问.例如,查看您的存储库并注意该GetUser()方法.现在从代码中退一步,考虑一下如何使用您的应用程序.现在考虑一下您在没有任何其他数据的情况下从用户表中请求数据的频率.除非您正在创建基本数据输入应用程序,否则答案几乎总是"很少".

你说它你的应用程序会显示很多网格.该网格中有哪些数据?我假设(不知道您的应用程序域)网格将用户数据与其他与该用户相关的信息组合在一起.如果是这种情况,您如何使用您的存储库?

一种方法是单独调用每个存储库的方法,如下所示:

var user = userRepository.GetUser("KallDrexx");
var companies = companyRepository.GetCompaniesForUser(user.Id);
Run Code Online (Sandbox Code Playgroud)

现在这意味着你有2个数据库调用,它们应该只是一个.随着屏幕变得越来越复杂,这将导致数据库命中数量增加和增加,如果您的应用程序获得大量流量,则会导致性能问题.在存储库模式中执行此操作的唯一方法是向存储库添加特殊方法以执行特定查询,例如:

public class UserRepository
{
    public User GetUser(string userName)
    {
        // GetUser code          
    }

    public User GetUserWithCompanies(string userName)
    {
        // query code here
    }
}
Run Code Online (Sandbox Code Playgroud)

那么现在如果您需要用户并在一个查询中说出他们的联系人数据会发生什么.现在,您必须向用户存储库添加另一个方法.现在假设您需要执行另一个查询,该查询还返回每个公司拥有的客户端数量,因此您需要添加另一个方法(或添加可选参数).现在假设您要添加一个返回所有公司及其包含的用户的查询.现在你需要一个新的查询方法,但接下来的问题是你把它放在User存储库或Company存储库中?你如何跟踪它是哪一个,GetUserWithCompanyGetCompanyWithUsers在以后需要时和之后选择它?

从那时起,一切都变得非常复杂,而那些使我放弃了存储库模式的情况.我现在做的数据访问是我创建单独的查询和命令类,每个类代表1(并且只有1)查询或数据更新命令到数据库.每个查询类都返回一个视图模型,该模型仅包含一个特定用户使用场景所需的数据.还有其他数据访问模式也可以工作(规范模式,一些优秀的开发人员甚至说你应该只在控制器中进行数据访问,因为EF 你的数据访问层).

成功进行数据访问的关键是良好的规划.你知道你的屏幕会是什么样子吗?你知道用户将如何使用你的系统吗?您是否知道每个屏幕上实际存在的所有数据?如果对这些问题的答案都是肯定的,那么你需要退后一步,忘掉数据层,因为数据层是(或应该是一个好的应用程序),根据应用程序的实际情况确定使用时,UI和屏幕不应该取决于数据层的设计方式.如果在开发数据访问时没有考虑UI需求和用户使用场景,那么您的应用程序将无法很好地扩展并且不会具有高性能.如果你没有计划在你的网站上做大事,那么有时候这不是问题,但是记住这些事情永远不会伤害.