Блокировка активной записи — объекта ссылается на несохраненный временный экземпляр

#nhibernate #configuration #castle-activerecord

#nhibernate #конфигурация #замок-activerecord

Вопрос:

Привет, это моя первая попытка с активной записью, я использую учебник с официального веб-сайта.

Сначала я создал некоторые правила:

 [ActiveRecord("Users")]
public class User : ActiveRecordBase<User>
{
    private IList<PhotoAlbum> _albums = new List<PhotoAlbum>();

    [PrimaryKey]
    public virtual int UserId { get; set; }

    [BelongsTo("ProfilId")]
    public virtual Profil Profil { get; set; }

    [HasMany(typeof(PhotoAlbum),Table = "PhotoAlbums",
        ColumnKey = "UserId", 
        Cascade = ManyRelationCascadeEnum.AllDeleteOrphan)]
    public IList<PhotoAlbum> Album
    {
        get { return _albums; }
        set { _albums = value; }
    }

    [Property]
    public virtual string AzetId { get; set; }
    [Property]
    public virtual string Nick { get; set; }
    [Property]
    public virtual string SelfNick { get; set; }
}

[ActiveRecord("Profiles")]
public class Profil : ActiveRecordBase<Profil>
{
    [PrimaryKey]
    public int ProfilId { get; set; }

    [Property]
    public int Age { get; set; }
    [Property]
    public int Sex { get; set; }
    [Property]
    public string Region { get; set; }
    [Property]
    public string Town { get; set; }
    [Property]
    public bool WithPhoto { get; set; }
    [Property]
    public bool HasPhotoAlbum { get; set; }
}

[ActiveRecord("PhotoAlbums")]
public class PhotoAlbum : ActiveRecordBase<PhotoAlbum>
{
    [PrimaryKey]
    public int PhotoAlbumId { get; set; }

    [Property]
    public string Name { get; set; }
    [Property]
    public int NumberOfPhoto { get; set; }
}
  

Затем я создал файл конфигурации xml для активной записи:

 <activerecord>
  <config>
    <add
      key="hibernate.connection.driver_class"
      value="NHibernate.Driver.SqlClientDriver" />
    <add
      key="dialect"
      value="NHibernate.Dialect.MsSql2008Dialect" />
    <add
      key="connection.provider"
      value="NHibernate.Connection.DriverConnectionProvider" />
    <add
      key="connection.connection_string"
      value="Data Source=testsqlexpress;Initial Catalog=TEST_AR_POKEC;Integrated Security=SSPI" />
  </config>

</activerecord>
  

Наконец, я протестировал:

     public static User GetUser(string nick, int sex,
        string loc)
    {
        return new User
        {
            AzetId = new Random().Next()
            .ToString(),
            Nick = nick,
            SelfNick = nick.ToUpper(),
            Profil = new Profil()
            {
                Sex = sex,
                Region = loc,
                WithPhoto = true,
                Age = new Random().Next(6, 99),
                HasPhotoAlbum = true,
                Town = loc
            },
            Album = new List<PhotoAlbum>
                                         {
                                             new PhotoAlbum
                                                 {
                                                     Name = "Me",
                                                     NumberOfPhoto =new Random().Next()
                                                 }
                                         }

        };
    }


        var source = new XmlConfigurationSource("ac.xml");

        ActiveRecordStarter.Initialize(source,typeof(Profil),typeof(PhotoAlbum), typeof(User));
        ActiveRecordStarter.CreateSchema();

        var user = GetUser("tom",1,"DC");
        user.Create();
  

Он завершился с этой ошибкой:

The ProxyFactoryFactory was not configured. Initialize
‘proxyfactory.factory_class’ property of the session-factory
configuration section with one of the available NHibernate.ByteCode
providers.

I google it and I think I found aswer I modified xml config for active record I added this part:

  <add
      key="proxyfactory.factory_class"
      value="NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle"/>
  

I tested again. It created tabels in DB but this didn’t insert data to tables and I got this error:

object references an unsaved transient instance — save the transient
instance before flushing.

Here is StackTrace :

в NHibernate.Движок.Внешние ключи.GetEntityIdentifierIfNotUnsaved(строковое имя объекта, объект объекта, ISessionImplementor session) в NHibernate.Type.EntityType .Получите идентификатор (значение объекта, ISessionImplementor session) в NHibernate.Type.ManyToOneType .IsDirty(объект старый, объект текущий, логическое значение [] проверяется, ISessionImplementor session) в NHibernate.Type.TypeHelper .Найдите dirty(StandardProperty[] properties, Object[] currentState, Object[] previousState, Boolean[][] includeColumns, Boolean anyUninitializedProperties, ISessionImplementor session) в NHibernate.Сохраняется.Сущность.AbstractEntityPersister .Найдите dirty(объект[] currentState, объект[] previousState, объект entity, ISessionImplementor session) в NHibernate.Событие.По умолчанию.DefaultFlushEntityEventListener.DirtyCheck(событие FlushEntityEvent) в NHibernate.Событие.По умолчанию.DefaultFlushEntityEventListener.IsUpdateNecessary(событие FlushEntityEvent, логическое значение mightBeDirty) в NHibernate.Событие.По умолчанию.DefaultFlushEntityEventListener.OnFlushEntity(событие FlushEntityEvent) в NHibernate.Событие.По умолчанию.AbstractFlushingEventListener .FlushEntities(событие FlushEvent) в NHibernate.Событие.По умолчанию.AbstractFlushingEventListener .FlushEverythingToExecutions(событие FlushEvent) в NHibernate.Событие.По умолчанию.DefaultFlushEventListener.onFlush(событие FlushEvent) в NHibernate.Impl.SessionImpl.Сброс () в замке.ActiveRecord.Фреймворк.SessionFactoryHolder.ReleaseSession(сеанс ISession) в замке.ActiveRecord.ActiveRecordBase.InternalCreate(экземпляр объекта, логический сброс) в замке.ActiveRecord.ActiveRecordBase.Создайте (экземпляр объекта) в замке.ActiveRecord.ActiveRecordBase.Create() в SAMPLE_1 .Program.Main(строка [] аргументов) в E:C# PROJECTSSTUDYSTUDY.ORM Active RecordSAMPLE_1Program.cs: строка 51
в System.AppDomain._nExecuteAssembly(сборка RuntimeAssembly, строка [] аргументы) в системе.AppDomain.Выполните сборку (String assemblyFile, Evidence assemblySecurity, String[] args) в Microsoft.VisualStudio.Процесс хостинга.HostProc.RunUsersAssembly()
в системе.Многопоточность.ThreadHelper.ThreadStart_Context(состояние объекта)
в системе.Многопоточность.ExecutionContext.Run(ExecutionContext ExecutionContext, обратный вызов ContextCallback, состояние объекта, логическое игнорирование SyncCtx) в системе.Многопоточность.ExecutionContext.Run(ExecutionContext ExecutionContext, обратный вызов ContextCallback, состояние объекта) в системе.Многопоточность.ThreadHelper.ThreadStart()

Возможно, проблема здесь:

 [BelongsTo("ProfilId")]
public virtual Profil Profil { get; set; }
  

и

 [HasMany(typeof(PhotoAlbum),Table = "PhotoAlbums",
    ColumnKey = "UserId", 
    Cascade = ManyRelationCascadeEnum.AllDeleteOrphan)]
public IList<PhotoAlbum> Album
{
    get { return _albums; }
    set { _albums = value; }
}
  

Я не уверен, но если я опустил эти два свойства (отношения), это работает хорошо, и данные вставляются в таблицу. Но с отношениями не работает.

ОТРЕДАКТИРОВАНО:

Если я указал каскадное поведение, оно работает…но почему?

    [BelongsTo("ProfilId", 
        Cascade =CascadeEnum.All)]
    public virtual Profil Profil { get; set; }

    [HasMany(typeof(PhotoAlbum), 
        Table = "PhotoAlbums",
        ColumnKey = "UserId",
        Cascade = ManyRelationCascadeEnum.All)]
    public IList<PhotoAlbum> Album
    {
        get { return _albums; }
        set { _albums = value; }
    }
  

Ответ №1:

Если вы не хотите Profile , чтобы он автоматически сохранялся вместе с вашим User объектом ( CascadeEnum.All ), вы должны сохранить этот объект отдельно в своем сеансе перед сохранением вашего User .

Причина, по которой он выдает это исключение, когда каскадирование не включено, заключается в том, что ваш Profile объект внутри вашего User is transient (не сохранен). Если вы включите каскадирование, он автоматически сохранит ваш объект и, следовательно, НЕ transient будет.

Пример с каскадированием

 ISession.Save(user);
  

Пример без каскадирования

 ISession.Save(profile);
Isession.Save(user);