- 修复 DateOnly/TimeOnly 映射问题;#1868 #1855 #1763 #939 #991

This commit is contained in:
2881099
2024-08-21 02:55:16 +08:00
parent 486015a3c2
commit 2334fe2450
36 changed files with 584 additions and 76 deletions

View File

@ -27,6 +27,7 @@ namespace FreeSql.Custom.SqlServer
{
if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}";
if (value?.Equals(DateTime.MinValue) == true) value = new DateTime(1970, 1, 1);
else if (value?.Equals(DateTimeOffset.MinValue) == true) value = new DateTime(1970, 1, 1);
var ret = Factory.CreateParameter();
ret.ParameterName = QuoteParamterName(parameterName);
ret.Value = value;
@ -40,6 +41,7 @@ namespace FreeSql.Custom.SqlServer
Utils.GetDbParamtersByObject<DbParameter>(sql, obj, null, (name, type, value) =>
{
if (value?.Equals(DateTime.MinValue) == true) value = new DateTime(1970, 1, 1);
else if (value?.Equals(DateTimeOffset.MinValue) == true) value = new DateTime(1970, 1, 1);
var ret = Factory.CreateParameter();
ret.ParameterName = $"@{name}";
ret.Value = value;

View File

@ -71,7 +71,7 @@ namespace FreeSql.Duckdb
else if (param is TimeOnly || param is TimeOnly?)
{
var ts = (TimeOnly)param;
return $"'{ts.Hour}:{ts.Minute}:{ts.Second}.{ts.Millisecond}'";
return $"time '{ts.Hour}:{ts.Minute}:{ts.Second}'";
}
#endif

View File

@ -41,7 +41,7 @@ namespace FreeSql.Duckdb
{ typeof(DateTime).FullName, CsToDb.New(DuckDBType.Timestamp, "timestamp", "timestamp NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(DuckDBType.Timestamp, "timestamp", "timestamp", false, true, null) },
#if net60
{ typeof(TimeOnly).FullName, CsToDb.New(DuckDBType.Time, "time", "time NOT NULL", false, false, 0) },{ typeof(TimeOnly?).FullName, CsToDb.New(DuckDBType.Time, "time", "time", false, true, null) },
{ typeof(TimeOnly).FullName, CsToDb.New(DuckDBType.Time, "time", "time NOT NULL", false, false, TimeOnly.MinValue) },{ typeof(TimeOnly?).FullName, CsToDb.New(DuckDBType.Time, "time", "time", false, true, null) },
{ typeof(DateOnly).FullName, CsToDb.New(DuckDBType.Date, "date", "date NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateOnly?).FullName, CsToDb.New(DuckDBType.Date, "date", "date", false, true, null) },
#endif
@ -53,17 +53,47 @@ namespace FreeSql.Duckdb
{ typeof(BitArray).FullName, CsToDb.New(DuckDBType.Bit, "bit", "bit", false, null, new BitArray(new byte[64])) },
{ typeof(BigInteger).FullName, CsToDb.New(DuckDBType.HugeInt, "hugeint","hugeint NOT NULL", false, false, 0) },{ typeof(BigInteger?).FullName, CsToDb.New(DuckDBType.HugeInt, "hugeint","hugeint", false, true, null) },
{ typeof(Dictionary<string, object>).FullName, CsToDb.New(DuckDBType.Struct, "struct", "struct", false, null, new Dictionary<string, object>()) },
};
public override DbInfoResult GetDbInfo(Type type)
{
//int[]..List<int>
var isarray = type.FullName != "System.Byte[]" && type.IsArray;
var elementType = isarray ? type.GetElementType() : type;
Type elementType = isarray ? type.GetElementType().NullableTypeOrThis() : type;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
isarray = true;
elementType = type.GenericTypeArguments[0].NullableTypeOrThis();
}
var info = GetDbInfoNoneArray(elementType);
if (info == null) return null;
if (isarray == false) return new DbInfoResult((int)info.type, info.dbtype, info.dbtypeFull, info.isnullable, info.defaultValue);
var dbtypefull = Regex.Replace(info.dbtypeFull, $@"{info.dbtype}(\s*\([^\)]+\))?", "$0[]").Replace(" NOT NULL", "");
return new DbInfoResult((int)(info.type | DuckDBType.Array), $"{info.dbtype}[]", dbtypefull, null, Array.CreateInstance(elementType, 0));
if (isarray)
{
var dbtypefull = Regex.Replace(info.dbtypeFull, $@"{info.dbtype}(\s*\([^\)]+\))?", "$0[]").Replace(" NOT NULL", "");
return new DbInfoResult((int)(info.type | DuckDBType.Array), $"{info.dbtype}[]", dbtypefull, null, Array.CreateInstance(elementType, 0));
}
if (type.IsGenericType)
{
var typeDefinition = type.GetGenericTypeDefinition();
//struct
if (typeDefinition == typeof(Dictionary<string, object>))
{
}
//map
if (typeDefinition == typeof(Dictionary<,>))
{
var tkeyInfo = GetDbInfoNoneArray(type.GenericTypeArguments[0].NullableTypeOrThis());
if (tkeyInfo == null) return null;
var tvalInfo = GetDbInfoNoneArray(type.GenericTypeArguments[1].NullableTypeOrThis());
if (tvalInfo == null) return null;
var dbtype = $"map({tkeyInfo.dbtype},{tvalInfo.dbtype})";
return new DbInfoResult((int)(info.type | DuckDBType.Array), dbtype, dbtype, null, Array.CreateInstance(elementType, 0));
}
}
return new DbInfoResult((int)info.type, info.dbtype, info.dbtypeFull, info.isnullable, info.defaultValue);
}
CsToDb<DuckDBType> GetDbInfoNoneArray(Type type)
{

View File

@ -17,6 +17,10 @@ namespace FreeSql.Duckdb
{
if (Interlocked.Exchange(ref _firstInit, 0) == 1) //不能放在 static ctor .NetFramework 可能报初始化类型错误
{
#if net60
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(DateOnly)] = true;
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(TimeOnly)] = true;
#endif
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(BigInteger)] = true;
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(BitArray)] = true;
Select0Provider._dicMethodDataReaderGetValue[typeof(Guid)] = typeof(DbDataReader).GetMethod("GetGuid", new Type[] { typeof(int) });

View File

@ -18,7 +18,7 @@
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
<Version>3.5.100-preview20240725</Version>
<Version>3.5.100-preview20240819</Version>
<PackageReadmeFile>readme.md</PackageReadmeFile>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
<TargetFrameworks>net8.0;net7.0;net6.0;netstandard2.0;net461</TargetFrameworks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>FreeSql;ncc;YeXiangQin</Authors>
<Description>FreeSql 数据库实现,基于 人大金仓数据库 V008R003/V008R006 Ado.Net (Kdbndp)</Description>
@ -50,5 +50,8 @@
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<DefineConstants>ns20;netstandard20</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0' or '$(TargetFramework)' == 'net7.0' or '$(TargetFramework)' == 'net6.0'">
<DefineConstants>net60</DefineConstants>
</PropertyGroup>
</Project>

View File

@ -72,7 +72,7 @@ namespace FreeSql.KingbaseES
else if (param is TimeOnly || param is TimeOnly?)
{
var ts = (TimeOnly)param;
return $"'{ts.Hour}:{ts.Minute}:{ts.Second}.{ts.Millisecond}'";
return $"'{ts.Hour}:{ts.Minute}:{ts.Second}'";
}
#endif

View File

@ -43,7 +43,7 @@ namespace FreeSql.KingbaseES
{ typeof(DateTime).FullName, CsToDb.New(KdbndpDbType.Timestamp, "timestamp", "timestamp NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(KdbndpDbType.Timestamp, "timestamp", "timestamp", false, true, null) },
#if net60
{ typeof(TimeOnly).FullName, CsToDb.New(KdbndpDbType.Time, "time", "time NOT NULL", false, false, 0) },{ typeof(TimeOnly?).FullName, CsToDb.New(KdbndpDbType.Time, "time", "time", false, true, null) },
{ typeof(TimeOnly).FullName, CsToDb.New(KdbndpDbType.Time, "time", "time NOT NULL", false, false, TimeOnly.MinValue) },{ typeof(TimeOnly?).FullName, CsToDb.New(KdbndpDbType.Time, "time", "time", false, true, null) },
{ typeof(DateOnly).FullName, CsToDb.New(KdbndpDbType.Date, "date", "date NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateOnly?).FullName, CsToDb.New(KdbndpDbType.Date, "date", "date", false, true, null) },
#endif

View File

@ -24,6 +24,10 @@ namespace FreeSql.KingbaseES
{
if (Interlocked.Exchange(ref _firstInit, 0) == 1) //不能放在 static ctor .NetFramework 可能报初始化类型错误
{
#if net60
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(DateOnly)] = true;
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(TimeOnly)] = true;
#endif
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(BigInteger)] = true;
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(BitArray)] = true;
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(KdbndpPoint)] = true;

View File

@ -67,6 +67,12 @@ namespace FreeSql.KingbaseES
} },
{ typeof((IPAddress Address, int Subnet)[]).FullName, a => getParamterArrayValue(typeof((IPAddress Address, int Subnet)), a, (IPAddress.Any, 0)) },
{ typeof((IPAddress Address, int Subnet)?[]).FullName, a => getParamterArrayValue(typeof((IPAddress Address, int Subnet)?), a, null) },
#if net60
{ typeof(DateOnly[]).FullName, a => getParamterArrayValue(typeof(DateTime), a, null) },
{ typeof(DateOnly?[]).FullName, a => getParamterArrayValue(typeof(DateTime?), a, null) },
{ typeof(TimeOnly[]).FullName, a => getParamterArrayValue(typeof(TimeSpan), a, null) },
{ typeof(TimeOnly?[]).FullName, a => getParamterArrayValue(typeof(TimeSpan?), a, null) },
#endif
};
static object getParamterValue(Type type, object value, int level = 0)
{
@ -85,6 +91,10 @@ namespace FreeSql.KingbaseES
}
if (type.IsNullableType()) type = type.GenericTypeArguments.First();
if (type.IsEnum) return (int)value;
#if net60
if (type == typeof(DateOnly)) return ((DateOnly)value).ToDateTime(TimeOnly.MinValue);
if (type == typeof(TimeOnly)) return ((TimeOnly)value).ToTimeSpan();
#endif
if (dicGetParamterValue.TryGetValue(type.FullName, out var trydic)) return trydic(value);
return value;
}

View File

@ -73,7 +73,7 @@ namespace FreeSql.MySql
else if (param is TimeOnly || param is TimeOnly?)
{
var ts = (TimeOnly)param;
return $"'{ts.Hour}:{ts.Minute}:{ts.Second}.{ts.Millisecond}'";
return $"'{ts.Hour}:{ts.Minute}:{ts.Second}'";
}
#endif

View File

@ -44,7 +44,7 @@ namespace FreeSql.MySql
{ typeof(DateTime).FullName, CsToDb.New(MySqlDbType.DateTime, "datetime(3)", "datetime(3) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(MySqlDbType.DateTime, "datetime(3)", "datetime(3)", false, true, null) },
#if net60
{ typeof(TimeOnly).FullName, CsToDb.New(MySqlDbType.Time, "time", "time NOT NULL", false, false, 0) },{ typeof(TimeOnly?).FullName, CsToDb.New(MySqlDbType.Time, "time", "time", false, true, null) },
{ typeof(TimeOnly).FullName, CsToDb.New(MySqlDbType.Time, "time", "time NOT NULL", false, false, TimeOnly.MinValue) },{ typeof(TimeOnly?).FullName, CsToDb.New(MySqlDbType.Time, "time", "time", false, true, null) },
{ typeof(DateOnly).FullName, CsToDb.New(MySqlDbType.Date, "date", "date NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateOnly?).FullName, CsToDb.New(MySqlDbType.Date, "date", "date", false, true, null) },
#endif

View File

@ -18,6 +18,10 @@ namespace FreeSql.MySql
{
if (Interlocked.Exchange(ref _firstInit, 0) == 1) //不能放在 static ctor .NetFramework 可能报初始化类型错误
{
#if net60
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(DateOnly)] = true;
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(TimeOnly)] = true;
#endif
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(MygisPoint)] = true;
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(MygisLineString)] = true;
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(MygisPolygon)] = true;

View File

@ -25,6 +25,7 @@ namespace FreeSql.Odbc.SqlServer
{
if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}";
if (value?.Equals(DateTime.MinValue) == true) value = new DateTime(1970, 1, 1);
else if (value?.Equals(DateTimeOffset.MinValue) == true) value = new DateTime(1970, 1, 1);
var ret = new OdbcParameter { ParameterName = QuoteParamterName(parameterName), Value = value };
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
if (tp != null) ret.OdbcType = (OdbcType)tp.Value;
@ -36,6 +37,7 @@ namespace FreeSql.Odbc.SqlServer
Utils.GetDbParamtersByObject<OdbcParameter>(sql, obj, null, (name, type, value) =>
{
if (value?.Equals(DateTime.MinValue) == true) value = new DateTime(1970, 1, 1);
else if (value?.Equals(DateTimeOffset.MinValue) == true) value = new DateTime(1970, 1, 1);
var ret = new OdbcParameter { ParameterName = $"@{name}", Value = value };
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
if (tp != null) ret.OdbcType = (OdbcType)tp.Value;

View File

@ -73,7 +73,7 @@ namespace FreeSql.PostgreSQL
else if (param is TimeOnly || param is TimeOnly?)
{
var ts = (TimeOnly)param;
return $"'{ts.Hour}:{ts.Minute}:{ts.Second}.{ts.Millisecond}'";
return $"'{ts.Hour}:{ts.Minute}:{ts.Second}'";
}
#endif

View File

@ -47,7 +47,7 @@ namespace FreeSql.PostgreSQL
{ typeof(DateTime).FullName, CsToDb.New(NpgsqlDbType.Timestamp, "timestamp", "timestamp NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(NpgsqlDbType.Timestamp, "timestamp", "timestamp", false, true, null) },
#if net60
{ typeof(TimeOnly).FullName, CsToDb.New(NpgsqlDbType.Time, "time", "time NOT NULL", false, false, 0) },{ typeof(TimeOnly?).FullName, CsToDb.New(NpgsqlDbType.Time, "time", "time", false, true, null) },
{ typeof(TimeOnly).FullName, CsToDb.New(NpgsqlDbType.Time, "time", "time NOT NULL", false, false, TimeOnly.MinValue) },{ typeof(TimeOnly?).FullName, CsToDb.New(NpgsqlDbType.Time, "time", "time", false, true, null) },
{ typeof(DateOnly).FullName, CsToDb.New(NpgsqlDbType.Date, "date", "date NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateOnly?).FullName, CsToDb.New(NpgsqlDbType.Date, "date", "date", false, true, null) },
#endif

View File

@ -26,6 +26,10 @@ namespace FreeSql.PostgreSQL
{
if (Interlocked.Exchange(ref _firstInit, 0) == 1) //不能放在 static ctor .NetFramework 可能报初始化类型错误
{
#if net60
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(DateOnly)] = true;
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(TimeOnly)] = true;
#endif
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(BigInteger)] = true;
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(BitArray)] = true;
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlPoint)] = true;

View File

@ -69,6 +69,12 @@ namespace FreeSql.PostgreSQL
} },
{ typeof((IPAddress Address, int Subnet)[]).FullName, a => getParamterArrayValue(typeof((IPAddress Address, int Subnet)), a, (IPAddress.Any, 0)) },
{ typeof((IPAddress Address, int Subnet)?[]).FullName, a => getParamterArrayValue(typeof((IPAddress Address, int Subnet)?), a, null) },
#if net60
{ typeof(DateOnly[]).FullName, a => getParamterArrayValue(typeof(DateTime), a, null) },
{ typeof(DateOnly?[]).FullName, a => getParamterArrayValue(typeof(DateTime?), a, null) },
{ typeof(TimeOnly[]).FullName, a => getParamterArrayValue(typeof(TimeSpan), a, null) },
{ typeof(TimeOnly?[]).FullName, a => getParamterArrayValue(typeof(TimeSpan?), a, null) },
#endif
};
static object getParamterValue(Type type, object value, int level = 0)
{
@ -87,6 +93,10 @@ namespace FreeSql.PostgreSQL
}
if (type.IsNullableType()) type = type.GenericTypeArguments.First();
if (type.IsEnum) return (int)value;
#if net60
if (type == typeof(DateOnly)) return ((DateOnly)value).ToDateTime(TimeOnly.MinValue);
if (type == typeof(TimeOnly)) return ((TimeOnly)value).ToTimeSpan();
#endif
if (dicGetParamterValue.TryGetValue(type.FullName, out var trydic)) return trydic(value);
return value;
}

View File

@ -90,15 +90,24 @@ namespace FreeSql.SqlServer
return string.Concat("'", ((DateTimeOffset)param).ToString("yyyy-MM-dd HH:mm:ss.fff zzzz"), "'");
}
#if net60
else if (param is DateOnly || param is DateOnly?)
else if (param is DateOnly)
{
var result = AddslashesTypeHandler(typeof(DateOnly), param);
if (result != null) return result;
if (param.Equals(DateOnly.MinValue) == true) param = new DateOnly(1970, 1, 1);
return string.Concat("'", ((DateOnly)param).ToString("yyyy-MM-dd"), "'");
}
else if (param is DateOnly?)
{
var result = AddslashesTypeHandler(typeof(DateOnly?), param);
if (result != null) return result;
if (param.Equals(DateOnly.MinValue) == true) param = new DateOnly(1970, 1, 1);
return string.Concat("'", ((DateOnly)param).ToString("yyyy-MM-dd"), "'");
}
else if (param is TimeOnly || param is TimeOnly?)
{
var ts = (TimeOnly)param;
return $"'{ts.Hour}:{ts.Minute}:{ts.Second}.{ts.Millisecond}'";
return $"'{ts.Hour}:{ts.Minute}:{ts.Second}'";
}
#endif
else if (param is TimeSpan || param is TimeSpan?)

View File

@ -38,7 +38,7 @@ namespace FreeSql.SqlServer
{ typeof(DateTime).FullName, CsToDb.New(SqlDbType.DateTime, "datetime", "datetime NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(SqlDbType.DateTime, "datetime", "datetime", false, true, null) },
{ typeof(DateTimeOffset).FullName, CsToDb.New(SqlDbType.DateTimeOffset, "datetimeoffset", "datetimeoffset NOT NULL", false, false, new DateTimeOffset(new DateTime(1970,1,1), TimeSpan.Zero)) },{ typeof(DateTimeOffset?).FullName, CsToDb.New(SqlDbType.DateTimeOffset, "datetimeoffset", "datetimeoffset", false, true, null) },
#if net60
{ typeof(TimeOnly).FullName, CsToDb.New(SqlDbType.Time, "time", "time NOT NULL", false, false, 0) },{ typeof(TimeOnly?).FullName, CsToDb.New(SqlDbType.Time, "time", "time", false, true, null) },
{ typeof(TimeOnly).FullName, CsToDb.New(SqlDbType.Time, "time", "time NOT NULL", false, false, TimeOnly.MinValue) },{ typeof(TimeOnly?).FullName, CsToDb.New(SqlDbType.Time, "time", "time", false, true, null) },
{ typeof(DateOnly).FullName, CsToDb.New(SqlDbType.Date, "date", "date NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateOnly?).FullName, CsToDb.New(SqlDbType.Date, "date", "date", false, true, null) },
#endif

View File

@ -1,4 +1,5 @@
using FreeSql.Internal.CommonProvider;
using FreeSql.Internal;
using FreeSql.Internal.CommonProvider;
using FreeSql.SqlServer.Curd;
using System;
using System.Data.Common;
@ -14,6 +15,10 @@ namespace FreeSql.SqlServer
{
if (Interlocked.Exchange(ref _firstInit, 0) == 1) //不能放在 static ctor .NetFramework 可能报初始化类型错误
{
#if net60
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(DateOnly)] = true;
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(TimeOnly)] = true;
#endif
Select0Provider._dicMethodDataReaderGetValue[typeof(Guid)] = typeof(DbDataReader).GetMethod("GetGuid", new Type[] { typeof(int) });
}
}

View File

@ -30,6 +30,10 @@ namespace FreeSql.SqlServer
{
if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}";
if (value?.Equals(DateTime.MinValue) == true) value = new DateTime(1970, 1, 1);
else if (value?.Equals(DateTimeOffset.MinValue) == true) value = new DateTime(1970, 1, 1);
#if net60
else if (value?.Equals(DateOnly.MinValue) == true) value = new DateTime(1970, 1, 1);
#endif
var ret = new SqlParameter { ParameterName = QuoteParamterName(parameterName), Value = value };
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
if (tp != null) ret.SqlDbType = (SqlDbType)tp.Value;
@ -52,6 +56,10 @@ namespace FreeSql.SqlServer
Utils.GetDbParamtersByObject<DbParameter>(sql, obj, "@", (name, type, value) =>
{
if (value?.Equals(DateTime.MinValue) == true) value = new DateTime(1970, 1, 1);
else if (value?.Equals(DateTimeOffset.MinValue) == true) value = new DateTime(1970, 1, 1);
#if net60
else if (value?.Equals(DateOnly.MinValue) == true) value = new DateTime(1970, 1, 1);
#endif
var ret = new SqlParameter { ParameterName = $"@{name}", Value = value };
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
if (tp != null) ret.SqlDbType = (SqlDbType)tp.Value;