数据访问层的设计模式

你可能觉得这是家庭作业,因为我很抱歉。 我搜索过但找不到合适的答案。

所以我的问题是:

我有几个类,每个类都有一个保存方法。 所以我为数据库处理创建了一个单独的类。

namespace HospitalMgt.Data { public static class DBConnection { public static string constr = "Data Source=ABD;Initial Catalog=HospitalMgt;User Id=sa;Password=123"; public static SqlConnection con; // public static SqlCommand com; public static SqlConnection OpenConnection() { con= new SqlConnection(constr); con.Open(); return con; } } } 

但是,我不认为使用DBConnection类实现所有类是合适的。

我的问题 :

  1. 什么设计模式适合克服这个问题?
  2. 将DBConnection创建为类是一种好习惯吗? (或者它应该是一个接口)

我使用Factory方法找到了一些关于DA图层的文章,但据我所知,这种模式不适合我的情况。

通常,如果我不能使用任何现有框架,我使用Repository和Active模式。

为简单起见,您只能使用Repository模式。 我通常将它定义为:

 // Define a generic repository interface public interface IRepository where E:IEntity>{ void Add(E entity); void AddRange(IEnumerable entities); IEntity Get(Key key); IEnumerable GetRange(IEnumerable keys); IEnumerable GetAll(); // ..., Update, Delete methods } // Create an abstract class that will encapsulate the generic code public abstract class Repository where E:IEntity>:IRepository{ protected Repository(/*parameter you may need to implement the generic methods, like a ConnectionFactory, table name, entity type for casts, etc */){} public override void Insert(IEntity entity){ // do the insert, treat exceptions accordingly and encapsulate them in your own and more concise Exceptions, etc } // ... } // Create the entities classes, one for each table, that will represent a row of that table public class Car: IEntity{/* Properties */} // Create a specific repository for each table // If the table have a composed key, just create a class representing it public CarRepository: Repository{ public CarRepository(){/* pass the base parameters */} // offer here your specific operations to this table entity public IEnumerable GetByOwner(PersonKey ownerKey){ // do stuff } } 

您现在有足够的工具来操作数据库,但如果需要,您可以使用活动模式。 一个简单的例子:

 public class Person:IEntity{ public PersonKey Key{get;} public IEnumerable OwnedCars{ get{ CarRepository rep = DBSingletons.Cars; return rep.GetByOwner(this.Key); } set{ // do stuff } } } 

显然,在进行自己的实现时,必须考虑线程安全,以便更好地使用事务,特别是跨不同的实体存储库。

 // simple example ITransaction t = TransactionFactory.GetNewTransaction(); t.begin(); try{ // create person entity personRepository.Add(person, t); // create cars assigned to person carRepository.AddRange(cars, t); t.commit(); }catch(Exception){ t.rollback(); } 

只要确保你真的想要创建自己的DAL,因为它可能会变得非常复杂,特别是试图开发最通用的解决方案。

我建议使用ORM,entity framework或NHibernate会做得很好。 然后,您不必担心db上下文或创建SQL语句。

首先,我想向您推荐Jeremy Miller撰写的“数据持久性设计模式 ”一文。

有一些数据访问层模式:

  1. 活动记录模式 ( 维基 , 详细信息 )。
  2. 存储库模式 ( 详细信息 )。

我建议您使用RepositoryBase进行所有这些常见操作。 如果您决定使用ORM进行数据访问,最好在基于Generic Type存储库的存储库实现中进行思考。

这是一篇很好的文章:

http://lostechies.com/jimmybogard/2009/09/03/ddd-repository-implementation-patterns/

它太旧了,但只是绕过这个问题,无法抗拒发表我的想法。

我发现使用UnitOfWork的 Repository有一些下降ORM是很好的方法。 这最大限度地减少了大多数问题。

上面提到的UoW可以在Repository中注入。 这增加了使用的灵活性。 此外,所有数据库通信代码都集中在一个地方。 该示例不完整,但是启动点。

上面链接中提到的存储库模式实际上是一个通用基类。 您可以为从中派生的每个具体存储库创建新类。

通用存储库被认为是反模式; 互联网上有很多文章可以解释它。

为什么通用存储库是反模式的?

  1. 存储库是正在建模的域的一部分,并且该域不是通用的。
    • 并非每个实体都可以删除。
    • 并非每个实体都可以添加
    • 并非每个实体都有一个存储库。
    • 查询变化很大; 存储库API变得与实体本身一样唯一。
    • 对于GetById() ,标识符类型可能不同。
    • 无法更新特定字段(DML)。
  2. 通用查询机制是ORM的责任。
    • 大多数ORM暴露出与Generic Repository非常相似的实现。
    • 存储库应该使用ORM公开的通用查询机制来实现实体的SPECIFIC查询。
  3. 无法使用复合键。
  4. 无论如何,它泄漏了服务中的DAL逻辑。
    • 如果您接受参数,则需要从服务层提供谓词条件。 如果这是特定于ORM的类,则会将ORM泄漏到服务中。

我建议你阅读这些( 1,2,3,4,5 )文章解释为什么通用存储库是一个anit-pattern。

解:

  1. 编写一个由具体存储库包装的抽象通用存储库。 这样您就可以控制公共接口,但仍然具有来自通用存储库的代码重用的优势。
  2. 使用通用存储库但使用组合而不是inheritance,并且不要将其作为合同公开给域。

在任何情况下,都不要将Generic Repository暴露给调用代码。 另外,不要将IQueryable从具体的存储库中公开。