{"record":{"id":"81d61b95c62bff2f","repo":"HangfireIO/Hangfire","slug":"property-type-fullname-batchcommand-not-found","errorCode":null,"errorMessage":"Property '{type.FullName}.BatchCommand' not found.","messagePattern":"Property '(.+?)\\.BatchCommand' not found\\.","errorType":"exception","errorClass":"MissingMemberException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.SqlServer/SqlCommandSet.cs","lineNumber":94,"sourceCode":"                _setConnection = SetConnection.GetOrAdd(sqlCommandSetType, static type =>\n                {\n                    var p = Expression.Parameter(typeof(object));\n                    var converted = Expression.Convert(p, type);\n                    var connectionParameter = Expression.Parameter(typeof(DbConnection));\n                    var connectionProperty = type.GetProperty(\"Connection\", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingMemberException($\"Property '{type.FullName}.Connection' not found.\");\n                    return Expression.Lambda<Action<object, DbConnection>>(Expression.Assign(Expression.Property(converted, connectionProperty), Expression.Convert(connectionParameter, connectionProperty.PropertyType)), p, connectionParameter).Compile();\n                });\n                _setTransaction = SetTransaction.GetOrAdd(sqlCommandSetType, static type =>\n                {\n                    var p = Expression.Parameter(typeof(object));\n                    var converted = Expression.Convert(p, type);\n                    var transactionParameter = Expression.Parameter(typeof(DbTransaction));\n                    var transactionProperty = type.GetProperty(\"Transaction\", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingMemberException($\"Property '{type.FullName}.Transaction' not found.\");\n                    return Expression.Lambda<Action<object, DbTransaction>>(Expression.Assign(Expression.Property(converted, transactionProperty), Expression.Convert(transactionParameter, transactionProperty.PropertyType)), p, transactionParameter).Compile();\n                });\n                var batchCommandProperty = BatchCommandProperty.GetOrAdd(sqlCommandSetType, static type =>\n                {\n                    return type.GetProperty(\"BatchCommand\", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? throw new MissingMemberException($\"Property '{type.FullName}.BatchCommand' not found.\");\n                });\n                _getBatchCommand = GetBatchCommand.GetOrAdd(sqlCommandSetType, type =>\n                {\n                    var p = Expression.Parameter(typeof(object));\n                    var converted = Expression.Convert(p, type);\n                    return Expression.Lambda<Func<object, DbCommand>>(Expression.Property(converted, batchCommandProperty), p).Compile();\n                });\n                _appendMethod = AppendMethod.GetOrAdd(sqlCommandSetType, type =>\n                {\n                    var p = Expression.Parameter(typeof(object));\n                    var converted = Expression.Convert(p, type);\n                    var batchCommandParameter = Expression.Parameter(typeof(DbCommand));\n                    return Expression.Lambda<Action<object, DbCommand>>(Expression.Call(converted, \"Append\", null, Expression.Convert(batchCommandParameter, batchCommandProperty.PropertyType)), p, batchCommandParameter).Compile();\n                });\n                _executeNonQueryMethod = ExecuteNonQueryMethod.GetOrAdd(sqlCommandSetType, static type =>\n                {\n                    var p = Expression.Parameter(typeof(object));\n                    var converted = Expression.Convert(p, type);","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.SqlServer/SqlCommandSet.cs#L76-L112","documentation":"MissingMemberException thrown while resolving the BatchCommand property getter on SqlCommandSet via reflection (Instance|Public|NonPublic). The expression that reads the accumulated batch command cannot be compiled because the property is absent on the resolved type.","triggerScenarios":"A SqlClient assembly whose SqlCommandSet type does not expose a BatchCommand property under that name; provider renamed the property (e.g. to CommandCollection) or removed it.","commonSituations":"Provider major-version upgrade that refactored internal batching; trimming; using an unsupported fork of SqlClient.","solutions":["Use a SqlClient + Hangfire.SqlServer version pair validated in the Hangfire.SqlServer compatibility matrix.","Turn off assembly trimming/obfuscation that strips the property metadata.","Open an issue / upgrade Hangfire.SqlServer if the provider legitimately renamed the member."],"exampleFix":"// before\n<PackageReference Include=\"Microsoft.Data.SqlClient\" Version=\"6.0.0-preview\" />\n\n// after (use a stable, supported release)\n<PackageReference Include=\"Microsoft.Data.SqlClient\" Version=\"5.2.2\" />","handlingStrategy":"type-guard","validationCode":"static bool HasBatchCommandProperty(Type sqlCommandSetType)\n    => sqlCommandSetType.GetProperty(\"BatchCommand\",\n        BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null;","typeGuard":"static bool IsSqlCommandSetUsable(Type type) =>\n    type.GetProperty(\"BatchCommand\", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null;","tryCatchPattern":null,"preventionTips":["Pin SqlClient to a version documented compatible with your Hangfire.SqlServer release.","Avoid preview/obfuscated SqlClient packages in production.","Add a startup health check that probes the provider's batch surface."],"tags":["sqlserver","reflection","provider","compatibility"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}