gpt4 book ai didi

nHibernate Future,加载顺序困惑

转载 作者:行者123 更新时间:2023-12-04 01:07:47 24 4
gpt4 key购买 nike

我可能正在使用 Future<T>方法完全错误,但我在理解如何优化其使用时遇到了很多麻烦。所以这是我的简单例子。

三个对象,Member , Player , Character

Member {
Player Player { get; set; }

Player {
IList<Character> Characters { get; set; }
}

所以基本上,一个成员也是一个玩家,一个玩家有很多角色。很简单。 (这种抽象的原因是保持 Member 轻量级,因此它只能用于身份验证和角色,其中更多的数据必须附加到 Player 类。)

那么,我有一个方法要查询所有Character那个Player有。所以我设置了以下查询...

        session.QueryOver<Player>()
.Fetch(context => context.Characters).Eager
.Take(1)
.Future<Player>();

session.QueryOver<Character>()
.Future<Character>()
.Take(10);

return session.QueryOver<Member>()
.Where(model)
.Fetch(context => context.Player).Eager
.List()
.Take(1)
.SingleOrDefault()
.Player;

我的想法是,根据我对 Future<T> 方式的理解工作(可能的方法是它会急切加载 Player (1:1),它将在同一数据库行程中执行 IList<Character> 的查询,限制为 10 个结果。它只需要 1每次行程玩家,每次行程 1 名成员(member),每次行程最多 10 个字符。

但是 nhProf告诉我我正在使用无限制的请求。有人可以向我解释这里发生了什么吗?我只是误解了这些方法的工作原理吗?或者任何人都可以提供一个更可行的例子吗?我不懂 HQL,所以我不能使用 CreateCriteria方法。

最佳答案

您问题中的三个查询将执行以下操作:

查询 1 将采用它可以在数据库中找到的第一个 Player,没有任何 where 条件。

查询 2 将采用它可以找到的前十个字符,同样没有任何 where 条件。

查询 3 将执行三个查询并获取第一个匹配您的 where 条件的成员以及关联的玩家,并返回成员的玩家。

如果您想遍历玩家的角色,NHibernate 会再次访问数据库,因为尚未加载任何角色。

您的示例可以在没有 Future 的情况下在单个查询中完成,如下所示:

System.Linq.Expressions.Expression<Func<Member, bool>> model = m => m.Id == 1;
Member mAlias = null;
Player pAlias = null;
Character cAlias = null;

Member member = session.QueryOver<Member>(() => mAlias)
.JoinAlias(m => m.Player, () => pAlias)
.Left.JoinAlias(() => pAlias.Characters, () => cAlias)
.Where(model)
.List().FirstOrDefault();

这是一个可以更好地展示 Futures 可以做什么的例子。查询的目标是获取 id = 1 的客户及其所有订单以及订单的详细信息和预订。

Class diagram

现在,如果我们想将订单及其详细信息和预订一起加载,结果查询将为我们提供笛卡尔积:count(Details) * count(Bookings)

int id = 1;
// define Aliases to use in query and be able to reference joined entities
Customer cAlias = null;
Order oAlias = null;
OrderDetails odAlias = null;
Booking bAlias = null;

// get the Customer and his Orders
var customers = session.QueryOver<Customer>(() => cAlias)
.Left.JoinAlias(o => o.Orders, () => oAlias)
.Where(c => c.Id == id)
.Future<Customer>();

// get the Orders and their Details
var orders = session.QueryOver<Order>(() => oAlias)
.JoinAlias(o => o.Customer, () => cAlias)
.Left.JoinAlias(() => oAlias.Details, () => odAlias)
.Where(() => cAlias.Id == id)
.Future<Order>();

// get the Orders and their Bookings
var orders2 = session.QueryOver<Order>(() => oAlias)
.JoinAlias(o => o.Customer, () => cAlias)
.Left.JoinAlias(() => oAlias.Bookings, () => bAlias)
.Where(() => cAlias.Id == id)
.Future<Order>();

var list = customers.ToList();
Customer customer = list.FirstOrDefault();

Order o1 = customer.Orders.FirstOrDefault();
// iterate through the Details
// normally this would cause N+1 selects, here it doesn't, because we already loaded
foreach (OrderDetails od1 in o1.Details)
{
decimal d = od1.Quantity;
}

我的所有映射都使用延迟加载,我没有在这些查询中指定预加载。尽管如此,当我运行代码时,在没有笛卡尔积的情况下,我在一次往返中正好得到三个 SQL 查询。这就是 Futures 的美妙之处。

关于nHibernate Future<T>,加载顺序困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5464296/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com