[英]Design pattern for Data Access Layer
You might feel this is homework, for that I am sorry. 您可能会觉得这是家庭作业,对不起。 I have searched but couldn't find a proper answer. 我已经搜索过,但是找不到正确的答案。
So my question is: 所以我的问题是:
I have several classes and each class has a method to save. 我有几个类,每个类都有一个保存方法。 So I created a separate class for database handling. 因此,我为数据库处理创建了一个单独的类。
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;
}
}
}
However, I don't think it's suitable to implement all the classes with a DBConnection class. 但是,我认为用DBConnection类实现所有类并不适合。
My question : 我的问题 :
I found a few articles about DA layers using the Factory method, but according to my knowledge, that pattern does not suit my situation. 我使用Factory方法发现了一些有关DA层的文章,但是据我所知,这种模式不适合我的情况。
Normally, if I can't use any existing framework, I use both the Repository and Active patterns. 通常,如果我不能使用任何现有框架,那么我会同时使用存储库和活动模式。
For simplicity, you could use only the Repository pattern. 为简单起见,您只能使用存储库模式。 I normally define it like this: 我通常这样定义:
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
}
}
Obviously, when doing your own implementations, you must take into account thread safety making good using of transactions, specially across diferent entity repositories. 显然,在执行自己的实现时,必须考虑到线程安全性,尤其是在不同的实体存储库之间,要善加使用事务。
// 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();
}
Just be sure that you really want to create your own DAL since it can end beeing extremelly complex, specially trying to develop the most generic solution. 只需确保您确实要创建自己的DAL,因为它可能会变得极其复杂,特别是尝试开发最通用的解决方案。
I suggest using an ORM, Entity Framework or NHibernate will do nicely. 我建议使用ORM,Entity Framework或NHibernate会很好。 Then you do not have to worry about a db context or create SQL statements. 然后,您不必担心数据库上下文或创建SQL语句。
First of all, I would like to recommend you the article Design Patterns for Data Persistence by Jeremy Miller . 首先,我想向您推荐Jeremy Miller的文章Data Persistence的设计模式 。
There are some data access layer patterns: 有一些数据访问层模式:
I suggest you to use a RepositoryBase for all this common operations. 我建议您对所有这些常用操作使用RepositoryBase。 If you decide to use an ORM for data access it's good to think in a implementation of repositories based on a Generic Type repository. 如果您决定使用ORM进行数据访问,最好考虑基于通用类型存储库的存储库实现。
Here is a good article about it: 这是一篇很好的文章:
http://lostechies.com/jimmybogard/2009/09/03/ddd-repository-implementation-patterns/ http://lostechies.com/jimmybogard/2009/09/03/ddd-repository-implementation-patterns/
Its too old but just came around this question and could not resist to post my thoughts. 它太旧了,但是只是围绕这个问题而已,无法抗拒发表我的想法。
I found Repository with UnitOfWork with some descent ORM is good approach. 我发现带有UnitOfWork的 仓库以及一些下降的ORM是很好的方法。 This minimizes most of the issues. 这样可以最大程度地减少大多数问题。
The UoW mentioned in above link can be injected in Repository. 可以将以上链接中提到的UoW注入存储库中。 That increases the flexibility of usage. 这增加了使用的灵活性。 Also, all DB Communication code is centralized at one place. 同样,所有DB Communication代码都集中在一个地方。 The example is not complete but a startup point. 该示例不是完整的,而是一个启动点。
Repository pattern mentioned in above link is actually a generic base class. 上面链接中提到的存储库模式实际上是一个通用基类。 You can create new class for each of your concrete Repository that derives from it. 您可以为每个派生自其的具体存储库创建新类。
Generic repository is considered an anti pattern; 通用存储库被视为反模式; there are lot many articles on internet that explains it. 互联网上有很多文章对此进行了解释。
Why generic repository is anti-pattern? 为什么通用存储库是反模式的?
GetById()
, identifier types may be different. 对于GetById()
,标识符类型可能不同。 I suggest you read these ( 1 , 2 , 3 , 4 , 5 ) articles explaining why generic repository is an anit-pattern. 我建议你阅读这些( 1 , 2 , 3 , 4 , 5 )的文章解释了为什么通用存储库是一个ANIT模式。
Solution: 解:
In any case, do not expose Generic Repository to calling code. 无论如何,请勿将通用存储库暴露给调用代码。 Also, do not expose IQueryable
from concrete repositories. 另外,请勿从具体存储库中公开IQueryable
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.