【问题标题】:Implement data access layer best practices in .net Project MVC在 .net Project MVC 中实现数据访问层最佳实践
【发布时间】:2017-02-26 22:33:48
【问题描述】:

我想通过在访问数据库时添加另一层来改进我的 .NET 项目。这是我的代码:

namespace Company.Models
{
public static class AgencyBean
{
[WebMethod]
    [ScriptMethod(UseHttpGet = true)]
    public static String createGUID(string name)
    {
       DataAccess dataAccess = new DataAccess();
       bool exists = dataAccess.checkIfExists(Id);
       if(exist)
       {
           dataAccess.delete(Id);
       }
       retur "ok";
    }
 }
}

我将 DataAccess 类放在一个名为“Helpers”的单独文件夹中,其中包含我的大部分查询:

public class DataAccess
 {    
public bool checkIfExists(String Id)
    {
        try
        {
            SqlConnection cnn = new SqlConnection(dataConnection);
            cnn.Open();
            SqlCommand check_Id = new SqlCommand("SELECT COUNT(*) FROM TABLE_GUID WHERE ([USER_ID] = @Id)", cnn);
            check_Id.Parameters.AddWithValue("@Id", Id);
            int UserExist = (int)check_Id.ExecuteScalar();

            if (UserExist > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        catch (SqlException ex)
        {
            Debug.WriteLine("SQL Exception " + ex);
            DisplaySqlErrors(ex);
            throw ex;
        }
    }
 }

public class AgentBeanController : Controller
{
    // GET: AgentBean
    public ActionResult Index(string name)
    {
        return View();
    }

    [AllowAnonymous]
    [WebMethod]              
    public string AgentURL()  //here we create Agent URL and return it to the view
    {
        string var = Models.AgentBean.createGUID("TODO");            
        return var;           
    }


}

我以非常直接的方式访问数据库。使用更好的技术会如何,因此这种访问可以更安全,例如通过服务层访问? 我正在连接到某个服务器中的现有 sql 数据库,并在我的项目中使用 MVC 架构。

【问题讨论】:

  • 你在正确的轨道上。如果您在 Google 上搜索“数据存储库”和“依赖注入”一词,可能会更进一步。存储库的一般概念是,您在模型层中有单独的类来访问数据(就像您现在所做的那样),但它们符合接口。当您实例化您的 AgencyBean 类时,您将接受一个实现该接口的对象作为参数。好处是您可以拥有不接触仅用于单元测试的数据库的接口的第二个实现。像 Ninject 这样的 DI 工具使这更容易编码。
  • 现在我理解得更好了,我也想实现单元测试,我发现我需要 DI。感谢您的建议!

标签: c# mysql asp.net-mvc dao


【解决方案1】:

这就是我过去所做的。

首先,这是您的“模型”命名空间...模型永远不应该具有数据库连接性。相反,您有一个单独的类,例如控制器,它可以为某些模型提供水合。

其次,我有一个“服务”类,它连接到一个“存储库”类。存储库类实现了一个接口来识别您正在使用的数据库的确切“类型”。但如果这不是您的要求的一部分,您可能不需要走那么远。

第三,查找依赖注入(又名 DI)。那里有几个框架。我个人使用过 Autofac,但也有其他工具可以更轻松地完成工作。

第四,在您的“控制器”、“服务”和“存储库”类上,实现依赖注入,以及形成合约所需的任何接口。

第五,我将使用一个实际的控制器命名空间,而不是使用你的模型命名空间来推送 http 调用带......相反,在你的控制器类中创建一个动作,并实例化你的“ agentBean”,用数据对其进行水合,然后将该模型返回到您的视图中。

基本上,在这样的场景中,您会尝试让每个组件都按照指定的方式执行...将职责分解为更小的部分并专注于此。您的控制器应该只“获取”您的模型,并可能根据需要或任何其他业务类型逻辑对其进行一些转换。
您的服务应该处理您的控制器和数据库层之间的通信。
您的数据访问层(即,在这种情况下,一些“存储库”类...)将完成所有这些新数据连接和/或设置对存储过程或查询的调用。

以这种方式做事有很多好处。其中一些重要的是可维护性、可读性、代码重用。当然,就文件放在任何地方而言,这会使您的项目变得更加复杂……但这可能是一件好事。这比把所有东西都塞进一个班级然后让它做所有事情要好得多:)

但是,仅供参考,这是我过去完成的一个实现...我确信有更好的方法,但这种设置对我和我的团队来说效果很好。

这是一个使用您发布的一些代码的小示例。我没有检查这个是否有错别字,它不会编译,但应该有助于大致了解我在说什么......

namespace Company.Models
{
    public class AgencyBean
    {
        public AgencyName{get;set;}
        public AgencyId{get;set;}
        // other properties...
    }
}




namespace Company.Controllers
{
    public class MyController : Controller
    {
        private readonly IMyService myService;


        public MyController(IMyService myService) // <-- this is your dependency injection here...
        {
            this.myService = myService; 
        }

        [WebMethod]
        [ScriptMethod(UseHttpGet = true)]
        public static String createGUID(string name)
        {
            var model = new AgencyBean();
            model.AgencyId = 1;
            model = myService.getAgency(agencyBean);            
            return model;
        }
    }
}




namespace Company.Services
{
    public class MyService
    {
        private readonly IMyRepository myRepository;


        public MyService(IMyRepository myRepository) // <-- this is your dependency injection here...
        {
            this.myRepository = myRepository; 
        }

        public AgencyBean getAgency(AgencyBean model){
            var dataTable = myRepository.getAgencyData(model.AgencyId);
            // fill other properties of your model you have...
            // ...
            // ...
            return model;
        }
    }
}



namespace Company.Repositories
{
    public class MyRepository : IDatabaseCommon  // <-- some interface you would use to ensure that all repo type objects get connection strings or run other necessary database-like setup methods...
    { 
        private readonly String connectionString{get;set;}

        public MyRepository()
        {
            this.connectionString = //get your connection string from web.config or somewhere else...; 
        }

        public DataTable getAgencyData(int id){
            var dataTable = new DataTable();

            // perform data access and fill up a data table

            return dataTable;
        }
    }
}

【讨论】:

  • 我在某处读到我的业务逻辑应该在模型中,并且控制器应该尽可能简单,这就是我开始以这种方式编码的原因。然后我发现了一个类似的帖子,人们建议有一个你指出我的服务层。因此,在您的示例中,IMyservice 是位于包含我的查询的新文件中的接口,对吗?我只是有点困惑在哪里可以找到某些文件,因为我不想“破坏”这个 MVC 模式......
  • IMyService 是您在另一个文件中创建的接口是的。但这不是你写查询的地方,什么不是。如果你想写一堆 SQL 命令,我推荐另一个“模型”类,比如“QueryModel”,它会是一堆返回你的 sql 字符串的常量。但实际上,我个人不会那样做。相反,我在数据库级别使用存储过程/函数,并从应用程序代码中调用它们。 db 存储的过程/函数将包含您的所有 SQL。
  • 现在我不明白你的意思,我将模型作为参数发送,使用带有 DI 的 myRepository 将其填充到 MyService 中,然后返回模型。还有一个问题,我从 Nugget 安装了 Unity DI,但出现无参数错误,我应该手动添加一些东西到我的 Application_Start() 还是应该由安装程序添加?
  • 通常对于那些 DI 框架,你需要为你的项目添加一个新的引用......至少我知道你是为 Autofac 做的。我从未亲自使用过 Unity DI,但我确信他们有某种“入门”指南。我相信这是微软提供的“内置”di 框架。这是使用 Unity 的一个很好的演练。 geekswithblogs.net/danielggarcia/archive/2014/01/23/…
猜你喜欢
  • 2011-02-21
  • 1970-01-01
  • 1970-01-01
  • 2010-09-05
  • 1970-01-01
  • 2011-06-29
  • 1970-01-01
  • 1970-01-01
  • 2015-09-10
相关资源
最近更新 更多