C# 我应该使用泛型来简化DAL吗?
我是NHibernate的新手,C#不是很好,但我正在学习。我有一个C# 我应该使用泛型来简化DAL吗?,c#,nhibernate,C#,Nhibernate,我是NHibernate的新手,C#不是很好,但我正在学习。我有一个DataProvider类,它使用nhibernate3为我的应用程序提供数据。它的结构与 我注意到我要重复很多代码,我想简化我的数据提供程序。例如,我有两个业务类,分别称为Instrument和Broker。在myDataProvider中添加仪器的方法是: public int AddInstrument(Instrument instrument) { using (ITransaction
DataProvider
类,它使用nhibernate3为我的应用程序提供数据。它的结构与
我注意到我要重复很多代码,我想简化我的数据提供程序
。例如,我有两个业务类,分别称为Instrument
和Broker
。在myDataProvider
中添加仪器的方法是:
public int AddInstrument(Instrument instrument)
{
using (ITransaction tx = _session.BeginTransaction())
{
try
{
int newId = (int)_session.Save(instrument);
_session.Flush();
tx.Commit();
return newId;
}
catch (NHibernate.HibernateException)
{
tx.Rollback();
throw;
}
}
}
而AddBroker
类看起来非常相似(只需查找并替换)。所以我想也许我可以用泛型来解决这个问题。比如:
public class DataProvider <TEntity>
{
public int AddEntity(TEntity entity)
{
using (ITransaction tx = _session.BeginTransaction())
{
try
{
int newId = (int)_session.Save(entity);
_session.Flush();
tx.Commit();
return newId;
}
catch (NHibernate.HibernateException)
{
tx.Rollback();
throw;
}
}
}
}
使用泛型,我必须将对象类型传递给我的数据提供者
。你能想出解决这个问题的办法吗?我是一个新手程序员,我想知道我是否走上了正确的道路。我应该做些完全不同的事情吗
更新
我试图实现格罗的答案,但遇到了一些问题。这就是我所做的
IRepo.cs
interface IRepo<T>
{
int Add<Entity>(Entity entity);
void Delete<Entity>(Entity entity);
void GetById<Entity>(int Id);
}
RepoFactory.cs
interface IRepoFactory
{
IInstrumentRepo CreateInstrumentRepo(ISession s);
}
public class RepoFactory : IRepoFactory
{
public IInstrumentRepo CreateInstrumentRepo(ISession s) // problem here
{
return new InstrumentRepo(s);
}
}
IInstrumentRepo.cs
interface IInstrumentRepo : IRepo<Instrument>
{
}
public class InstrumentRepo : BaseRepo<Instrument>, IInstrumentRepo
{
public InstrumentRepo(ISession s) : base(s) { }
}
接口IInstrumentRepo:IRepo
{
}
报告书
interface IInstrumentRepo : IRepo<Instrument>
{
}
public class InstrumentRepo : BaseRepo<Instrument>, IInstrumentRepo
{
public InstrumentRepo(ISession s) : base(s) { }
}
公共类InstrumentRepo:BaseRepo、IInstrumentRepo
{
公共仪器报告(ISession s):基本(s){
}
在RepoFactory.cs中,我遇到以下错误:
可访问性不一致:返回类型“MooDB.Data.iInstrumEnterpo”的可访问性低于方法“MooDB.Data.RepoFactory.CreateInstrumentRepo(NHibernate.ISession)”
你知道我遗漏了什么吗?你的数据提供程序类不一定需要是泛型的-你可以把
AddEntity
方法本身变成泛型的。然后实例化一个DataProvider
实例,并调用(例如)它的AddEntity
方法。您的类将如下所示:
#region Fields
private DataProvider _provider;
private SessionManager _sessionManager;
private NHibernate.ISession _session;
#endregion
[SetUp]
public void Setup()
{
DatabaseSetUp();
_session = _sessionManager.GetSession();
_provider = new DataProvider(_session); // problem here
}
public class DataProvider
{
public int AddEntity<TEntity>(TEntity entity)
{
using (ITransaction tx = _session.BeginTransaction())
{
try
{
int newId = (int)_session.Save(entity);
_session.Flush();
tx.Commit();
return newId;
}
catch (NHibernate.HibernateException)
{
tx.Rollback();
throw;
}
}
}
}
公共类数据提供程序
{
公共整数加法(tenty实体)
{
使用(ITransaction tx=\u session.BeginTransaction())
{
尝试
{
int newId=(int)_session.Save(实体);
_session.Flush();
tx.Commit();
返回newId;
}
捕获(NHibernate.hibernateeexception)
{
tx.回滚();
投掷;
}
}
}
}
您的问题的答案绝对是肯定的!
这就是泛型的含义
你的方法是对的
这一论点实在太长,无法在此讨论,但您可以在本文中找到许多有用的信息:
创建我的通用nhibernate Dao对我有很大帮助。首先,解决您的测试设置问题:术语存储库可能暗示它应该是一个长寿命的持久对象,但是DAL操作中使用的存储库实际上应该是生命周期短的轻量级无状态对象:需要时实例化一个,一旦完成就扔掉。当您考虑到这是性能方面时,您可以很容易地每秒实例化数百万个 结合NHibernate的短命
会话
实例,这就是当一切就绪时代码的外观:
using (var session = SessionManager.OpenSession())
{
// create an instrument repo
IInstrumentRepo instruments = DAL.RepoFactory.CreateInstrumentRepo(session);
var guitar = instruments.Find(i => i.Type == "Guitar");
// create a customer repo
ICustomerRepo customers = DAL.RepoFactory.CreateCustomerRepo(session);
var cust = customers.Find(c => c.Name == "Mark")
// do something -> changes will be persisted by NH when session is disposed
cust.Instruments.Add(guitar);
}
这是总的想法。现在,让我更详细地解释一下:
IRepo
。这允许您在99%的情况下使用通用存储库,但仍有空间实现特定于(例如,Customer
实体)的自定义查询方法:
public interface IInstrumentRepo : IRepo<Instrument>
{
// nothing to do here
}
public interface ICustomerRepo : IRepo<Customer>
{
// but we'll need a custom method here
void FindByAddress(string address);
}
public interface IRepo<T>
{
T GetById(object id);
T Save(T item);
}
public class RepoFactory : IRepoFactory
{
public IInstrumentRepo CreateInstrumentRepo(ISession s)
{
return new InstumentRepo(s);
}
}
DAL
类中使用单例模式来保持工厂(有一些更好的方法可以做到这一点,使用DI,但目前这很好):
是否存在非泛型的
数据提供程序类?还是你有编译错误?我知道你正在学习,但仅供参考。在DAO/存储库后面抽象Nh实际上限制了Nh的潜力。更不用说NH是数据层抽象,因此在其上添加抽象只会产生噪音。@Groo我正在考虑从非泛型转换为泛型。@JasonMeckley:对于这样的泛型基类,它不会增加太多工作或开销,但它允许您在需要时自由操作。有时候,在一个地方对特定实体进行特定查询是很有用的,而不是在代码中重复这些查询。@Jason我真的不明白你的意思。我只是想保持代码紧凑,避免重复,因此我想探索解决这个问题的方法。这是正确的,但可能不是最好的方法。这个通用的repo应该作为一个基类,其他存储库可以根据需要继承和扩展它。如果将其方法设置为泛型,则将所有DAL调用限制为单个类。每个实体都有自己的存储库的工作单元方法是通常的做法,IMHO。@DavidM有趣的方法,我喜欢。@Groo你似乎对这个主题很了解,如果你有时间,你能发布你的解决方案吗?@MarkAllison:当然,我马上就要离开,但稍后会做。太好了-非常感谢。我正在努力解决一些问题,但我会坚持下去,看看我是否能让它发挥作用。我有一个问题-请有人看看我在这个问题上的更新?抓我的头。@马克:接口缺少public
关键字。我会更新。但是,请注意,具体类(如
public static class DAL
{
// repo factory is pretty lightweight, so no need for fancy
// singleton patterns
private static readonly IRepoFactory _repoFactory = new RepoFactory();
public static IRepoFactory RepoFactory
{
get { return _repoFactory; }
}
}