Skip to content

Cascade delete-orphan on no-proxy null association fails #1719

Closed
@fubar-coder

Description

@fubar-coder

It seems that there is a problem with one-to-one relations or my mapping.

Exception:

Exception occurred getter of TestNhBug.FileEntry.Id
NHibernate.PropertyAccessException: Exception occurred getter of TestNhBug.FileEntry.Id ---> System.Reflection.TargetException: Non-static method requires a target.
   at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
   at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
   at NHibernate.Properties.BasicPropertyAccessor.BasicGetter.Get(Object target)
   --- End of inner exception stack trace ---
   at NHibernate.Properties.BasicPropertyAccessor.BasicGetter.Get(Object target)
   at NHibernate.Tuple.Entity.AbstractEntityTuplizer.GetIdentifier(Object entity)
   at NHibernate.Persister.Entity.AbstractEntityPersister.IsTransient(Object entity, ISessionImplementor session)
   at NHibernate.Engine.ForeignKeys.IsTransientFast(String entityName, Object entity, ISessionImplementor session)
   at NHibernate.Engine.ForeignKeys.IsTransientSlow(String entityName, Object entity, ISessionImplementor session)
   at NHibernate.Event.Default.DefaultDeleteEventListener.OnDelete(DeleteEvent event, ISet`1 transientEntities)
   at NHibernate.Impl.SessionImpl.FireDelete(DeleteEvent event, ISet`1 transientEntities)
   at NHibernate.Impl.SessionImpl.Delete(String entityName, Object child, Boolean isCascadeDeleteEnabled, ISet`1 transientEntities)
   at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything)
   at NHibernate.Event.Default.AbstractFlushingEventListener.CascadeOnFlush(IEventSource session, IEntityPersister persister, Object key, Object anything)
   at NHibernate.Event.Default.AbstractFlushingEventListener.PrepareEntityFlushes(IEventSource session)
   at NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent event)
   at NHibernate.Event.Default.DefaultAutoFlushEventListener.OnAutoFlush(AutoFlushEvent event)
   at NHibernate.Impl.SessionImpl.AutoFlushIfRequired(ISet`1 querySpaces)
   at NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results, Object filterConnection)
   at NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results)
   at NHibernate.Impl.AbstractSessionImpl.List(IQueryExpression queryExpression, QueryParameters parameters)
   at NHibernate.Impl.AbstractQueryImpl2.List()
   at NHibernate.Linq.DefaultQueryProvider.ExecuteQuery(NhLinqExpression nhLinqExpression, IQuery query, NhLinqExpression nhQuery)
   at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
   at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
   at System.Linq.Queryable.Single[TSource](IQueryable`1 source, Expression`1 predicate)
   at TestNhBug.Program.GetOrCreateEntry(ISession session, FileEntry parent, String name, Byte[] data) in c:\users\markjunker\source\repos\TestNhBug\TestNhBug\Program.cs:line 99
   at TestNhBug.Program.Main(String[] args) in c:\users\markjunker\source\repos\TestNhBug\TestNhBug\Program.cs:line 36

This are my mappings:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping
        assembly="TestNhBug"
        namespace="TestNhBug"
        xmlns="urn:nhibernate-mapping-2.2">
  <class name="FileEntry" table="filesystementries">
    <id name="Id" column="id" generator="assigned" />
    <property name="ParentId" column="parent_id" />
    <property name="Name" column="name" length="50" not-null="true" />
    <one-to-one name="Data" lazy="no-proxy" cascade="all-delete-orphan" />
  </class>
  <class name="FileData" table="filesystementrydata">
    <id name="Id" column="id">
      <generator class="foreign">
        <param name="property">Entry</param>
      </generator>
    </id>
    <property name="Data" column="data" not-null="true" type="BinaryBlob" lazy="true" />
    <one-to-one name="Entry" lazy="no-proxy" constrained="true" foreign-key="fk_data_entry" />
  </class>
</hibernate-mapping>

This is my test application:

using System;
using System.Linq;
using System.Text;

using NHibernate;

namespace TestNhBug
{
    class Program
    {
        private static readonly Guid RootGuid = Guid.Parse("00000000-0000-0000-0000-000000000001");

        static void Main(string[] args)
        {
            var connectionString = @"Data Source=(LocalDb)\MSSQLLocalDB;Integrated Security=SSPI";
            var cfg = new NHibernate.Cfg.Configuration();
            cfg.SetProperty(NHibernate.Cfg.Environment.Dialect, "NHibernate.Dialect.MsSql2012Dialect");
            cfg.SetProperty(NHibernate.Cfg.Environment.ConnectionString, connectionString);
            cfg.AddAssembly(typeof(FileData).Assembly);

            var updater = new NHibernate.Tool.hbm2ddl.SchemaUpdate(cfg);
            updater.Execute(true, true);

            try
            {
                using (var sf = cfg.BuildSessionFactory())
                {
                    using (var session = sf.OpenSession())
                    {
                        using (var trans = session.BeginTransaction())
                        {
                            var rootEntry = GetOrCreateRootEntry(session);
                            GetOrCreateEntry(session, rootEntry, "text1.txt",
                                Encoding.UTF8.GetBytes("text1"));
                            var subEntry = GetOrCreateEntry(session, rootEntry, "test1");
                            GetOrCreateEntry(session, subEntry, "text1.txt",
                                Encoding.UTF8.GetBytes("text1 below test1"));

                            trans.Commit();
                        }
                    }
                }

                using (var sf = cfg.BuildSessionFactory())
                {
                    using (var session = sf.OpenSession())
                    {
                        using (var trans = session.BeginTransaction())
                        {
                            var entry = GetForPath(session, "test1", "text1.txt");

                            session.Delete(entry);
                            trans.Commit();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex);
            }
        }

        private static FileEntry GetForPath(ISession session, params string[] path)
        {
            var found = session.Load<FileEntry>(RootGuid);
            foreach (var pathPart in path)
            {
                var next = session.Query<FileEntry>()
                    .Single(x => x.ParentId == found.Id && x.Name == pathPart);
                found = next;
            }

            return found;
        }

        private static FileEntry GetOrCreateRootEntry(ISession session)
        {
            var entry = session.Get<FileEntry>(RootGuid);

            if (entry != null)
                return entry;

            entry = new FileEntry()
            {
                Id = RootGuid,
                Name = string.Empty,
            };

            session.Save(entry);

            session.Flush();

            return entry;
        }

        private static FileEntry GetOrCreateEntry(ISession session, FileEntry parent, string name, byte[] data = null)
        {
            var entry = session.Query<FileEntry>()
                .SingleOrDefault(x => x.Name == name && x.ParentId == parent.Id);
            if (entry != null)
                return entry;

            entry = new FileEntry()
            {
                Id = Guid.NewGuid(),
                ParentId = parent.Id,
                Name = name,
            };

            FileData fileData;
            if (data != null)
            {
                fileData = new FileData
                {
                    Entry = entry,
                    Data = data,
                };

                entry.Data = fileData;
            }
            else
            {
                fileData = null;
            }

            session.Save(entry);

            if (fileData != null)
            {
                session.Save(fileData);
            }

            session.Flush();

            return entry;
        }
    }

    public class FileData
    {
        public virtual Guid Id { get; set; }
        public virtual byte[] Data { get; set; }
        public virtual FileEntry Entry { get; set; }
    }

    public class FileEntry
    {
        public virtual Guid Id { get; set; }
        public virtual Guid? ParentId { get; set; }
        public virtual string Name { get; set; }
        public virtual FileData Data { get; set; }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions