Last but not least is the enigmatic DeepCopy... reading some of the drudged 
up old blogs, different folks interpretations over IUserType, take aways 
are all over the map. Best I can figure, and from debugging, and since you 
are not given 'object owner', either...

One has to disassembly the value. Whereas assembling a value you are given 
the owner. So I again take away the reasonable conclusion that Assembly and 
Disassembly are central.

public virtual object DeepCopy(object value) => value switch
{
    null => null,
    R r => Disassemble(r),
    _ => throw new InvalidOperationException($"Unable to deep copy value 
type '{value.GetType()}'.")
};

On Tuesday, June 10, 2025 at 2:53:08 PM UTC-4 Michael W Powell wrote:

> Extending that thought a bit, from what I could determine Equals is a bit 
> nuanced as well. First argument x appears to be cached or disassembled, 
> whereas it would seem second argument y appears to be assembled version of 
> the same.
>
> protected virtual bool Equals(P x, P y) => x is IEquatable<P> xe && y is 
> IEquatable<P> ye && xe.Equals(ye);
>
> public new virtual bool Equals(object x, object y)
> {
>     object Normalize(object value) => value switch
>
>     {
>         null => null,
>         R r => Disassemble(r),
>         P p => p,
>         _ => throw new InvalidOperationException($"Unsupported equality 
> value type '{value.GetType()}'.")
>     };
>
>     x = Normalize(x);
>     y = Normalize(y);
>
>     return (x is null && y is null)
>         || ReferenceEquals(x, y)
>         || (x is P xp && y is P yp && Equals(xp, yp))
>         //|| (x is R xr && y is R yr && Equals(xr, yr))
>         ;
> }
>
> It's unlikely probably would see an R clause (returned class), as 
> contrasted with the P clause (primitive class).
>
> The Normalize local function is also geared at any rate along the same 
> lines to compare vis-a-vis the primitive type.
>
> Then Equals(P, P), after having ruled out null and reference equality, 
> base implementation whether P is IEquatable<P> can just do it then.
>
> Allowing for authors to extend as needed.
>
> On Tuesday, June 10, 2025 at 1:13:17 PM UTC-4 Michael W Powell wrote:
>
>> Hello,
>>
>> Double checking my work implementing IUserType. Implementing to 
>> facilitate mapping types to postgres Npgsql. Specifically in one case to 
>> JSON/JSONB column types, facilitated by either string, then to 
>> Newtonsoft.Json.Linq JObject or JArray, both JContainer, depending on the 
>> use case.
>>
>> Best I can figure, Assemble and Disassemble are somewhat core and central 
>> of such an implementation. Around the NullSafeGet and Set, for instance. 
>> Almost to a point where it might be worth providing a generic serialization 
>> implementation, interface, etc, but starting from here:
>>
>> public virtual object NullSafeGet(DbDataReader rs, string[] names, 
>> ISessionImplementor session, object owner)
>> {
>>     this.VerifyNullSafeNames(names: names);
>>
>>     var name = names[0];
>>     var ordinal = rs.GetOrdinal(name);
>>     var value = rs[ordinal];
>>     return value switch
>>     {
>>         null => null,
>>         P p => Assemble(p, owner),
>>         _ => throw new InvalidOperationException($"Unable to get null 
>> safe value, names: [{string.Join(", ", names)}].")
>>     };
>> }
>>
>> public void NullSafeSet(DbCommand cmd, object value, int index, 
>> ISessionImplementor session)
>> {
>>     // We expect there to be an parameter of this type.
>>     if (cmd.Parameters.TryGetValue<NpgsqlParameter>(index, out var arg))
>>     {
>>         // Parameter Value may be either null, of types R or P, otherwise 
>> throw.
>>         arg.Value = value switch
>>         {
>>             null => null,
>>             R r => Disassemble(r),
>>             P p => p,
>>             _ => throw new InvalidOperationException($"Unable to set null 
>> safe value type '{value.GetType()}' index {index}.")
>>         };
>>
>>         // Indeed return here since we do not want to throw the default 
>> parameter ex.
>>         return;
>>     }
>>
>>     throw new InvalidOperationException($"Unable to set null safe 
>> parameter value index {index}.");
>> }
>>
>> Here I verify names apart from the implementation. Also I look up the 
>> postgres Npgsql parameter in this instance.
>>
>> But the core of the approach, I think, are Assemble and Disassemble, from 
>> what I can gather. Everything revolves around that, including DeepCopy.
>>
>> Mostly everything else is pretty boilerplate, in my estimation, so any 
>> specialization can focus on the A/D overrides. Sometimes perhaps also the 
>> Equals.
>>
>> public abstract class NpgsqlJsonCustomTypeBase<P, R> : IUserType
>> {
>>     // ...
>> }
>>
>> Have verified through mappings and to a test project, seems to satisfy 
>> things.
>>
>> Posting here in case I am missing something, perhaps there are gaps I am 
>> unaware of.
>>
>> Appreciate the feedback.
>>
>> Best regards,
>>
>> 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/034d0171-2512-477e-a9df-26e1680bc803n%40googlegroups.com.

Reply via email to