简体   繁体   中英

ServiceStack.OrmLite Creating table with wrong column definition

I'm using ServiceStack.OrmLite, and when trying to set the default column definition for DateTime, I can't manage to get the column to be nullable. Everything else sticks, but "NULL" is somehow converted into "NOT NULL".

In my example code below I've set ColumnDefinition => "DATETIME(6) NULL DEFAULT... and when running it, it creates a table with DATETIME(6) NOT NULL ...

using ServiceStack.OrmLite;
using ServiceStack.OrmLite.Converters;
using System;
using System.Data;
using System.Linq;

OrmLiteConfig.OnModelDefinitionInit = a =>
{
    a.Alias = $"co_{a.ModelType.Name}";
    var idFieldDef = a.FieldDefinitions.Where(field => field.Name == "Id").First();
    idFieldDef.AutoIncrement = true;
    idFieldDef.AutoId = true;
};

MySqlDialect.Provider.RegisterConverter<DateTime>(new AlfaDateTimeConverter());
var factory = new OrmLiteConnectionFactory($"Uid=xxx;Password=yyy;Server=127.0.0.1;Port=3306;Database=ormtest", MySqlDialect.Provider);
var db = await factory.OpenDbConnectionAsync();
db.CreateTable<TestObject>();

public class AlfaDateTimeConverter : DateTimeConverter
{
    public override DbType DbType => DbType.DateTime;
    public override string ColumnDefinition => "DATETIME(6) NULL DEFAULT '0000-01-01 09:00:00'";
}

public class TestObject
{
    public long Id { get; set; }
    public DateTime Time { get; set; }
}

The resulting table definition looks like this:

CREATE TABLE `co_testobject` (
    `Id` BIGINT(20) NOT NULL AUTO_INCREMENT,
    `Time` DATETIME(6) NOT NULL DEFAULT '0000-01-01 09:00:00.000000',
    PRIMARY KEY (`Id`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
;

And I cannot for my life figure out where the "NOT NULL" comes from.

Clearly, my pretty unique default value sticks.

And in my experience MYSQL aborts and lets you know if there is a problem with your statement. It's not best effort, MySQL will not try to figure out what you want and give you what it can base on your faulty query. Either you have a well-formed query, or you don't.

Based on that, I would assume the create statement posted to MySQL contains "NOT NULL". But that would mean ServiceStack.OrmLite is string parsing my ColumnDefinition, changing it before appending it to the full create statement. And that doesn't sound all that likely?

Any thoughts?

If you want to specify a nullable ValueType RDBMS column it needs to be nullable on the C# Type, eg:

public class TestObject
{
    public long Id { get; set; }
    public DateTime? Time { get; set; }
}

OrmLite builds the RDBMS column definition from the Type's metadata which expects the ColumnDefinition on your custom Type Converter to only contain the RDBMS Column Type, ie:

public class AlfaDateTimeConverter : DateTimeConverter
{
    public override DbType DbType => DbType.DateTime;
    public override string ColumnDefinition => "DATETIME(6)";
}

To specify a Default Value you would use a [Default] attribute on the property or you could use the OnModelDefinitionInit to programmatically populate it for all DateTime types, eg:

OrmLiteConfig.OnModelDefinitionInit = modelDef => {
    modelDef.FieldDefinitions
        .Where(x => x.FieldType == typeof(DateTime))
        .Each(x => {
            x.DefaultValue = "'0000-01-01 09:00:00.000000'";
        });
};

You could also populate IsNullable metadata property here but DateTime? should be nullable if the RDBMS column is.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM