We are working on a distributed, sequential ID generator that creates a 96-bit numeric ID. The datatype we work in the application for this value is decimal
. On the database side, the column's datatype would be decimal(28,0)
.
The problem is that when I map by code and configure the Id, I can't specify the precision and scale. Ideally, I'd want something like this:
map.Id(c => c.Id, id =>
{
id.Generator(RustFlakeGeneratorDef.Instance);
id.Precision(28); // nope
id.Scale(0); // nope. *$%!
});
If I try and ignore that, NHibernate falls back to using decimal(28,5)
when creating parameters and issuing commands, which won't work.
I'm aware that there's a ticket, and if I'd like to contribute to that in due time. In the meantime, I need to see if this is going to pan out, so I'm wondering if there are any workarounds for this. Custom type, hack the deserialized HBM, anything like that?
I did try to create my own type that derives from DecimalType
, and I overrode the property that returns the SqlType
, where I specified my own precision and scale, but that didn't seem to do anything.
So I figured that I can edit the deserialized HBM mappings that ByCode creates and update the mappings manually.
var mapping = ModelMapper.CompileMappingFor(entityTypes);
// HACK: by code mapping doesn't support setting precision and scale, so fix flake ID columns here
var flakeTypeName = typeof (RustFlakeGenerator).AssemblyQualifiedName;
foreach (var id in (from root in mapping.RootClasses
where root.Id.Type.name == "Decimal" && root.Id.generator.@class == flakeTypeName
select root.Id))
{
var column = id.column == null || !id.column.Any() ? new HbmColumn() : id.column.First();
column.name = id.name;
column.precision = "28";
column.scale = "0";
if (id.column == null || !id.column.Any()) id.column = new[] {column};
}
It sucks, and SchemaExport et al totally ignore the precision and scale (defaulting to decimal(19,5)
, but I only use that for scaffolding and can just fix that manually), but it works.