如何使用NHibernate在Repository模式中进行复杂连接?

时间:2017-03-14 05:17:46

标签: c# nhibernate

我使用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;
        }
    }

这里我可以在没有任何连接的情况下获取数据。如何使用连接获取数据? 例如:菜单详细信息存储在菜单表中,菜单权限存储在菜单权限表中。如何为其创建存储库?

2 个答案:

答案 0 :(得分:1)

使用QueryOver,您的Junction方法接受输入Expression而不是FindBy即可。

以下代码可能会有所帮助。如果不需要,请移除columnListtop参数。请注意,我的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)

如果您想加载相关的实体,请使用FetchFetchMany

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而不是抓取。