Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM Новый топик    Ответить
 [NHibernate] Unable to resolve property: _{Namespace}  [new]
_Novichok
Member

Откуда:
Сообщений: 316
Доброго здоровья.

Работаю с БД через NHibernate. В базу пишется объект, имеющий более 20 полей, некоторые - это списки списков. Для того, чтобы сохранять изменения, которые произошли в списках, использую session.Merge(), для того, чтобы эти списки правильно обрабатывались: в главную очередь - удалялись те элементы, которые пользователь удалил в UI.
Некоторое время работало так, как нужно, но потом начало выбрасываться исключение
NHibernate.HibernateException = "Unable to resolve property: _dt_shared"


Что делать, как заставить работать правильно?
Спасибо
4 июл 13, 09:25    [14520306]     Ответить | Цитировать Сообщить модератору
 Re: [NHibernate] Unable to resolve property: _{Namespace}  [new]
SolYUtor
Member

Откуда:
Сообщений: 948
_Novichok,

для начала выложить классы, маппинги, и код на котором валится ошибка.
4 июл 13, 09:44    [14520378]     Ответить | Цитировать Сообщить модератору
 Re: [NHibernate] Unable to resolve property: _{Namespace}  [new]
_Novichok
Member

Откуда:
Сообщений: 316
класс, описывающий объект:
    public class Assent
    {
        /*0)*/ public virtual string Id { get; set; }
        /*1)*/ public virtual Enterprise Enterprise { get; set; }
        /*2)*/ public virtual string WaterObjectName { get; set; }
        /*3)*/ public virtual IList<WaterUsePurposeSet> WaterUsePurposes { get; set; }
        /*4)*/ public virtual IList<WaterSourceSet> WaterSources { get; set; }
        /*5)*/ public virtual string WaterIntake { get; set; }
        /*6)*/ public virtual IList<Well> Wells { get; set; }
        /*7)*/ public virtual string FishProtectionConstructions { get; set; }
        /*8)*/ public virtual string SanitaryControl { get; set; }
        /*9)*/ public virtual IList<WaterConsumptionIndicatorSet> WaterConsumptionIndicatorSets { get; set; }
       /*10)*/ public virtual IList<WasteWaterIndicatorSet> WasteWaterIndicatorSets { get; set; }
       /*11)*/ public virtual string WaterUseRange { get; set; }
       /*12)*/ public virtual IList<OutletSet> OutletSets { get; set; }
       /*13)*/ public virtual string WasteWaterCleaning { get; set; }
       /*14)*/ public virtual IList<AccountingModeSet> AccountingModeSets { get; set; }
       /*15)*/ public virtual IList<Activity> Activities { get; set; }
       /*16)*/ public virtual IList<Condition> OtherConditions { get; set; }
       /*17)*/ public virtual IList<Agreement> Agreements { get; set; }
       /*18)*/ public virtual DateTime IssueDate { get; set; }
       /*19)*/ public virtual DateTime ValidityFromDate { get; set; }
       /*20)*/ public virtual DateTime ValidityToDate { get; set; }
       /*21)*/ public virtual string AssentNumber { get; set; }
       /*22)*/ public virtual IList<Document> Documents { get; set; }
    }

соответствующий мапинг:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="dt_shared"
                   namespace="dt_shared">
  <class name="dt_shared.Assent" lazy="false" table ="Assents">
    <id name="Id">
      <column name="AssentId" sql-type="int"/>
      <generator class="native"/>
    </id>
    <property name="WaterObjectName"  column="WaterObjectName"/>
    <property name="WaterIntake"      column="WaterIntake"/>
    <property name="FishProtectionConstructions" column="FishProtectionConstructions"/>
    <property name="SanitaryControl"  column="SanitaryControl"/>
    <property name="WaterUseRange"    column="WaterUseRange"/>
    <property name="WasteWaterCleaning" column="WasteWaterCleaning"/>
    <property name="AssentNumber"     column="AssentNumber"/>
    <property name="IssueDate"        column="IssueDate"/>
    <property name="ValidityFromDate" column="ValidityFromDate"/>
    <property name="ValidityToDate"   column="ValidityToDate"/>

    <many-to-one name="Enterprise" column="EnterpriseId"/>
    
    <bag name ="WaterUsePurposes" table="Assents_WaterusePurposes"  cascade="all-delete-orphan" lazy="false">
      <key column="AssentId" not-null="true"/>
      <one-to-many class="WaterUsePurposeSet"/>
    </bag>

    <bag name="WaterSources" table="Assents_WaterSources" cascade="all-delete-orphan" lazy="false">
      <key column="AssentId" not-null="true"/>
      <one-to-many class="WaterSourceSet"/>
    </bag>

    <bag name="Wells" table="Wells" cascade="all-delete-orphan" lazy="false">
      <key column="AssentId" not-null="true"/>
      <one-to-many class="Well"/>
    </bag>

    <bag name="WaterConsumptionIndicatorSets" table="WaterConsumptionIndicators_Values" cascade="all-delete-orphan" lazy="false" >
      <key column="AssentId" not-null="true"/>
      <one-to-many class="WaterConsumptionIndicatorSet"/>
    </bag>
    
    <bag name="WasteWaterIndicatorSets" table="WastewaterIndocators_Values" cascade="all-delete-orphan" lazy="false" >
      <key column="AssentId" not-null="true"/>
      <one-to-many class="WasteWaterIndicatorSet"/>
    </bag>

    <bag name="OutletSets" table="Assent_Outlets" cascade="all-delete-orphan" lazy="false">
      <key column="AssentId" not-null="true"/>
      <one-to-many class="OutletSet"/>
    </bag>

    <bag name="AccountingModeSets" table="Sources_AccountingModes" cascade="all-delete-orphan" lazy="false">
      <key column="AssentId" not-null="true"/>
      <one-to-many class="AccountingModeSet"/>
    </bag>

    <bag name="Activities" table="Activities" cascade="all-delete-orphan" lazy="false">
      <key column="AssentId" not-null="true"/>
      <one-to-many class="Activity"/>
    </bag>

    <bag name="OtherConditions" table="Assents_Conditions" cascade="all-delete-orphan" lazy="false">
      <key column="AssentId" not-null="true"/>
      <one-to-many class="Condition"/>
    </bag>
    
    <bag name="Agreements" table="Agreements" cascade="all-delete-orphan" lazy="false">
      <key column="AssentId" not-null="true"/>
      <one-to-many class="Agreement"/>
    </bag>

    <bag name="Documents" table="Assents_Documents" cascade="all-delete-orphan" lazy="false">
      <key column="AssentId" not-null="true"/>
      <one-to-many class="Document"/>
    </bag>
    
  </class>
</hibernate-mapping>

класс, взаимодействующий с БД:
    public class Proxy
    {
        public Assent RegisterAssent(Assent assent)
        {
            if (assent != null)
                using (var session = GetSessionFactory().OpenSession())
                {
                    using (var tx = session.BeginTransaction())
                    {
                        try
                        {
                            if (assent.Enterprise != null)
                            {
                                var retrievedEnterprise = RegisterEnterprise(assent.Enterprise);
                                assent.Enterprise = retrievedEnterprise;
                                assent = session.Merge<Assent>(assent); // тут вываливается исключение
                                tx.Commit();
                            }
                        }
                        catch (Exception ex)
                        {
                            throw new Exception("Помилка при збереженні дозволу");
                        }
                    }
                }
            return assent;
        }
    }

причем исключение вываливается, когда изменяется список элементов какого-то из поля
4 июл 13, 14:57    [14522716]     Ответить | Цитировать Сообщить модератору
 Re: [NHibernate] Unable to resolve property: _{Namespace}  [new]
_Novichok
Member

Откуда:
Сообщений: 316
Up
6 июл 13, 00:38    [14530498]     Ответить | Цитировать Сообщить модератору
 Re: [NHibernate] Unable to resolve property: _{Namespace}  [new]
SolYUtor
Member

Откуда:
Сообщений: 948
_Novichok,

Странно, странно. Всё-таки поищите в своих маппингах слово _dt_shared. Уже очень похоже на описку при маппинге какого-либо объекта. И почему-то мне кажется, это проблема в классе Enterprise.
8 июл 13, 09:54    [14534146]     Ответить | Цитировать Сообщить модератору
 Re: [NHibernate] Unable to resolve property: _{Namespace}  [new]
_Novichok
Member

Откуда:
Сообщений: 316
Да не, исключение вываливается, когда к какой-то из коллекций добавился новый элемент.
dt_shared (без нижнего подчеркивания) - это проект в солюшене, который отвечает за взаимодействие с БД. Соответственно, нейспейс по-умолчанию - dt_shared. А нижнее подчеркивание добавляет сам фреймворк, когда вываливает исключение.
Люди уже стыкались с этой проблемой

Все дело в коллекциях.
Когда ничего не изменять - все работает.
Когда удалил какой-то элемент из списка - работает.
Когда добавился новый элемент в одну из коллекций (неважно в какую) - выдает данное исключение.

В документации про метод Merge() сказано следующее:
http://www.nhforge.org/doc/nh/en/index.html#manipulatingdata-updating-detached
This method copies the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. The method returns the persistent instance. If the given instance is unsaved or does not exist in the database, NHibernate will save it and return it as a newly persistent instance. Otherwise, the given instance does not become associated with the session. In most applications with detached objects, you need both methods, SaveOrUpdate() and Merge().

Меня заинтересовала такая строчка:
In most applications with detached objects, you need both methods, SaveOrUpdate() and Merge().

Действительно, когда добавился элемент в коллекцию - при использовании SaveOrUpdate() - работает. Но он не удаляет из БД элементы, которые были пользователем удалены.
Вместо него это делает Merge(). Но он не добавляет в БД элементы, которые были добавлены пользователем.
Причем, может быть такая ситуация, когда из одной коллекции элементы были удалены, а в другую добавлены. Или в одной коллекции какие-то элементы удалены, а какие-то новые добавлены.

Возникает вопрос: как же использовать SaveOrUpdate() и Merge() вместе?
8 июл 13, 20:17    [14538399]     Ответить | Цитировать Сообщить модератору
 Re: [NHibernate] Unable to resolve property: _{Namespace}  [new]
_Novichok
Member

Откуда:
Сообщений: 316
Кому надо будет, решил проблему следующим способом (иногда все-таки надо читать документацию :) ):

public Assent RegisterAssent(Assent assent)
        {
            Assent persistedAssent = null;
            if (assent != null)
            {
                Assent assentToPersist = assent.CreateCopy(); // создается полная копия объекта
                if (assentToPersist != null)
                {
                    try
                    {
                        using (var session = GetSessionFactoryFluently().OpenSession())
                        using (var tx = session.BeginTransaction())
                        {
                            if (assentToPersist.Enterprise != null)
                            {
                                session.SaveOrUpdate(assentToPersist.Enterprise); 
                                if (assentToPersist.Enterprise.Id != 0)
                                {
                                    session.SaveOrUpdate(assentToPersist); // тут сохраняются добавленные элементы коллекций
                                    tx.Commit();
                                }
                            }
                        }
                        using (var session = GetSessionFactoryFluently().OpenSession())
                        using (var tx = session.BeginTransaction())
                        {
                            persistedAssent = session.Merge<Assent>(assent); // тут удаляются из БД удаленные элементы коллекций
                            tx.Commit();
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Помилка при збереженні дозволу");
                    }
                }
            }
            return persistedAssent;
        }

При чем важно делать это в разных сессиях. Возможно как-то можно очищать сессию, но пока я над этим не заморачиваюсь.
9 июл 13, 15:28    [14541880]     Ответить | Цитировать Сообщить модератору
 Re: [NHibernate] Unable to resolve property: _{Namespace}  [new]
_Novichok
Member

Откуда:
Сообщений: 316
session.Evict(Object obj) - метод который удаляет экземпляр obj из кеша сессии.
есть еще метод session.Clear(), который полностью очищает сессию, удаляя все загруженные экземпляры и изменения, ожидающие сохранения
16 июл 13, 12:07    [14572291]     Ответить | Цитировать Сообщить модератору
Все форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM Ответить