【发布时间】:2014-01-24 23:05:09
【问题描述】:
我正在重写我的一些旧 NHibernate 代码,使其与数据库无关,并使用 NHibernate 查询而不是硬编码的 SELECT 语句或数据库视图。我被一个重写后速度非常慢的卡住了。 SQL查询是这样的:
SELECT
r.recipeingredientid AS id,
r.ingredientid,
r.recipeid,
r.qty,
r.unit,
i.conversiontype,
i.unitweight,
f.unittype,
f.formamount,
f.formunit
FROM recipeingredients r
INNER JOIN shoppingingredients i USING (ingredientid)
LEFT JOIN ingredientforms f USING (ingredientformid)
因此,这是一个非常基本的查询,其中包含从每个表中选择几列的几个 JOIN。此查询恰好返回大约 400,000 行,执行时间大约为 5 秒。我第一次尝试将其表达为 NHibernate 查询是这样的:
var timer = new System.Diagnostics.Stopwatch();
timer.Start();
var recIngs = session.QueryOver<Models.RecipeIngredients>()
.Fetch(prop => prop.Ingredient).Eager()
.Fetch(prop => prop.IngredientForm).Eager()
.List();
timer.Stop();
此代码可以运行并生成所需的 SQL,但运行需要 120,264 毫秒。之后,我遍历recIngs 并填充List<T> 集合,这需要不到一秒钟的时间。所以,NHibernate 正在做的事情是非常慢!我有一种感觉,这只是为每一行构建模型类实例的开销。但是,就我而言,我只使用每个表中的几个属性,所以也许我可以优化它。
我尝试的第一件事是:
IngredientForms joinForm = null;
Ingredients joinIng = null;
var recIngs = session.QueryOver<Models.RecipeIngredients>()
.JoinAlias(r => r.IngredientForm, () => joinForm)
.JoinAlias(r => r.Ingredient, () => joinIng)
.Select(r => joinForm.FormDisplayName)
.List<String>();
在这里,我只从我的一个 JOIN'ed 表中获取一个值。 SQL 代码再次正确,这一次它仅抓取了 select 子句中的 FormDisplayName 列。此调用需要 2498 毫秒才能运行。我想我们正在做点什么!
但是,我当然需要返回几个不同的列,而不仅仅是一个。这就是事情变得棘手的地方。我的第一次尝试是匿名类型:
.Select(r => new { DisplayName = joinForm.FormDisplayName, IngName = joinIng.DisplayName })
理想情况下,这应该返回具有DisplayName 和IngName 属性的匿名类型的集合。但是,这会在 NHibernate 中导致异常:
对象引用未设置为对象的实例。
另外,.List() 正在尝试返回 RecipeIngredients 的列表,而不是匿名类型。我也试过.List<Object>() 无济于事。唔。好吧,也许我可以创建一个新类型并返回这些类型的集合:
.Select(r => new TestType(r))
TestType 构造将采用 RecipeIngredients 对象并执行任何操作。但是,当我这样做时,NHibernate 会抛出以下异常:
发生了“NHibernate.MappingException”类型的未处理异常 在 NHibernate.dll 中
附加信息:没有持久性:KitchenPC.Modeler.TestType
我猜 NHibernate 想生成一个与 RecipeIngredients 的模式匹配的模型。
我该如何做我想做的事?似乎.Select() 只能用于选择单列的列表。有没有办法用它来选择多列?
也许一种方法是使用我的确切架构创建一个模型,但我认为这最终会和最初的尝试一样慢。
有没有什么方法可以从服务器返回这么多数据而无需大量开销,无需将 SQL 字符串硬编码到程序中或依赖于数据库中的 VIEW?我想让我的代码完全与数据库无关。谢谢!
【问题讨论】:
标签: c# .net nhibernate fluent-nhibernate