Typehandler support - #117
Conversation
|
@mgravell Is there anything you need me to do with this PR - I'd love to get this feature in so I can start looking at the DateOnly/TimeOnly support next? |
| public override void PostProcess(in global::Dapper.UnifiedCommand cmd, global::Foo.CommandParameters args, int rowCount) | ||
| { | ||
| var ps = cmd.Parameters; | ||
| args.OutputValue = new global::CustomClassTypeHandler().Parse(ps[0]); |
There was a problem hiding this comment.
this new concerns me; I would prefer something more like:
private static global::CustomClassTypeHandler? __handler42; // some generated pattern/index
private static global::CustomClassTypeHandler __Handler42 => __handler42 ??= new();
// ...
args.OutputValue = __Handler42.Parse(ps[0]);| /// </summary> | ||
| [ImmutableObject(true)] | ||
| [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method, AllowMultiple = true)] | ||
| [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module, AllowMultiple = true)] |
There was a problem hiding this comment.
presumably this is to keep the context simpler when emitting readers that may be shared/reused between targets?
|
I apologise for delay - 10 months! that's on me; life gets hectic; I've added some minor feedback, and given the delay is my fault, I'm happy to help deal with any fixup etc caused by delays. Overall approach looks sound. |
|
Looks like DAP048 got take4n by something else |
|
Any updates on this? my TypeHandlers aren't picked by the source generator |
SqlMapper.AddTypeHandler registrations now work under interception, in both directions, by delegating to vanilla's own decision procedure at execution time rather than trying to see runtime state at compile time: - writes: a member type the generator does not recognize emits a dispatch through SqlMapper.LookupDbType (public, CS0618-suppressible - the same tier as PackListParameters): handler present -> handler.SetValue (with DBNull for null, never null itself - the TypeHandler<T> interface impl NREs on a raw null); otherwise any returned DbType is applied and the value binds raw as before (demand:false deliberately - modern providers natively handle types vanilla's map does not, DateOnly being the live case until the Dapper re-enable ships). Update-mode mirrors it, so command reuse stays legal (the parameter shape is stable); an expandable member checks the handler *first*, which is the order vanilla applies (a handled collection type must not list-expand - Issue253). - reads: the lib cannot reference Dapper (a consumer may use Dapper or Dapper.StrongName, and a hard reference would split the handler registry between the two), so generated code installs a TypeHandlerBridge from a module initializer, compiled against the consumer's own Dapper; the flexible read path consults it, and a whole-type handler overrides a generated row factory (RowFactory<T>.Resolve), matching vanilla's handler-before-member-binding order. A ModuleInitializerAttribute polyfill is emitted for down-level targets, probe-gated like the interceptor attribute; the whole feature is inert against a Dapper too old to have HasTypeHandler/LookupDbType. - char/char? stay excluded (their StringFixedLength map entry pads the round-trip); object/dynamic stay excluded (runtime-typed values); ParamMember gains TypeOfName, mirroring RowMember's, because typeof on an annotated reference type or dynamic does not compile. This also clears the bare-DataTable TVP shape and the Xml types for free - vanilla registers DataTableHandler and the XML handlers by default, and the dispatch reaches them like any other registration. Dapper test suite: 677 -> 705/793. Design and probed facts in notes/typehandlers-design.md; prior art PRs #117 and #162 (the announced- attribute tier) remain as the static-dispatch optimization, redone on the plain-data model.
Here's my initial attempt at solving #115
I've added a test case and manually verified the output, which looks like it's picked up the changes without effecting any other tests.
Let me know if you need me to make any changes and I can push them up - I've tried to avoid changing as much of the existing code as possible.