风继续吹----对一些ORM框架的使用心得(2)
如今到处的谈论着OOP,我想这个世界原本是很复杂的!
我们把职责单一到一个类去,维护一个类固然简单了,但是随着而来的关系却很让人头痛.
Hibernate是一个优秀的ORM工具.可以让这个框架为你做很多事.他们说可以把对象到数据库的映射工作量大大降低,实体之间的关系可以非常简单地进行配置.
但是我发现正如<<Joel说软件>>,被包装和抽象的东西约多,我们的应对意外的能力就约低了.
在hibernate的配置文件了,如果你要配置一个组有很多用户.可能config如下:
<bag name="Users" table="OrgUsers" lazy="false" inverse="false" >
<key column="Org_ID" />
<many-to-many class="QPG.Support.Data.User, Support.Data" column="User_ID" />
</bag>
<bag name="ACL" table="AccessRights" lazy="true">
<key column="Org_ID" />
<one-to-many class="QPG.Support.Data.AccessToResource, Support.Data" />
</bag>
<key column="Org_ID" />
<many-to-many class="QPG.Support.Data.User, Support.Data" column="User_ID" />
</bag>
<bag name="ACL" table="AccessRights" lazy="true">
<key column="Org_ID" />
<one-to-many class="QPG.Support.Data.AccessToResource, Support.Data" />
</bag>
随着业务的发展,将来很可能就比较多事情了....
在我们的事件中,总结了一个集中处理一对多的思想:
1) 把关系集中到一个表,用Catalog区分是什么关系,比如GroupUsers就是一个组到多个用户的那种关系.
2) 这个关系实体数据就由hibernate替我们自动保存了;
3) 使用OneToMany<T1,T2>来获取关系数据,比如new OneToMany<Group,User>(theGroup,theUserArray)
下面就看看我们的通用DAO吧:
namespace QPG.Support.DataAccessService{
using System;
using System.Collections;
using QPG.Support.Data;
using Castle.Services.Transaction;
using Castle.Facilities.NHibernateIntegration;
using NHibernate;
public class DAO<T> where T : BasicData {
protected readonly ISessionManager _sessManager;
protected NHibernateGenericDao _dao;
public DAO(ISessionManager sm, string dbtag)
{
_sessManager=sm;
_dao = new NHibernateGenericDao(sm);
_dao.SessionFactoryAlias = dbtag;
}
public DAO(ISessionManager sm)
{
_sessManager = sm;
_dao = new NHibernateGenericDao(sm);
_dao.SessionFactoryAlias = GLOBAL.BASIC_DB_TAG;
}
public T[] getEntites(string wherehql) {
Array temp = _dao.FindAllWithCustomQuery("from " + typeof(T) + " where " + wherehql);
if (temp == null || temp.Length == 0) return new T[0];
T[] rt = new T[temp.Length];
temp.CopyTo(rt,0);
return rt;
}
public T[] getEntites(IQuery q)// 危险,小心使用,用于从关系表中返回对应实体
{
IList list = q.List();
T[] rt = new T[list.Count];
list.CopyTo(rt, 0);
return rt;
}
public T[] getEntites(ICriteria criteria)// 危险,小心使用,用于从关系表中返回对应实体
{
IList list = criteria.List();
T[] rt = new T[list.Count];
list.CopyTo(rt, 0);
return rt;
}
public T getEntityByID(string id)
{
return _dao.FindById(typeof(T),id)as T;
}
public T getEntityByCode(string code)
{
return getEntites("IndexCode='" + code + "'")[0];
}
public T getEntityLikedCode(string code)
{
return getEntites("IndexCode like '" + code + "%'")[0];
}
public T[] findAll()
{
return _dao.FindAll(typeof(T)) as T[];
}
[Transaction]
public virtual void save(T data) {
_dao.Save(data);
}
[Transaction]
public virtual void save(T[] data) {
foreach(T r in data)
_dao.Save(r);
}
[Transaction]
public virtual void delete(T entity) {
_dao.Delete(entity);
}
[Transaction]
public virtual void deleteAll() {
_dao.DeleteAll(typeof(T));//如果存在关系,这个操作就会发生异常!
}
[Transaction]
public virtual void saveOneToManyData< T2>(string catalog, OneToMany<T, T2> rel,
DAO<OneToManyData> oneToManyDao,
ISessionManager sessManager, string dbTag)
where T2 : BasicData
{
using (NHibernate.ISession s = sessManager.OpenSession(dbTag))
{
OneToManyData[] old = oneToManyDao.getEntites("FromID='" + rel.Master.ID + "'");
foreach (OneToManyData d in old) oneToManyDao.delete(d);
s.Flush();
foreach (T2 r in rel.Assistants)
{
OneToManyData data = new OneToManyData();
data.Catalog = catalog;
data.FromID = rel.Master.ID;
data.ToID = r.ID;
oneToManyDao.save(data);
}
s.Flush();
}
}
[Transaction]
public virtual void deleteOneToManyData<T2>(string catalog, string mid,
DAO<OneToManyData> oneToManyDao,
ISessionManager sessManager, string dbTag)
where T2 : IndexData
{
using (NHibernate.ISession s = sessManager.OpenSession(GLOBAL.BASIC_DB_TAG))
{
string hql = "Catalog='" + catalog + "' and " + "FromID='" + mid + "'";
OneToManyData[] data = oneToManyDao.getEntites(hql);
foreach (OneToManyData d in data) oneToManyDao.delete(d);
s.Flush();
}
}
[Transaction(TransactionMode.NotSupported)]
public virtual OneToMany<T, T2> loadOneToMany<T2>(string catalog, string master_id,
DAO<T2> sdao, DAO<OneToManyData> oneToManyDao,
ISessionManager sessManager, string dbTag)
where T2 : IndexData
{
OneToMany<T, T2> rel = null;
string[] wantIDs = null;
ICriteria c;
using (NHibernate.ISession s = sessManager.OpenSession(GLOBAL.BASIC_DB_TAG))
{
c = s.CreateCriteria(typeof(OneToManyData));
c.Add(new NHibernate.Expression.EqExpression("Catalog", catalog));
c.Add(new NHibernate.Expression.EqExpression("FromID", master_id));
OneToManyData[] many = oneToManyDao.getEntites(c);
wantIDs = new string[many.Length];
for (int i = 0; i < many.Length; i++) wantIDs[i] = many[i].ToID;
}
using (NHibernate.ISession s = sessManager.OpenSession(dbTag))
{
T root = this.getEntityByID(master_id);
c = s.CreateCriteria(typeof(T2));
c.Add(new NHibernate.Expression.InExpression("ID", wantIDs));
rel = new OneToMany<T, T2>(root, sdao.getEntites(c));
}
return rel;
}
}
}
注意:BasicData里只有ID这个所有实体都要的属性而已.
alex 4-10