Коллекции Nhibernate. Дети не сохраняются - PullRequest
3 голосов
/ 07 июля 2019

Использование

.NET Core SDK (отражает любой global.json): Версия: 2.2.300 Совершить: 73efd5bd87

и

Nhibernate 5.2.5

Имеют следующие объекты

public class Customer : Entity {
    public Customer() {
        Initialize();
    }
    public virtual string Name { get; set; }
    public virtual string LegalName { get; set; }
    public virtual string VATCode { get; set; }
    public virtual ICollection<Site> Sites { get; set; }
    public virtual DateTime Created { get; set; } = DateTime.UtcNow;

    private void Initialize() {
        Sites = new List<Site>();
    }
}

public class Site : Entity {
    public virtual string Address { get; set; }
    public virtual string City { get; set; }
    public virtual string Country { get; set; }
    public virtual Customer Customer { get; set; }
}

со следующими мапперами

internal class CustomerConfiguration : ClassMapping<Customer> {
    public CustomerConfiguration() {
        Table( TableNames.CustomersTable );

        Id( x => x.EntityID, im => {
            im.Column( "CustomerID" );
            im.Generator( Generators.Identity );
        } );
        [... code omitted for brevity ...]
        Set<Site>( property => property.Sites,
            collection => {
                collection.Fetch( CollectionFetchMode.Join );
                collection.Lazy( CollectionLazy.Lazy );
                collection.Cascade( Cascade.Persist.Include( Cascade.DeleteOrphans ) );
                collection.Inverse( true );
                collection.Key( keyMapping => {
                    keyMapping.Column( "CustomerID" );
                } );
            },
            mapping => {
                mapping.OneToMany( relationalMapping => {
                    relationalMapping.Class( typeof( Site ) );
                } );
            } );
    }
}

internal class SiteConfiguration : ClassMapping<Site> {
    public SiteConfiguration() {
        Table( TableNames.SitesTable );

        Id( x => x.EntityID, im => {
            im.Column( "SiteID" );
            im.Generator( Generators.Identity );
        } );
        [... code omitted for brevity ...]
        ManyToOne( x => x.Customer, mm => {
            mm.Column( "CustomerID" );
            mm.NotNullable( true );
        } );
    }
}

Полагаю, это отображение неверно, потому что если я сделаю что-то вроде

using ( var session = sessionFactory.OpenSession() ) {
    var customer = new Customer() {
        Name = $"Customer 1",
        LegalName = $"Customer 1 LLC",
        VATCode = "xxxxxxxxx",
        Created = DateTime.UtcNow
    };
    customer.Sites.Add( new Site() {
        Address = $"Address Customer 1",
        City = $"City Customer 1",
        Country = $"Country Customer 1",
        Customer = customer
    } );
    session.Save( customer );
}

я получаю следующее исключение

Необработанное исключение: NHibernate.TransientObjectException: объект ссылается на несохраненный временный экземпляр - сохраните временный экземпляр перед сбросом или задайте каскадное действие для свойства, которое сделает его автоматически сохраненным. Тип: Nhibernate.ConsoleApp.Entities.Site, Объект: [Сайт 0]

Есть предложения?

EDIT

На самом деле проблема была в другой области. это было из-за присутствия двух зарегистрированных слушателей (IDeleteEventListener и IUpdateEventListener). Всякий раз, когда я добавляю те Обновление и удаление не работает. Однако мне удалось обнаружить проблему благодаря Роману Артюхину комментарий

Ответы [ 2 ]

2 голосов
/ 12 июля 2019

Исключением является , говорящее , что корневая сущность Customer содержит ссылку на другую (Site) сущность, которая является временной сущностью. Вот почему корневая сущность не может быть сохранена.

Сценарий 1: параметры каскада не настроены.
В этом случае дочерние или ссылочные объекты должны быть сохранены первыми.

using ( var session = sessionFactory.OpenSession() ) {
    var customer = new Customer() {
        Name = $"Customer 1",
        LegalName = $"Customer 1 LLC",
        VATCode = "xxxxxxxxx",
        Created = DateTime.UtcNow
    };
    Site site = new Site() {
        Address = $"Address Customer 1",
        City = $"City Customer 1",
        Country = $"Country Customer 1",
        Customer = customer
    }
    customer.Sites.Add(site);
    session.Save( customer );//<--Save the master
    session.Save( site );//<--Save the site
    ...
    ...
    ...
    session.Flush();//<--You are calling this somewhere in your code
}

Это должно сработать.

Сценарий 2: параметры каскада не были настроены для всех входных данных; Операции ОБНОВЛЕНИЕ или УДАЛЕНИЕ.
В этом случае необходимо изменить конфигурацию или сначала сохранить дочерние или ссылочные объекты.

Вы уже:

  • набор collection.Inverse( true );
  • добавлены оба значения DeleteOrphans | Persist для Cascade через метод расширения Include.

так что это не проблема.

Сценарий 3: Связанные временные объекты, которые были созданы и связаны с постоянным объектом, но с этими объектами операция сохранения не должна выполняться.
В этом случае обучающие объекты должны быть отсоединены от текущего сеанса с помощью команды: ISession.Evict(obj)

Вместо Evict вы можете вызвать Save, чтобы явно прикрепить эти объекты, как указано выше.

Для получения более подробной информации, посмотрите документацию , которая объясняет различные стратегии.

1 голос
/ 12 июля 2019

Я думаю, что коллекция не ваша проблема. Кажется, у вас есть объект Site где-то еще (например, свойство многие-к-одному customer.LastSite или что-то в этом роде). И каскадная логика натыкается на это еще не сохраненное свойство Site перед сохранением коллекции. Поэтому вы должны убедиться, что другие свойства Site также имеют Cascade.Persist отображение

...