我使用Repository模式使用Nhibernate开发我的项目。如何在Nhibernate中进行复杂的连接。我使用下面的存储库方法来获取数据
public virtual TEntity FindBy(Expression<Func<TEntity, bool>> query)
{
try
{
return NHUnitOfWork.Session.Query<TEntity>().Where(query).FirstOrDefault();
}
catch (Exception ex)
{
throw;
}
}
这里我可以在没有任何连接的情况下获取数据。如何使用连接获取数据? 例如:菜单详细信息存储在菜单表中,菜单权限存储在菜单权限表中。如何为其创建存储库?
答案 0 :(得分:1)
使用QueryOver
,您的Junction
方法接受输入Expression
而不是FindBy
即可。
以下代码可能会有所帮助。如果不需要,请移除columnList
和top
参数。请注意,我的ISession
用法不同。您需要将nhSession
替换为NHUnitOfWork.Session
。另一个区别是您使用的是Query
,我在这里使用QueryOver
。
public virtual IList<T> FindBy<T>(ProjectionList columnList, Junction where, int top) where T : BaseEntity
{
IList<T> instance = GetQueryOver<T>(columnList, where).Take(top).List();
return instance;
}
public virtual IQueryOver<T> GetQueryOver<T>(ProjectionList columnList, Junction where) where T : BaseEntity
{
IQueryOver<T> query = null;
if((columnList != null) && (where != null))
{
query = nhSession.QueryOver<T>()
.Select(columnList)
.TransformUsing(Transformers.AliasToBean<T>())
.Where(where);
}
else if((columnList != null) && (where == null))
{
query = nhSession.QueryOver<T>()
.Select(columnList)
.TransformUsing(Transformers.AliasToBean<T>());
}
else if((columnList == null) && (where != null))
{
query = nhSession.QueryOver<T>()
.Where(where);
}
else
{
query = nhSession.QueryOver<T>();
}
return query;
}
然后,您可以在其他位置调用此信息,例如:
Junction where = Restrictions.Conjunction();
where.Add(Restrictions.Eq(Projections.Property<MyEntity>(x => x.Field), findValue));
where.Add(Restrictions.................);
where.Add(Restrictions.................);
entityList = Repository.FindBy<MyEntity>(null, where, 100);
答案 1 :(得分:1)
如果您想加载相关的实体,请使用Fetch
和FetchMany
。
public virtual Menu FindBy(Expression<Func<Menu, bool>> query)
{
return NHUnitOfWork.Session.Query<Menu>().Where(query)
.FetchMany(m => m.Rights)
// Required with FetchMany and First, otherwise only one right would be loaded.
.ToList()
.FirstOrDefault();
}
或者,如果您的模型每个菜单只有一个权限:
public virtual Menu FindBy(Expression<Func<Menu, bool>> query)
{
return NHUnitOfWork.Session.Query<Menu>().Where(query)
.Fetch(m => m.Right)
.FirstOrDefault();
}
但似乎你想要定义一些&#34;通用存储库&#34;封装NHibernate API 也许那时候:
public virtual TEntity FindBy<TFetched>(Expression<Func<TEntity, bool>> query,
Expression<Func<TEntity, IEnumerable<TFetched>>> fetchMany)
{
var query = NHUnitOfWork.Session.Query<TEntity>().Where(query);
if (fetchMany != null)
query = query.FetchMany(fetchMany);
return query
// Required with FetchMany and First, otherwise only one right would be loaded.
.ToList()
.FirstOrDefault();
}
或者,如果您的模型每个菜单只有一个权限:
public virtual TEntity FindBy<TFetched>(Expression<Func<TEntity, bool>> query,
Expression<Func<TEntity, TFetched>> fetch)
{
var query = NHUnitOfWork.Session.Query<TEntity>().Where(query);
if (fetch != null)
query = query.Fetch(fetch);
return query
.FirstOrDefault();
}
但如果你需要很多提取怎么办*?和子提取(ThenFetch
/ ThenFetchMany
)?它看起来像一条被诅咒的道路。您可能最终会在该路径之后编写整个NHibernate API的封装。
事实上,公开披露有关存储库的Expression where
论点对我来说并不好看。因此,您的存储库不再负责定义查询数据的方式
如果你想这样做,为什么不直接暴露IQueryable
?与试图将其封装在&#34;存储库中相比,它的代码冗长得多。同时仍在此&#34;存储库&#34;。
*:如果您执行多个FetchMany
,请注意笛卡尔积。要避免这种情况,请将您的查询拆分为多个(如果您希望单次往返数据库,请使用ToFuture
),或使用lazy loading with batching而不是抓取。