Я использую NHibernate 3.2 и у меня проблема с отображением коллекции.
После запроса учетной записи пользователя ...
UserAccount userAccount = (from u in Session.Query<UserAccount>()
where u.Username == username
select u).SingleOrDefault();
... свойство Role
содержит пустую коллекцию, в то время как поле roles
содержит актуальные элементы:
![Debugger view](https://i.stack.imgur.com/95l2K.png)
Это ошибка в NH 3.2 или что-то в этом роде?Я почти уверен, что он работал на 3.1.
Я полагаю, что с поведением прокси-сервера может быть что-то не так, особенно переопределение, которое обрабатывает отложенную загрузку для свойства Roles
.Однако я не знаю, как проверить сгенерированный прокси-класс (используя декомпилятор IL), потому что, насколько я знаю, он живет только в памяти во время выполнения.
EDIT 1
Чтобы помочь мне узнать, что происходит внутри прокси-сервера, я только что разместил вопрос: Есть ли способ декомпилировать прокси-классы, сгенерированные NHibernate? .Я думаю, что предмет заслуживает того, чтобы быть вопросом сам по себе, потому что он может быть полезен во многих других ситуациях.
РЕДАКТИРОВАТЬ 2
Ну, мне удалось декомпилироватьдинамический прокси-класс.Это метод, который управляет отложенной загрузкой свойства Roles
:
public override IEnumerable<Role> get_Roles()
{
IInterceptor interceptor = this.Interceptor;
if (interceptor == null)
{
throw new NotImplementedException();
}
object[] args = new object[0];
InvocationInfo info = new InvocationInfo(
this, (MethodInfo)methodof(UserAccount.get_Roles),
null, new Type[0], args);
args = info.Arguments;
return (IEnumerable<Role>)interceptor.Intercept(info);
}
Я не думаю, что здесь происходит что-то особенное.
РЕДАКТИРОВАТЬ 3
Во время отладки перехватчика (который частично показан ниже), я заметил, что когда он вызывается для methodName == "get_Roles"
, для свойства TargetInstance
(в данном случае это UserAccount
), этоroles
поле является пустой коллекцией.Однако перед доступом к свойству Roles
в экземпляре прокси поле прокси *1046* содержит заполненную коллекцию.
public class DefaultDynamicLazyFieldInterceptor
: IFieldInterceptorAccessor, Proxy.DynamicProxy.IInterceptor
{
...
public object Intercept(InvocationInfo info)
{
var methodName = info.TargetMethod.Name;
if (FieldInterceptor != null)
{
...
При проверке экземпляра InvocationInfo
proxy
и Target
экземпляры do имеют поле roles
, содержащее заполненную коллекцию.
РЕДАКТИРОВАТЬ 4
Я думаю,что я столкнулся с NH Выпуск 2772 - Ленивая коллекция не загружается, когда свойство загружено Лениво .
КОНЕЦ РЕДАКТИРОВАНИЯ
Вот классы сущностей:
public class UserAccount : Entity
{
...
private IList<Role> roles;
public virtual IEnumerable<Role> Roles
{
get
{
return roles;
}
}
...
}
public class Role : Entity
{
...
}
Вот часть файла отображения HBM для сопоставления UserAccount:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property"
auto-import="false" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" dynamic-insert="true"
dynamic-update="true" schema="[MySchema]" mutable="true"
name="MyNamespace.UserAccount, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
table="UserAccounts">
...
<bag access="nosetter.camelcase" cascade="none" name="Roles"
schema="[MySchema]" table="UserAccounts_Roles" mutable="true">
<key>
<column name="UserAccountId" />
</key>
<many-to-many class="MyNamespace.Role, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<column name="RoleId" />
</many-to-many>
</bag>
...
</class>
</hibernate-mapping>
А вот часть HBM, которая определяет отображение ролей:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property"
auto-import="false" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" dynamic-insert="true"
dynamic-update="true" schema="[MySchema]" mutable="true"
name="MyNamespace.Role, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
table="Roles">
...
</class>
</hibernate-mapping>