Skip to content

"No persister for: NhibernateTest.Entities.CustomDateType" When performing a query for the 2nd time #3669

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
pietje666 opened this issue Apr 16, 2025 · 0 comments

Comments

@pietje666
Copy link

Hi,
In my current project when updating NHibernate i seem to stumble upon an issue.
I am having the following issue, which i have been able to reproduce in a very small test project .
When performing the folowing select statement for the 2nd time gives an error "No persister for: NhibernateTest.Entities.CustomDateType". The folowing code seems to work using NHibernate Version 5.3.20 and seems to break from version 5.4.x and onwards. Trying to debug the problem myself it seems to be related with setting the "ExpectedType" to the wrong type. First time it resolves as "CustomType", second time it resolves to a "ManytoOneType" which leads to the issue. Is there any fix to this issue or any tips how to resolve this?

        [HttpGet(Name = "GetProducts")]
        public async Task<IEnumerable<ProductsDto>> Get()
        {
            var nothing = (CustomDateType?)null;

            var products = await _session.Query<Product>().Where(x => x.ValidityPeriod.Until >= nothing).ToListAsync();

            //the folowing line gives NHibernate.MappingException: 'No persister for: NhibernateTest.Entities.CustomDateType'
            var products2 = await _session.Query<Product>().Where(x => x.ValidityPeriod.Until >= nothing).ToListAsync();

            return products.Select(x => new ProductsDto
            {
                Id = x.Id,
                Name = x.Name
            }).ToList();
        }
    }

The Product class has a limited amount of properties, but also has a ValidityPeriod class which is stored in the database as ValidFrom ValidUntil column.

    public class Product
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual ValidityPeriod ValidityPeriod { get; set; }

    }

    public class  ValidityPeriod
    {
        public virtual CustomDateType From { get; set; }
        public virtual CustomDateType? Until { get; set; }
    }  

The From and Until are being represented by a Custom Type and therefore we implement the IUserType interface

public class CustomDateTypeUserType : IUserType
{
    public bool IsMutable { get; } = false;

    public Type ReturnedType => typeof(CustomDateType);

    public SqlType[] SqlTypes { get; } = { new DateSqlType() };

    public object NullSafeGet(DbDataReader rs, string[] names, ISessionImplementor session, object owner)
    {
        var dateTime = (DateTime?)NHibernateUtil.Date.NullSafeGet(rs, names, session);
        return dateTime.HasValue ? new CustomDateType(dateTime.Value) : null;
    }

    public void NullSafeSet(DbCommand cmd, object value, int index, ISessionImplementor session)
    {
        var date = (CustomDateType?)value;
        NHibernateUtil.Date.NullSafeSet(cmd, date?.DateTime, index, session);
    }
    public object DeepCopy(object value)
    {
        var input = (CustomDateType)value;

        return value == null ? (object)null : DoDeepCopy(input);
    }
    public object Assemble(object cached, object owner)
    {
        return DeepCopy(cached);
    }

    public object Disassemble(object value)
    {
        return DeepCopy(value);
    }

    public object Replace(object original, object target, object owner)
    {
        return DeepCopy(original);
    }

    public new bool Equals(object x, object y)
    {
        if (ReferenceEquals(x, y))
            return true;

        if (x == null || y == null)
            return false;

        return x.Equals(y);
    }

    public int GetHashCode(object x)
    {
        return x.GetHashCode();
    }

    public virtual CustomDateType DoDeepCopy(CustomDateType value)
    {
        return value;
    }
}

[Serializable]
public class DateSqlType : SqlType
{
    /// <summary>
    /// Initializes a new instance of the <see cref="DateSqlType" /> class.
    /// </summary>
    public DateSqlType()
        : base(DbType.Date)
    {
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant