How can I run NHibenate queries asynchronously?

♀尐吖头ヾ 提交于 2019-11-30 08:10:18

As of NHibernate v5, async is now fully supported!

Here are some nifty examples:

Customer customer = await session.GetAsync<Customer>(1);

List<Customer> customers = await session.Query<Customer>().ToListAsync();

Customer customer = await session.Query<Customer>()
.Where(x => x.Name.Contains("Customer 1"))
.SingleOrDefaultAsync();

Updating an entity

using (ISession session = sessionFactory.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
    Customer customer = await session.GetAsync<Customer>(1);
    customer.Name = "Customer 3";
    await session.SaveOrUpdateAsync(customer);
    await transaction.CommitAsync();
}

Source article

Note that async database calls do NOT imply better overall scalability by themselves. I recommend reading the article "Should my database calls be Asynchronous?" for an in-depth analysis. Here's a quote from that article:

One respected DB/Web architect went so far as to say:
For database applications using async operations to reduce the number of blocked threads on the web server is almost always a complete waste of time. A small web server can easily handle way more simultaneous blocking requests than your database back-end can process concurrently. Instead make sure your service calls are cheap at the database, and limit the number of concurrently executing requests to a number that you have tested to work correctly and maximize overall transaction throughput.

multiple async calls can be rewritten with Futures

var footask = QueryFooAsync();
var bartask = QueryBarAsync();
var baztask = QueryBazAsync();

var foos = await footask;
var bars = await bartask;
var baz = await baztask;

// do something with foos, bars, baz

can be replaced with

var foos = session.Query<Foo>().....ToFuture();
var bars = session.Query<Bar>().....ToFuture();
var baz = session.Query<Bazes>().....ToFutureValue();

await Task.Factory.StartNew(() => var ignored = baz.Value)  // await the results

// do something with foos, bars, baz

this even has the benefit over async code that the roundtrip time is only paid once instead of 3 times.

Unfortunately, no. NHibernate does not expose the internal implementation of the command execution in the way L2S does.

You'll have to use the threadpool OR create a patch for NH to add asynchronous query support. That would be very welcome by the community and would make for a nice exercise (but it's not trivial at all)

Although there is still no support for async queries in NH, you can still partially overcome some of the undesired effects of running (long-running) db calls from request thread.

What you want is to split Threadpool between short-running and long-running operations. Of course this is not possible with actual implementation of Threadpool and TPL but you can help yourself quite eassilly by writing your own Producer/Consumer queue with awaitable items and customized concurency.

Please have a look at example i have put together : https://gist.github.com/3746240

Code is copy/pasted from great book "C# 5.0 in a Nutshell: The Definitive Reference" by Joseph Albahari and Ben Albahari with modification done by me causing the scheduler to create dedicated worker threads for items proccesing.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!