Castle Active Record - объект ссылается на несохраненный временный экземпляр - PullRequest
0 голосов
/ 02 ноября 2011

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

Сначала я создал несколько компонентов:

[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=test\sqlexpress;Initial Catalog=TEST_AR_POKEC;Integrated Security=SSPI" />
  </config>

</activerecord>

Finnaly я тестировал:

    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();

Закончено с этой ошибкой:

ProxyFactoryFactory не был настроен. инициализировать свойство proxyfactory.factory_class фабрики сеансов раздел конфигурации с одним из доступных NHibernate.ByteCode провайдеры.

Я гуглю и думаю, что нашел aswer. Я изменил конфигурацию xml для активной записи. Я добавил эту часть:

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

Я снова проверил. Он создал таблицы в БД, но при этом данные не вставлялись в таблицы, и я получил эту ошибку:

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

Вот StackTrace:

в NHibernate.Engine.ForeignKeys.GetEntityIdentifierIfNotUnsaved (String entityName, Object entity, сеанс ISessionImplementor) в NHibernate.Type.EntityType.GetIdentifier (Значение объекта, ISessionImplementor session) в NHibernate.Type.ManyToOneType.IsDirty (Объект старый, Текущий объект, Boolean [] проверяемый, сеанс ISessionImplementor) в NHibernate.Type.TypeHelper.FindDirty (свойства StandardProperty [], Object [] currentState, Object [] previousState, Boolean [] [] includeColumns, Boolean anyUninitializedProperties, ISessionImplementor session) в NHibernate.Persister.Entity.AbstractEntityPersister.FindDirty (Object [] currentState, Object [] previousState, Object, ISessionImplementor session) в NHibernate.Event.Default.DefaultFlushEntityEventListener.DirtyCheck (FlushEntityEvent событие) в NHibernate.Event.Default.DefaultFlushEntityEventListener.IsUpdateNecessary (FlushEntityEvent событие, Boolean mightBeDirty) в NHibernate.Event.Default.DefaultFlushEntityEventListener.OnFlushEntity (FlushEntityEvent событие) в NHibernate.Event.Default.AbstractFlushingEventListener.FlushEntities (FlushEvent событие) в NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions (FlushEvent событие) в NHibernate.Event.Default.DefaultFlushEventListener.OnFlush (FlushEvent событие) в NHibernate.Impl.SessionImpl.Flush () в Castle.ActiveRecord.Framework.SessionFactoryHolder.ReleaseSession (ISession сеанс) в Castle.ActiveRecord.ActiveRecordBase.InternalCreate (экземпляр объекта, Boolean flush) в Castle.ActiveRecord.ActiveRecordBase.Create (экземпляр объекта) в Castle.ActiveRecord.ActiveRecordBase.Create () в SAMPLE_1.Program.Main (String [] args) в E: \ C # PROJECTS \ STUDY \ STUDY.ORM \ Active Record \ SAMPLE_1 \ Program.cs: строка 51
в System.AppDomain._nExecuteAssembly (сборка RuntimeAssembly, String [] args) в System.AppDomain.ExecuteAssembly (String AssemblyFile, Свидетельство AssemblySecurity, String [] args) в Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly ()
в System.Threading.ThreadHelper.ThreadStart_Context (состояние объекта)
в System.Threading.ExecutionContext.Run (ExecutionContext executeContext, ContextCallback обратный вызов, состояние объекта, логическое значение ignoreSyncCtx) в System.Threading.ExecutionContext.Run (ExecutionContext executeContext, обратный вызов ContextCallback, состояние объекта) в System.Threading.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 Ответ

0 голосов
/ 02 ноября 2011

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

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

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

ISession.Save(user);

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

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