SQL 2008 | .NET 4.0 | NHibernate 3.1 | NHibernate.Castle 3.1 | Castle.Core 2.5.2
Итак, у меня есть таблица связей с метаданными, как и автор этого вопроса NHibernate Отображение многих ко многим с данными в таблице соединений
Изначально я составил карту так же, как и ответ на этот вопрос, поскольку он казался самым экономным способом справиться с этим. Однако после включения show_sql
и наблюдения за тем, что происходило, поиск идентификаторов в итоге дал N + 1 запросов, где N - количество ассоциаций.
Обратите внимание на этот пример базы данных, которая аналогична моим фактическим данным, определенным в sql-подобном синтаксисе
CREATE TABLE [User]
(
Id int PRIMARY KEY
)
CREATE TABLE UserPref
(
Id int PRIMARY KEY,
Name varchar(32)
)
CREATE TABLE UserPrefAssociation
(
UserId int,
PrefId int,
Value varchar(32)
)
Я взломал следующий код вместе с этим сопоставлением объектов «один ко многим» этого пользователя IList<UserPrefAssociation> Preferences { get; set; }
public IDictionary<string, string> GeneratePrefDict()
{
return Preferences
.ToDictionary(i => i.UserPref.Name, i => i.Value);
}
Конечно, это прекрасно работает, но, как упоминалось ранее, каждый i.UserPref.Name
является дополнительным запросом к SQL.
После игры в SQL я нашел запрос, который выполняет то, что я хочу. Тогда у меня возникает вопрос: как я могу это сделать с помощью NHibernate?
SELECT UserPref.Name, UserPrefAssociation.Value
FROM [User]
INNER JOIN UserPrefAssociation ON [User].Id = UserPrefAssociation.UserId
INNER JOIN UserPref ON UserPrefAssociation.UserPrefId = UserPref.Id
WHERE [User].Id = 1
~~~~ решаемый ~~~~~
using NHibernate.Linq;
...
public IDictionary<string, string> GeneratePrefDict(ISession s)
{
return
(from entry in s.Query<User_UserPref>()
where entry.User == this
select new
{
key = entry.UserPref.Name,
value = entry.Value
})
.ToDictionary(i => i.key, i => i.value);
}
Создает этот SQL
NHibernate: select userpref1_.Name as col_0_0_, user_userp0_.Value as col_1_0_ f
rom User_UserPref user_userp0_ left outer join UserPref userpref1_ on user_userp
0_.UserPrefId=userpref1_.Id where user_userp0_.UserId=@p0;@p0 = 1 [Type: Int32 (
0)]
Это лучше, чем N + 1 запросов, и решает мою проблему.