Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# web应用中的NHibernate查询策略_C#_Asp.net Mvc_Asp.net Mvc 3_Nhibernate - Fatal编程技术网

C# web应用中的NHibernate查询策略

C# web应用中的NHibernate查询策略,c#,asp.net-mvc,asp.net-mvc-3,nhibernate,C#,Asp.net Mvc,Asp.net Mvc 3,Nhibernate,在web应用程序场景中,数据检索通常有两个要求: 1.所有查询都需要有选择地分页 2.用户需要进行大量“过滤”查询(例如,按姓名、邮件和年龄搜索人员) 3.某些客户端网格隐含的排序查询 当然还有组合的情况:经过筛选的分页查询,它们是经过排序的:) 这些需求会导致数据层中出现大量的存储库方法,每个方法都有很多参数。 是否存在使此过程具有更动态行为的常见模式(例如,根据域类属性自动生成的查询) 我知道存储库方法应该是干净的和定义良好的。但目前,每当我向MVC视图或可排序的分页表添加一些过滤表单时,我

在web应用程序场景中,数据检索通常有两个要求: 1.所有查询都需要有选择地分页 2.用户需要进行大量“过滤”查询(例如,按姓名、邮件和年龄搜索人员) 3.某些客户端网格隐含的排序查询

当然还有组合的情况:经过筛选的分页查询,它们是经过排序的:)

这些需求会导致数据层中出现大量的存储库方法,每个方法都有很多参数。 是否存在使此过程具有更动态行为的常见模式(例如,根据域类属性自动生成的查询)

我知道存储库方法应该是干净的和定义良好的。但目前,每当我向MVC视图或可排序的分页表添加一些过滤表单时,我都想编写大量样板代码

其他开发人员如何处理此类需求


提前感谢您

您可以让您的存储库提供IQueryable并让ActionMethod确定要显示的内容。例如:

    public System.Linq.IQueryable<Models.MyModel> Query()
    {
        return mSession.Query<Models.MyModel>();
    }
public System.Linq.IQueryable查询()
{
返回mSession.Query();
}

在我们的项目中,我们也使用了存储库,每个实体都使用存储库,但我不喜欢这样。 当您编写包含大量交互实体的复杂查询时,它可能会产生很多问题。 我认为它将是一个用于基本操作的通用存储库,所有查询都应该以查询对象模式呈现,类似于每个查询都有一个单独的类,不过请看:

存储库和公开IQueryable的存储库是一场激烈的辩论

底线是一个通用的存储库或公开IQueryable根本不是真正的存储库,它只是数据层的抽象。

现在,这不是一件坏事,但不要称之为存储库,尽管如此。数据层抽象允许您在UI中快速插入一些内容,在其中读取和写入实体,而不会将数据层框架泄漏到UI中。当然,您可以只注入一个
会话
,然后就可以使用它了

public interface IRepository<T> {}

public class NHibernateRepository<T> : IRepository<T>
{
    private ISession session;

    public NHibernateRepository(ISession session)
    {
        this.session = session;
    }

    T Get(object id) { return session.GetById<T>(id)); }

    IQueryable<T> Query { get { return session.Query<T>(); }
}

new NHibernateRepository<Customer>(session).Query().Where(customer => customer.Name == Fred);
最后,如果你有冒险精神,你可能想看看,这是一个很大的主题概述在这里,但有大量的例子


第一种方法实现起来更快,第二种方法提供了更清晰的可重用代码,第三种方法提供了UI层之间的分离,但需要更多的基础工作。这取决于您需要什么,需要什么,可能应该按照这个顺序处理。

您使用存储库来枚举聚合根。通常情况下,您的控制器使用聚合根,您可以根据用户的要求对其进行筛选、排序等

因此,我按照前面提到的方法使用存储库

然而,有时我需要在更复杂的规范中工作,在这些规范中,使用聚合根和/或整个存储库要么痛苦、低效,要么根本不可能。例如,您可能需要运行大型业务报告,或者可能需要执行批处理命令

在这种情况下,我还定义了
ICommand
/
IQuery
,使用NH基本实现来处理管道设备(就像通用
存储库那样)

然后,我要做的是创建一个表示规范契约的接口,公开可能需要帮助我构建所需参数的任何成员。然后,我使用NH作为主干来实现该规范,使用任何最合适的技术(HQL语句、原始SQL、标准、查询版本……等等)来实现该规范

这是我的意思的粗略说明。请注意,我使用的是任意的
ICommandProvider
,它是根据需要创建命令新实例的对象(如果您需要在一个操作中发出多个命令)。我将向IoC注册我的命令,并让提供程序使用它来创建命令实例

public interface ICommand
{

}

public interface ICommandProvider
{
    TCommand Create<TCommand>()
        where TCommand : ICommand;

}

public interface IQuery<TResult> : ICommand
{
    TResult Execute();
}

public class NhCommand : ICommand
{
    // plumbing stuff here, like finding the current session
}

public class DelinquentAccountViewModel
{
    public string AccountName { get; set; }
    public decimal Amount { get; set; }
}

public interface IDelinquentAccountsQuery : IQuery<IEnumerable<DelinquentAccountViewModel>>
{
    void AmountGreaterThan(decimal amount);
    // you could define members for specifying sorting, etc. here
}

public class DelinquentAccountsQuery : NhCommand
{
    public IEnumerable<DelinquentAccountViewModel> Execute()
    {
        // build HQL and execute results, resulting in a list of DelinquentAccountViewModels
        // using _amountGreaterThan as a parameter
        return null;
    }

    private Decimal _amountGreaterThan;

    public void AmountGreaterThan(Decimal amount)
    {
        _amountGreaterThan = amount;
    }
}
公共接口ICommand
{
}
公共接口ICommandProvider
{
TCommand Create()
其中t命令:i命令;
}
公共接口IQuery:ICommand
{
TResult Execute();
}
公共类命令:ICommand
{
//这里的管道工具,比如查找当前会话
}
公共类CountViewModel
{
公共字符串AccountName{get;set;}
公共十进制数{get;set;}
}
公共接口IDelinquentAccountsQuery:IQuery
{
无效金额大于(十进制金额);
//您可以在此处定义用于指定排序等的成员
}
公共类countsquery:NhCommand
{
公共IEnumerable Execute()
{
//构建HQL并执行结果,生成一个CountViewModels列表
//使用_amountterthan作为参数
返回null;
}
私有十进制数_大于;
公共无效金额大于(十进制金额)
{
_金额大于等于金额;
}
}
控制器中的用法可能如下所示:

public class DelinquentAccountsController : Controller
{
     protected ICommandProvider CommandProvider { get; private set; }

     public DelinquentAccountsController(ICommandProvider commandProvider)
     {
         CommandProvider = commandProvider;
     }

     public ActionResult Index(decimal amount)
     {
         var query = CommandProvider.Create<IDelinquentAccountsQuery>();
         query.AmountGreaterThan(amount);
         return View(query.Execute());

     }
}
公共类计数器控制器:控制器
{
受保护的ICommandProvider命令提供程序{get;private set;}
公共计数器控制器(ICommandProvider commandProvider)
{
CommandProvider=CommandProvider;
}
公共行动结果指数(十进制金额)
{
var query=CommandProvider.Create();
查询金额大于(金额);
返回视图(query.Execute());
}
}

没有人说您不能使用命令/查询来访问所有数据,但这比我需要的工作量要多。我发现标准存储库方法(使用LINQ对抗NHibernate)可以处理我的应用程序所需的95%左右的数据访问。

Imho orm已经足够抽象了。除此之外,您不需要存储库。
public class DelinquentAccountsController : Controller
{
     protected ICommandProvider CommandProvider { get; private set; }

     public DelinquentAccountsController(ICommandProvider commandProvider)
     {
         CommandProvider = commandProvider;
     }

     public ActionResult Index(decimal amount)
     {
         var query = CommandProvider.Create<IDelinquentAccountsQuery>();
         query.AmountGreaterThan(amount);
         return View(query.Execute());

     }
}
public static class QueryExtensions
{
    public static IQueryable<T> Published(this IQueryable<T> pages) where T : IPage
    {
        return pages.Where(p => p.State == PageState.Public && p.Published <= DateTime.UtcNow);
    }
    public static IQueryable<T> By(this IQueryable<T> pages, User author) where T : IPage
    {
        return pages.Where(p => p.Author == author);
    }

    public static IEnumerable<Foo> AdvancedThing(this ISession session, string text)
    {
        // I get all the power of NHibernate :)
        return session.CreateQuery("...").SetString("text", text).List<Foo>();
    }
}
var posts = session.Query<Post>().By(user).Published().FetchMany(p => p.Tags).ToList();