Skip to content

Commit

Permalink
处理Rafy ORM Sql Server 中 DateTime 类型的字段溢出的问题 #101 和无法生成实体注释到数据库 #66 (#133
Browse files Browse the repository at this point in the history
)

* 添加对DateTimeOffset类型的支持
修改DbTypeConverter.IsCompatible方法

* 规范代码

* 修改测试兼容SqlCE
  • Loading branch information
dyancl1024 authored and zgynhqf committed Dec 16, 2017
1 parent dc8325c commit 7998a26
Show file tree
Hide file tree
Showing 12 changed files with 254 additions and 33 deletions.
2 changes: 1 addition & 1 deletion Rafy/Rafy/DbMigration/DbMigrationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ public void MigrateTo(DestinationDatabase destination)

var dbMeta = this.DatabaseMetaReader.Read();

var differ = new ModelDiffer();
var differ = new ModelDiffer((_runGenerator as SqlRunGenerator).DbTypeCoverter);
differ.IDbIdentifierProvider = (_runGenerator as SqlRunGenerator).IdentifierQuoter;
var changeSet = differ.Distinguish(dbMeta, destination);

Expand Down
11 changes: 9 additions & 2 deletions Rafy/Rafy/DbMigration/Model/Differ/ModelDiffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ internal class ModelDiffer
{
internal IDbIdentifierQuoter IDbIdentifierProvider;

private DbTypeConverter dbTypeConverter;

internal ModelDiffer(DbTypeConverter dbTypeConverter)
{
this.dbTypeConverter = dbTypeConverter;
}

/// <summary>
/// 计算出两个数据库元数据的所有表差别
/// </summary>
Expand Down Expand Up @@ -137,7 +144,7 @@ private ColumnChanges Distinguish(Column oldColumn, Column newColumn)

if (newColumn.IsPrimaryKey != oldColumn.IsPrimaryKey) { columnChanged.IsPrimaryKeyChanged = true; }

if (!DbTypeConverter.IsCompatible(newColumn.DbType, oldColumn.DbType)) { columnChanged.IsDbTypeChanged = true; }
if (!dbTypeConverter.IsCompatible(newColumn.DbType, oldColumn.DbType)) { columnChanged.IsDbTypeChanged = true; }

//ForeignRelationChangeType
columnChanged.ForeignRelationChangeType = ChangeType.UnChanged;
Expand All @@ -164,7 +171,7 @@ private bool Equals(Column a, Column b)
{
if (a.Table.Name.EqualsIgnoreCase(b.Table.Name) &&
a.Name.EqualsIgnoreCase(b.Name) &&
DbTypeConverter.IsCompatible(a.DbType, b.DbType) &&
dbTypeConverter.IsCompatible(a.DbType, b.DbType) &&
//a.DataType == b.DataType &&
a.IsRequired == b.IsRequired &&
a.IsForeignKey == b.IsForeignKey &&
Expand Down
3 changes: 2 additions & 1 deletion Rafy/Rafy/DbMigration/Providers/DbTypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public virtual DbType FromClrType(Type clrType)
if (clrType == typeof(long)) { return DbType.Int64; }
if (clrType == typeof(bool)) { return DbType.Boolean; }
if (clrType == typeof(DateTime)) { return DbType.DateTime; }
if (clrType == typeof(DateTimeOffset)) { return DbType.DateTimeOffset; }
if (clrType == typeof(Guid)) { return DbType.Guid; }
if (clrType == typeof(double)) { return DbType.Double; }
if (clrType == typeof(byte)) { return DbType.Byte; }
Expand Down Expand Up @@ -146,7 +147,7 @@ internal virtual object GetDefaultValue(DbType type)
/// <param name="oldColumnType"></param>
/// <param name="newColumnType"></param>
/// <returns></returns>
internal static bool IsCompatible(DbType oldColumnType, DbType newColumnType)
internal virtual bool IsCompatible(DbType oldColumnType, DbType newColumnType)
{
if (oldColumnType == newColumnType) return true;

Expand Down
27 changes: 24 additions & 3 deletions Rafy/Rafy/DbMigration/Providers/MySql/MySqlDbTypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ private MySqlDbTypeConverter() { }

/// <summary>
/// 把 DbType的类型值 转换为 MySql 数据库中兼容的数据类型
/// MySql数据精度 http://qimo601.iteye.com/blog/1622368
/// </summary>
/// <param name="fieldType">字段的DbType类型值</param>
/// <param name="length">数据类型的长度</param>
Expand Down Expand Up @@ -63,13 +64,12 @@ public override string ConvertToDatabaseTypeName(DbType fieldType, string length
case DbType.UInt64:
case DbType.Int64:
return "BIGINT";
case DbType.DateTimeOffset:
return "TIMESTAMP";
case DbType.Time:
return "TIME";
case DbType.Date:
return "DATE";
case DbType.DateTime:
case DbType.DateTimeOffset:
return "DATETIME";
case DbType.Single:
return "FLOAT";
Expand Down Expand Up @@ -131,7 +131,7 @@ public override DbType ConvertToDbType(string databaseTypeName)
}
if (string.Compare(databaseTypeName, "TIME", true) == 0) { return DbType.Time; }
if (string.Compare(databaseTypeName, "DATETIME", true) == 0) { return DbType.DateTime; }
if (string.Compare(databaseTypeName, "TIMESTAMP", true) == 0) { return DbType.DateTimeOffset; }
if (string.Compare(databaseTypeName, "TIMESTAMP", true) == 0) { return DbType.DateTime; }
}
if (TypeContains(databaseTypeName, "DATE")) { return DbType.Date; }

Expand All @@ -158,6 +158,10 @@ public override object ToDbParameterValue(object value)
{
value = TypeHelper.CoerceValue(typeof(int), value);
}
else if (value is DateTimeOffset)
{
value = ((DateTimeOffset)value).DateTime;
}
}

return value;
Expand All @@ -178,6 +182,23 @@ public override object ToClrValue(object dbValue, Type clrType)
dbValue = string.Empty;//null 转换为空字符串
}

// DateTime to DateTimeOffset
// https://msdn.microsoft.com/zh-cn/library/bb546101.aspx
// DateTime DateTime2 区别 http://www.studyofnet.com/news/1050.html
if (clrType == typeof(DateTimeOffset) && dbValue != null)
{
DateTime dateTime = (DateTime)dbValue;

if (dateTime == DateTime.MinValue)
{
dbValue = DateTimeOffset.MinValue;
}
else
{
dbValue = (DateTimeOffset)DateTime.SpecifyKind(dateTime, DateTimeKind.Local);
}
}

return dbValue;
}

Expand Down
19 changes: 18 additions & 1 deletion Rafy/Rafy/DbMigration/Providers/Oracle/OracleDbTypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public override DbType ConvertToDbType(string databaseTypeName)
/// <returns></returns>
public override DbType FromClrType(Type clrType)
{
if (clrType == typeof(DateTime)) { return DbType.Date; }
if (clrType == typeof(DateTime) || clrType == typeof(DateTimeOffset)) { return DbType.Date; }

var value = base.FromClrType(clrType);

Expand Down Expand Up @@ -153,6 +153,10 @@ public override object ToDbParameterValue(object value)
{
value = TypeHelper.CoerceValue(typeof(int), value);
}
else if (value is DateTimeOffset)
{
value = ((DateTimeOffset)value).DateTime;
}
}

return value;
Expand All @@ -174,6 +178,19 @@ public override object ToClrValue(object dbValue, Type clrType)
{
dbValue = dbValue.ToString() == "1" ? true : false;
}
else if (clrType == typeof(DateTimeOffset))
{
DateTime dateTime = (DateTime)dbValue;

if (dateTime == DateTime.MinValue)
{
dbValue = DateTimeOffset.MinValue;
}
else
{
dbValue = (DateTimeOffset)DateTime.SpecifyKind(dateTime, DateTimeKind.Local);
}
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ public override string ConvertToDatabaseTypeName(DbType fieldType, string length
case DbType.Date:
case DbType.Time:
case DbType.DateTime:
case DbType.DateTimeOffset:
return "DATETIME";
case DbType.DateTimeOffset:
return "DATETIMEOFFSET";
case DbType.Guid:
return "UNIQUEIDENTIFIER";
case DbType.Double:
Expand Down Expand Up @@ -121,12 +122,43 @@ public override DbType ConvertToDbType(string databaseTypeName)
return DbType.Byte;
case "date":
case "datetime":
case "datetimeoffset":
case "time":
return DbType.DateTime;
case "datetimeoffset":
return DbType.DateTimeOffset;
default:
throw new NotSupportedException($"不支持读取数据库中的列类型:{databaseTypeName}");
}
}

/// <summary>
/// 由于不同的 DbType 映射到库中后的类型可能是相同的,所以这里需要对类型进行兼容性判断。
/// </summary>
/// <param name="oldColumnType"></param>
/// <param name="newColumnType"></param>
/// <returns></returns>
internal override bool IsCompatible(DbType oldColumnType, DbType newColumnType)
{
if (oldColumnType == newColumnType) return true;

for (int i = 0, c = CompatibleTypes.Length; i < c; i++)
{
var sameTypes = CompatibleTypes[i];
if (sameTypes.Contains(oldColumnType) && sameTypes.Contains(newColumnType))
{
return true;
}
}

return base.IsCompatible(oldColumnType, newColumnType);
}

/// <summary>
/// SqlServer DataType
/// https://technet.microsoft.com/zh-cn/library/microsoft.sqlserver.dac.model.sqldatatype(v=sql.120).aspx
/// </summary>
private static DbType[][] CompatibleTypes = new DbType[][]{
new DbType[]{ DbType.DateTime2, DbType.DateTimeOffset }
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,96 @@ public override string ConvertToDatabaseTypeName(DbType fieldType, string length
return "NVARCHAR(4000)";
case DbType.Binary:
return "VARBINARY(8000)";
case DbType.DateTime2:
case DbType.DateTimeOffset:
return "DATETIME";
default:
return base.ConvertToDatabaseTypeName(fieldType, length);
}
}

/// <summary>
/// 将从数据库 Schema Meta 中读取出来的列的类型名称,转换为其对应的 DbType。
/// </summary>
/// <param name="databaseTypeName">从数据库 Schema Meta 中读取出来的列的类型名称。</param>
/// <returns></returns>
/// <exception cref="NotSupportedException"></exception>
public override DbType ConvertToDbType(string databaseTypeName)
{
switch (databaseTypeName.ToLower())
{
case "datetimeoffset":
case "datetime2":
case "time":
return DbType.DateTime;
default:
return base.ConvertToDbType(databaseTypeName);
}
}

/// <summary>
/// 返回 CLR 类型默认映射的数据库的类型。
/// </summary>
/// <param name="clrType"></param>
/// <returns></returns>
public override DbType FromClrType(Type clrType)
{
if (clrType == typeof(DateTimeOffset)) { return DbType.DateTime; }

var value = base.FromClrType(clrType);

return value;
}

/// <summary>
/// 将指定的值转换为一个兼容数据库类型的值。
/// 该值可用于与下层的 ADO.NET 交互。
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public override object ToDbParameterValue(object value)
{
value = base.ToDbParameterValue(value);

if (value != DBNull.Value)
{
if (value is DateTimeOffset)
{
value = ((DateTimeOffset)value).DateTime;
}
}

return value;
}

/// <summary>
/// 将指定的值转换为一个 CLR 类型的值。
/// </summary>
/// <param name="dbValue">The database value.</param>
/// <param name="clrType">Type of the color.</param>
/// <returns></returns>
public override object ToClrValue(object dbValue, Type clrType)
{
dbValue = base.ToClrValue(dbValue, clrType);

if (dbValue != null)
{
if (clrType == typeof(DateTimeOffset))
{
DateTime dateTime = (DateTime)dbValue;

if (dateTime == DateTime.MinValue)
{
dbValue = DateTimeOffset.MinValue;
}
else
{
dbValue = (DateTimeOffset)DateTime.SpecifyKind(dateTime, DateTimeKind.Local);
}
}
}

return dbValue;
}
}
}
12 changes: 10 additions & 2 deletions Rafy/Rafy/Domain/ORM/DbMigration/CommentFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,21 @@ public string TryFindComment(IManagedProperty property)
// return this.TryFindComment(type.Assembly, key);
//}

/// <summary>
/// 通过程序集获取对应xml文件,为设置备注做准备
/// Assembly.CodeBase vs Assembly.Location
/// https://www.cnblogs.com/happyframework/p/3612494.html
/// </summary>
/// <param name="assembly"></param>
/// <param name="key"></param>
/// <returns></returns>
private string TryFindComment(Assembly assembly, string key)
{
XDocument xdoc = null;
if (!_store.TryGetValue(assembly, out xdoc))
{
var assemblyPath = assembly.Location;
var xmlDocPath = Path.Combine(Path.GetDirectoryName(assemblyPath), Path.GetFileNameWithoutExtension(assemblyPath) + ".xml");
var assemblyCodeBase = assembly.CodeBase.Replace("file:///", "");
var xmlDocPath = Path.Combine(Path.GetDirectoryName(assemblyCodeBase), Path.GetFileNameWithoutExtension(assemblyCodeBase) + ".xml");
if (File.Exists(xmlDocPath))
{
try
Expand Down
9 changes: 9 additions & 0 deletions Test/Rafy.UnitTest/Entities/Yacht.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ public decimal DecimalValue
set { this.SetProperty(DecimalValueProperty, value); }
}

public static readonly Property<DateTimeOffset?> DateTimeOffsetValueProperty = P<Yacht>.Register(e => e.DateTimeOffsetValue);
/// <summary>
///
/// </summary>
public DateTimeOffset? DateTimeOffsetValue
{
get { return this.GetProperty(DateTimeOffsetValueProperty); }
set { this.SetProperty(DateTimeOffsetValueProperty, value); }
}

#endregion

Expand Down
Loading

0 comments on commit 7998a26

Please sign in to comment.