12

你可能会觉得这是作业,对此我很抱歉。我已经搜索但找不到正确的答案。

所以我的问题是:

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

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 创建为类是一种好习惯吗?(或者它应该是一个接口)

我发现了一些关于使用工厂方法的 DA 层的文章,但据我所知,这种模式不适合我的情况。

4

5 回答 5

14

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

为简单起见,您可以只使用存储库模式。我通常这样定义它:

public interface IEntity<T> { }

//  Define a generic repository interface
public interface IRepository<TKey, TEntity>
    where TEntity : IEntity<TKey>
{
    void Add(TEntity entity);
    void AddRange(IEnumerable<TEntity> entities);
    IEntity<TKey> Get(TKey key);
    IEnumerable<TEntity> GetRange(IEnumerable<TKey> keys);
    IEnumerable<TEntity> GetAll();
    //  ..., Update, Delete methods
}

//  Create an abstract class that will encapsulate the generic code
public abstract class Repository<TKey, TEntity> : IRepository<TKey, TEntity>
    where TEntity : IEntity<TKey>
{
    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<TKey> 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<string> {/* Properties */}

//  Create a specific repository for each table
//  If the table have a composed key, just create a class representing it
public class CarRepository : Repository<string, Car>
{
    public CarRepository() {/* pass the base parameters */}

    // offer here your specific operations to this table entity
    public IEnumerable<Car> GetByOwner(PersonKey ownerKey)
    {
        //  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,因为它可能会非常复杂,特别是尝试开发最通用的解决方案。

于 2012-12-06T19:11:33.997 回答
5

首先,我想向您推荐Jeremy Miller 的文章 Design Patterns for Data Persistence

有一些数据访问层模式:

  1. 活动记录模式wiki详细信息)。
  2. 存储库模式详细信息)。
于 2012-12-06T17:30:22.033 回答
4

我建议使用 ORM、实体框架或 NHibernate 会做得很好。然后您不必担心数据库上下文或创建 SQL 语句。

于 2012-12-06T17:26:23.207 回答
2

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

这是一篇关于它的好文章:

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

于 2012-12-06T17:49:37.333 回答
2

它太旧了,但刚刚解决了这个问题,无法抗拒发表我的想法。

我发现带有一些下降 ORM 的 UnitOfWork 存储库是一个好方法这可以最大限度地减少大多数问题。

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

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

通用存储库被认为是一种反模式;互联网上有很多文章对此进行了解释。

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

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

我建议您阅读这些(1、2、3、4、5 文章解释为什么通用存储库是一种反模式。

解决方案:

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

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

于 2018-02-07T13:55:17.250 回答