如何适当地设计数据访问层?

Posted

技术标签:

【中文标题】如何适当地设计数据访问层?【英文标题】:How do I design a Data Access Layer appropriately? 【发布时间】:2011-06-04 19:49:43 【问题描述】:

我有以下数据访问层 (DAL)。我想知道它是否设置正确,或者我是否需要改进它?

public class User 




//Persistence methods
static class UserDataAccess

   UsersDAL udal = // Choose SQL or FileSystem DAL impl.


   InsertUser(User u)
   
      // Custom logic , is 'u' valid etc. 

      udal.Insert(u);
   


abstract class UsersDAL
    
   GetUserByID();
   InsertUser(u);
   ...


// implementaitons of DAL

static class UsersSQLStore : UsersDAL




static class UsersFileSystemStore : UsersDAL



我将存储层从 User 类中分离出来,以访问进一步调用任何自定义 DAL 的方法集合。

在 DAL 实现中使用 static 是否正确?

请提出更正或改进的方法。我没有很多分层编写代码的经验。

【问题讨论】:

如果您不能花时间完整地说明您的问题(使用 Pl. 而不是 Please),那么您如何期望有人花时间回答您的问题或帮助您? @George,我不知道这是否会伤害到某人,但为了避免人们阅读过多,我经常使用它。相反,我专注于写下我的例子。这并不意味着我不欣赏人们的时间和他们的反应。 为什么要这样做而不是使用像 LLBLGen 或 Dapper 这样的 ORM?无需重新发明***。 【参考方案1】:

Davy Brion 有一组关于这个主题的优秀博文:located on GitHub

【讨论】:

您包含的链接现已损坏。请更新它。【参考方案2】:

我的拙见

    如果用户没有任何层次结构,则使用接口而不是抽象类。 编写一个通用 DAL,以便您可以将其重用为 DAL 层的外观。 通过 DI 框架解析具体的 DAL

【讨论】:

【参考方案3】:

这些类都不应该是static。我认为你也不应该将你的类命名为DAL,因为它是数据访问层的缩写,而一个类本身并不是一个层(至少在我看来)。您可以改用广泛采用的术语repository。我建议您执行以下操作:

public class User



public abstract class UserRepository
    public abstract void InsertUser(User user);


public class SqlUserRepository : UserRepository
    public override void InsertUser(User user)
    
      //Do it
    


public class FileSystemUserRepository : UserRepository
    public override void InsertUser(User user)
    
      //Do it
    


public class UserService
    private readonly UserRepository userRepository;

    public UserService(UserRepository userRepository)
        this.userRepository = userRepository;
    

    public void InsertUser(User user)
        if(user == null) throw new ArgumentNullException("user");
        //other checks
        this.userRepository.InsertUser(user);
    

注意UserService 在其构造函数中注入了抽象类UserRepository 的实例。您可以使用Dependency Injection (DI) 框架自动为您执行此操作,例如来自Castle Project 的Windsor Castle。它将允许您在配置文件或代码中指定从抽象(UserRepository)到具体实现(例如SqlUserRepository)的映射。

希望这能为您指明正确的方向,如果您需要更多信息,请询问。

【讨论】:

这就是模板模式。正如 Hoffmann 和 Jani 所建议的那样,您的方向是正确的 很好的解释。为什么我应该使用静态?如果不是存储库,对于 UserService,我猜我可以将其设为静态吗?还有 1 件事(可能与 DAL 无关):如果尝试插入现有用户,那么谁应该通过构造函数进行检查、UserService 或 User 类本身(因为它在新的时候不知道存在性) @Munish Goyal,你不应该使用static,因为没有必要。如果使用不当,static 会在您的应用程序中引入不必要的状态,这使得调试变得更加困难,最重要的是,它非常难以自动测试。您可能想在这里阅读static 的确切含义:msdn.microsoft.com/en-us/library/98f28cdx%28vs.71%29.aspx @Munish Goyal,我认为UserService 应该通过询问存储库是否已经存在具有该 ID/名称的用户来检查用户是否已经存在。为此,您需要在您的存储库中使用一个名为 bool UserAlreadyExists(User user) 的方法。 @Munish Goyal,不,这是不正确的。抽象的 UserRepository、User 类和 UserService 必须在同一个程序集 (AssemblyA) 中。存储库的不同实现可以在它们自己的程序集中(AssemblyB/C)。使用 UserService 的程序需要同时引用 AssemblyA 和 AssemblyB(或 AssemblyC)。

以上是关于如何适当地设计数据访问层?的主要内容,如果未能解决你的问题,请参考以下文章

工单系统的设计与实现

使用 C#、SQL Server 设计数据访问层

DDD中的数据访问层设计

数据访问层应该如何构建?

JDBC的架构设计

Spring Boot - 构建数据访问层