>From what I can tell, this is so far doing the right thing from an Equals 
perspective. We prefer to see the primitive P type by default, but 
apparently can also see the returned R type, so normalize accordingly.

protected virtual bool Equals(P x, P y) => x is IEquatable<P> xe && y is 
IEquatable<P> ye && xe.Equals(ye);

public virtual new bool Equals(object x, object y)
{
    object Normalize(object value) => value switch
    {
        DBNull or null => DBNull.Value,
        P p => p,
        R r => Disassemble(r),
        _ => throw new InvalidOperationException($"Unexpected value type: 
'{value.GetType().FullName}'.")
    };

    var (xnorm, ynorm) = (Normalize(x), Normalize(y));

    return (xnorm is null && ynorm is null)
        || (xnorm is DBNull && ynorm is DBNull)
        || ReferenceEquals(x, y)
        || (xnorm is P xp && ynorm is P yp && Equals(xp, yp));
}

Another concern is getting the hash code; ostensibly we think this may 
suffer from the same P versus R behavior patterns as Equals exhibits. 
Initially taking the naive approach that we are expecting the primitive P 
type and that's it. But wondering if we might also see the returned R type 
there as well.

protected virtual int GetHashCode(P p) => p?.GetHashCode() ?? default;

public virtual int GetHashCode(object x) => x is P p ? GetHashCode(p) : 
throw new InvalidOperationException(
    $"Value {(x is null ? "null" : $"{x}")} of the incorrect type: '{(x is 
null ? "null" : typeof(P).FullName)}'"
);

Taking a step back from equality and hash codes, could that perhaps be an 
indication that one of the cache directions may be assembling or 
disassembling a value somehow incorrectly, perhaps? Which is entirely 
possible; although overall we went to some lengths to ensure that the 
diretion was properly, from database assemble, and to database disassemble.

Thoughts? Anyone?
On Friday, July 25, 2025 at 11:46:28 PM UTC-4 Michael W Powell wrote:

> The docs as do the comments claim Equals compares the _persistent state_ 
> which I take to mean the PRIMITIVE (P) type.
>
> Take for instance, we have a DECIMAL database mapping, to a CLR UINT64 in 
> the apporpriate scale and precision.
>
> Equals is not seeing DECIMAL, which I would expect, but rather, UINT64. 
> Which is part and partial my confusion over this issue.
>
> In the following base implementation, assuming NH docs, comments, etc, are 
> accurate, then this should never throw. But it is throwing, because object 
> value is UINT64.
>
> public virtual new bool Equals(object x, object y)
> {
>     static object Normalize(object value) => value switch
>     {
>         DBNull or null => DBNull.Value,
>         P p => p,
>         _ => throw new InvalidOperationException($"Unexpected value type: 
> '{value.GetType().FullName}'.")
>     };
>
>     var (xp, yp) = (Normalize(x), Normalize(y));
>
>     return (xp is null && yp is null)
>         || (xp is DBNull && yp is DBNull)
>         || ReferenceEquals(x, y)
>         || Equals(xp, yp);
> }
>
> So my guess is, we want to be comparing values of type P, but can also see 
> values of type R (returned types), so need to disassemble them accordingly, 
> presumably from cached.
>
> Anyone with any insight into this, please chime in? Thanks...
>
> On Friday, July 25, 2025 at 11:25:43 PM UTC-4 Michael W Powell wrote:
>
>> Perhaps making it harder than it needs to be. The interfaces both 
>> indicating literally equality and hash codes _of the persistent state_ that 
>> is of the P primitive types, I gather. If so no biggie, that's a simple 
>> correction to make.
>>
>> On Friday, July 25, 2025 at 10:58:19 PM UTC-4 Michael W Powell wrote:
>>
>>> Hello,
>>>
>>> I am at a point now implementing some user types, things are loading 
>>> from the database correctly, I can work with the models, make adjustments 
>>> via services and WPF UI views, view models, all that is working beautifully.
>>>
>>> Now I am doing the last leg of the game plan: persisting back to the 
>>> database, which as I can gather from the traces, StackOverflowExceptions, 
>>> etc, revolves around negotiating Equals: A LOT, and a lot of navigation to 
>>> and/or from assembed and/or dissassembled form factors. Which depending 
>>> upon the user type implementation, can be tricky.
>>>
>>> Which is part partial my question. What is the general expection, i.e. 
>>> persistence 'protocol' from an NHibernate perspective, navigating the 
>>> persistence conversation.
>>>
>>> Our approach is also generally to implement a P or R based generic user 
>>> type at base (i.e. primitive versus returned types), especially when we 
>>> want to do things such as negotiate NodaTime constructs, sometimes also 
>>> JSON based Newtonsoft.Json.Linq constructs; whch as I mentioned, works 
>>> beautifully querying and loading from the database.
>>>
>>> From what I can also determine, user types sometimes also cached, 
>>> although from the lack of documentation, we are not hundred percent clear 
>>> in which form, either P or R.
>>>
>>> I've implemented the assembly and disassembly generally to use switch 
>>> expressions with strategically placed pattern matching in order to isolate 
>>> P from R in a broad range of use cases. But still finding a StackOverflow 
>>> slip through the cracks here and there.
>>>
>>> Overall, we are familiar with ORM in general, usually involving 
>>> comparison between two datasets, so I'd guess minimally at a primitive 
>>> level, but what is cached, the assembled version, and to make the 
>>> apporpriate comparison that does not blow up the stack.
>>>
>>> So I am here to ask the question: what sort of protocol, assy, disassy, 
>>> caching, can we expect, negotiating the persistence sequence?
>>>
>>> Thanks!
>>>
>>> Best,
>>>
>>> Michael W. Powell
>>>
>>>

-- 
You received this message because you are subscribed to the Google Groups 
"Fluent NHibernate" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/fluent-nhibernate/46325334-993d-4105-949a-7c3b8d620cf0n%40googlegroups.com.

Reply via email to