powered by simpleCommunicator - 2.0.52     © 2025 Programmizd 02
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / NHIbernate: коллекции равны null у proxy
8 сообщений из 8, страница 1 из 1
NHIbernate: коллекции равны null у proxy
    #37290007
NHibernate_User_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день, уважаемые! Очень были бы рады помощи в решении такой проблемы, уже давно возникающей:

Есть entity Organization. У нее есть потомок ТакаяТоOrganization. В потомке две коллекции, вот та из них, от которой проблемы:
Код: plaintext
1.
2.
3.
4.
5.
        public virtual IEnumerable<Contract> Contracts // для внешних слоев приложения
        {
            get { return new ImmutableSet<Contract>(_contracts); }
        }
        protected internal virtual Iesi.Collections.Generic.ISet<Contract> _contracts { get; set; } // NH, entities

маппинг, экспортированный Fluent (коллекция попала в маппинг предка, в ветку <joined-subclass>):
Код: plaintext
1.
2.
3.
4.
5.
6.
      <set cascade="save-update" inverse="true" name="_contracts" where="DeletionDate is null" mutable="true">
        <key foreign-key="FK_ТакаяТоOrganization_Contract_ТакаяТоOrganizationId">
          <column name="ТакаяТоOrganizationId" />
        </key>
        <one-to-many class="..." />
      </set>

В конструкторе Contract вызывается метод изменения коллекции, принадлежащей ТакаяТоOrganization:
Код: plaintext
такаяТоOrganization._contracts.Add(this);
Это кидает Exception, значение null. Вместо такаяТоOrganization на данный момент NH держит в памяти прокси.
Самое странное - смотрим в отладчике MSVS коллекцию public (Contracts), видны в ней договора.
Смотрим поле _contracts, из которого собственно и читается она - у прокси она null.
Как бы не работает Lazy Load в таком случае, выходит.

Как быть?
...
Рейтинг: 0 / 0
NHIbernate: коллекции равны null у proxy
    #37290632
NHibernate_User_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Собственно, пока нашел 4 варианта ответов

а) GetConcrete() у организации, возвращающий null (этот класс абстрактный), и его реализации, возвращающие this, у потомков.
б) переписать методы - лишить другие классы доступа к коллекции. Тогда упростится и маппинг.
в) вызвать NHibernat-овский метод, который может распроксить объект (где-то, помню, обсуждался, решили, что GetConcrete() лучше).
г) сделать третье поле, которое будет возвращать не ImmutableSet<Contract>, а непосредственно _contracts. Громоздко.

Как лучше, или, может, еще как-то?
...
Рейтинг: 0 / 0
NHIbernate: коллекции равны null у proxy
    #37290706
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NHibernate_User_Как бы не работает Lazy Load в таком случае, выходит.


Угадаете, как отладчик смотрит коллекцию?

NHibernate_User_б) переписать методы - лишить другие классы доступа к коллекции. Тогда упростится и маппинг.


Единственно верная мысль, я вам ее уже говорил. Коллекция - собственность класса. Изменения членов только через методы add/remove.
...
Рейтинг: 0 / 0
NHIbernate: коллекции равны null у proxy
    #37290736
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
простейший вариант вдогонку.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
    public class Org
    {
        private Iesi.Collections.Generic.ISet<Contract> _contracts;
        
        public virtual IEnumerable<Contract> Contracts 
        {
            get { return new ImmutableSet<Contract>(_contracts); }
        }

        public virtual void AddContract(Contract contract)
        {
            contract.Org = this;
            _contracts.Add(contract);
        }

        public virtual void RemoveContract(Contract contract)
        {
            contract.Org = null;
            _contracts.Remove(contract);
        }
        
    }

    public class Contract
    {
        public virtual Org Org{get; protected internal set; }
    }

Целуйтесь по возможности :)
...
Рейтинг: 0 / 0
NHIbernate: коллекции равны null у proxy
    #37290957
NHibernate_User_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спасибо, хотя у нас М:М. Я вижу, поле Org в Contract не зазорно переписывать из другого объекта?
Тут встает вопрос, как нам не спутать и не вызвать метод по ошибке не тот?
Скажем, надо полностью разорвать связь, Organization.DeleteContract() убирает контракт из своей коллекции contracts, а потом для убирания организации из коллекции организаций внутри контракта вызывает Contract.DeleteOrganization. Которая уже ничего не вызывает, а только чистит свою коллекцию. Т.е. первый метод чистит две коллекции - свою и чужую (через второй) - а второй только свою.

Что, если программист ошибется и вызовет в контроллере (MVC) или еще где-то вместо первого метода второй? Называются-то они одинаково. Тот не почистит обе коллекции (только одну), и в той же сессии кто-то может успеть прочитать коллекцию с "фантомным" как бы значением.

Если для удаления еще могу придумать разные названия: Delete и Remove, то как с добавлением быть? AddContract и DobavitOrganization? :)
Ну и protected internal сделать у "внутренних" методов, т.е. которые только одну коллекцию чистят.

Придумал еще вариант, у него, конечно, минус, что вся коллекция пройдется (хотя бы id-ы будут прочитаны), но тем не менее она и так (при collection.Remove) пройдется, как я понимаю.
Примерно как
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
class A {
  void DeleteB(B b)
  {
    collection_of_b.Remove(b);
    if (b.Collection_of_a.Any(x => x.Id == this.Id)) // =================== В этом вся суть. Как вам такое??
    {
      b.DeleteA(this);
    }
  }
  public Collection_of_b ... // read-only, для всех
  private collection_of_b ... // для себя, можно менять
}

class B {
  void DeleteB(A a)
  {
    collection_of_a.Remove(a);
    if (a.Collection_of_b.Any(x => x.Id == this.Id)) // =================== В этом вся суть. Как вам такое??
    {
      a.DeleteB(this);
    }
  }
  public Collection_of_a ... // read-only, для всех
  private collection_of_a ... // для себя, можно менять
}

Кстати сказать, Вы бы использовали collection.Contains() или linq с лямбдой?

Нет ли статей по реализации М:М по-нормальному? Сколько ни смотрю примеров, везде всё public! Хотя бы тут... Мне бы несколько вариантов реализаций М:М в NHibernate от разных авторов, но увы - ищу, ищу, а там все (от мегаразработчиков-глав до студентов) в примерах используют public...
...
Рейтинг: 0 / 0
NHIbernate: коллекции равны null у proxy
    #37291824
NHibernate_User_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Что-то все же непонятное.
>Угадаете, как отладчик смотрит коллекцию?
Нет, не угадаю. Попытался сделать метод внутри entity для работы с ее же коллекцией

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
        protected internal virtual void AddContract(Contract contract)
        {
            if (contract.Id != 0 && _contracts.Any(x => x.Id == contract.Id))
            {
                throw new Exception("Данный договор уже связан с этой организацией.");
            }

            _contracts.Add(contract); ///////////////
        }

Не только в отладчике коллекция null, но и он кидает exception "Object reference not set to an instance of an object." на строке Add(contract).
А public коллекция почему-то не Null.
Почему так.
...
Рейтинг: 0 / 0
NHIbernate: коллекции равны null у proxy
    #37292144
NHibernate_User_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Может, в маппингах все дело. В книге NH CookBook вроде пример маппинга в связи 1:М (на стороне М) просто как
Код: plaintext
<property name="Actor" not-null="true" />

А у нас на стороне М:
Код: plaintext
            References(x => x.ТакаяТоOrganization).Column("ТакаяТоOrganizationId").Not.Nullable();
Код: plaintext
1.
2.
    <many-to-one class="ТакаяТоOrganization, ... foreign-key="FK_Contract_ТакаяТоOrganization" name="ТакаяТоOrganization">
      <column name="ТакаяТоOrganizationId" not-null="true" />
    </many-to-one>

в примере на стороне 1:
Код: plaintext
1.
2.
3.
4.
<list name="Actors" cascade="all-delete-orphan">
  <key column="MovieId" />
  <index column="ActorIndex" />
  <one-to-many class="ActorRole"/>
</list>

у нас:
Код: plaintext
1.
2.
            HasMany(x => x.Contracts)
                .AsSet().Access.CamelCaseField()
                .KeyColumn("ТакаяТоOrganizationId").Inverse().Cascade.SaveUpdate().Where("DeletionDate is null");
Код: plaintext
1.
2.
3.
4.
5.
      <set access="field.camelcase" cascade="save-update" inverse="true" name="Contracts" where="DeletionDate is null" mutable="true">
        <key foreign-key="FK_ТакаяТоOrganization_Contract_ТакаяТоOrganizationId">
          <column name="ТакаяТоOrganizationId" />
        </key>
        <one-to-many class="..." />
      </set>
...
Рейтинг: 0 / 0
NHIbernate: коллекции равны null у proxy
    #37292286
NHibernate_User_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Такое впечатление, что NHibernate не дружит с protected internal.
Заменил protected internal на public, все заработало.

public /*protected internal*/ virtual void AddContract(Contract contract)

Весь тщательно спроектированный домен будет разваливаться по швам из-за этих public .... :(
...
Рейтинг: 0 / 0
8 сообщений из 8, страница 1 из 1
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / NHIbernate: коллекции равны null у proxy
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]