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