如何在应用程序的上层使用NHibernate.Criterion而不使用NHibernate参考?

时间:2015-08-11 08:34:44

标签: c# linq nhibernate

我写了一个多层应用程序(数据访问层,业务层,UILayer) 在DAL中我使用NHibernate来访问DB

然后在BusinessLayer中我访问DAL以使用存储库接口获取一些数据。

有时我需要通过困难的查询来获取数据。现在我使用Linq来提取数据。

我尝试在实现Criterion逻辑的存储库中编写metods,但是我认为,增长被覆盖方法的数量是错误的。

public T GetBy(System.Linq.Expressions.Expression<Func<T, bool>> func)
{
    return _session.QueryOver<T>().Where(func).List().FirstOrDefault();
}
public IEnumerable<T> GetAllWhere(System.Linq.Expressions.Expression<Func<T, bool>> func)
{
    return _session.QueryOver<T>().Where(func).List();
}
public IEnumerable<T> GetAllIn(ICollection collection)
{
    return _session.QueryOver<T>().Where(x => x.Id.IsIn(collection)).List<T>();
}

但是我越来越需要创建难以查询的标准(我不喜欢提取所有数据并按Linq过滤它的想法) 我希望在BL中使用的标准的示例:

repository.GetMany(x=>
                     x.Prop1.IsIn(Collection1)&&
                     x.Prop2.IsIn(Collection2)&&
                     x.Prop3.IsLike("SomeData")).ToList();

那么如何在没有参考的情况下在BL中使用NHibernate.Criterion逻辑?

---- ---解

我创建了课程Filter

public class CustomFilter<T>
        where T : Entity
    {
        public class FilterQuery
        {
            public enum QueryType
            {
                In, Where, Like, LikeIn,Top
            }

            public QueryType QType { get; set; }
            public Expression<Func<T,object>> Selector { get; set; }
            public object Data { get; set; }

            public FilterQuery(QueryType qType, Expression<Func<T,object>> selector, object data)
            {
                QType = qType;
                Selector = selector;
                Data = data;
            }
        }

        public  List<FilterQuery> Queries = new List<FilterQuery>();
        public  CustomFilter<T> In(Expression<Func<T, object>> selector, ICollection collection) 
        {
            var query = new FilterQuery(FilterQuery.QueryType.In, selector, collection);
            Queries.Add(query);
            return this;
        }

        public CustomFilter<T> Top(int i)
        {
            Queries.Add(new FilterQuery(FilterQuery.QueryType.Top, null,i));
            return this;
        }
    }

并在Repository

中编写了方法
public IEnumerable<T> GetByFilter(CustomFilter<T> filter)
        {

            IQueryOver<T,T> query = _session.QueryOver<T>();

            foreach (var _filter in filter.Queries)
            {

                switch (_filter.QType)
                {
                   case CustomFilter<T>.FilterQuery.QueryType.In:
                        query = query.WhereRestrictionOn(_filter.Selector)
                                     .IsIn((ICollection)_filter.Data);
                        break;
                   case CustomFilter<T>.FilterQuery.QueryType.Top :
                        query = (IQueryOver<T, T>) query.Take((int)_filter.Data);
                        break;
                }
            }
            return query != null ? query.List<T>() : null;

        }

使用过滤器我致电

 var docs = docRepo.GetByFilter(
                        new CustomFilter<Doc>()
                        .In(x => x.Archive, arcs)
                        .Top(200)
                        ).ToList();

1 个答案:

答案 0 :(得分:1)

如何打开或关闭该功能并不容易。总的来说,有三种方法,我要说。

第一个是MS及其LINQ。要做到这一点,只需使用

var query = session.Query<TEntity>()

我们(上层)现在可以根据需要查询该实体...只需使用LINQ API。缺点是NHibernate提供程序中没有完全覆盖LINQ - 但最终并没有那么糟糕。我不喜欢的是你发布了很多你的域名...没有一些属性或其他AOP ......只要有一个IQueryable就可以获得整个系统。

第二种是Ayendes方法:The DAL should go all the way to UI。小引用:

  

......我目前的方法完全不同。我定义了查询,其中包含查询的实际业务逻辑,但我将该查询向前传递到我的应用程序的更高级别。可以对查询(投影,分页,排序等)进行任何其他处理。这样,我的查询将被关闭以进行修改并打开扩展,因为它们可以被更高级别的代码进一步操纵...

在此处详细了解它:How to organize database layer using NHibernate

第三种选择是使用一些自定义解决方案。例如。我首选的是引入一些名为IFilter的抽象,它通过层传递。填写UI (可能是基于API的客户端),在BL上检查所有规则(包括一些安全的AOP)并在DAL中使用..并转换为NHibernate Criteria API。

希望这篇评论有所帮助...因为没有简单的方法可以说:上转过来。