2024-11-13 18:18:28 +08:00

254 lines
14 KiB
C#

using FreeSql.DataAnnotations;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using FreeSql.Provider.QuestDb.Subtable;
using Newtonsoft.Json.Linq;
using NpgsqlTypes;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Numerics;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.QuestDb
{
class QuestDbCodeFirst : Internal.CommonProvider.CodeFirstProvider
{
public QuestDbCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm,
commonUtils, commonExpression)
{
}
static object _dicCsToDbLock = new object();
static Dictionary<string, CsToDb<NpgsqlDbType>> _dicCsToDb = new Dictionary<string, CsToDb<NpgsqlDbType>>()
{
{ typeof(sbyte).FullName, CsToDb.New(NpgsqlDbType.Smallint, "byte", "byte NOT NULL", false, false, 0) },
{ typeof(sbyte?).FullName, CsToDb.New(NpgsqlDbType.Smallint, "byte", "byte", false, true, null) },
{ typeof(short).FullName, CsToDb.New(NpgsqlDbType.Smallint, "short", "short NOT NULL", false, false, 0) },
{ typeof(short?).FullName, CsToDb.New(NpgsqlDbType.Smallint, "short", "short", false, true, null) },
{ typeof(int).FullName, CsToDb.New(NpgsqlDbType.Integer, "int", "int NOT NULL", false, false, 0) },
{ typeof(int?).FullName, CsToDb.New(NpgsqlDbType.Integer, "int", "int", false, true, null) },
{ typeof(long).FullName, CsToDb.New(NpgsqlDbType.Bigint, "long", "long NOT NULL", false, false, 0) },
{ typeof(long?).FullName, CsToDb.New(NpgsqlDbType.Bigint, "long", "long", false, true, null) },
{ typeof(byte).FullName, CsToDb.New(NpgsqlDbType.Smallint, "byte", "byte NOT NULL", false, false, 0) },
{ typeof(byte?).FullName, CsToDb.New(NpgsqlDbType.Smallint, "byte", "byte", false, true, null) },
{ typeof(ushort).FullName, CsToDb.New(NpgsqlDbType.Integer, "short", "short NOT NULL", false, false, 0) },
{ typeof(ushort?).FullName, CsToDb.New(NpgsqlDbType.Integer, "short", "short", false, true, null) },
{ typeof(uint).FullName, CsToDb.New(NpgsqlDbType.Bigint, "int", "int NOT NULL", false, false, 0) },
{ typeof(uint?).FullName, CsToDb.New(NpgsqlDbType.Bigint, "int", "int", false, true, null) },
{ typeof(ulong).FullName, CsToDb.New(NpgsqlDbType.Numeric, "long", "long NOT NULL", false, false, 0) },
{ typeof(ulong?).FullName, CsToDb.New(NpgsqlDbType.Numeric, "long", "long", false, true, null) },
{ typeof(float).FullName, CsToDb.New(NpgsqlDbType.Real, "float", "float NOT NULL", false, false, 0) },
{ typeof(float?).FullName, CsToDb.New(NpgsqlDbType.Real, "float", "float", false, true, null) },
{ typeof(double).FullName, CsToDb.New(NpgsqlDbType.Double, "double", "double NOT NULL", false, false, 0) },
{ typeof(double?).FullName, CsToDb.New(NpgsqlDbType.Double, "double", "double", false, true, null) },
{ typeof(decimal).FullName, CsToDb.New(NpgsqlDbType.Numeric, "double", "double NOT NULL", false, false, 0) },
{ typeof(decimal?).FullName, CsToDb.New(NpgsqlDbType.Numeric, "double", "double", false, true, null) },
{ typeof(string).FullName, CsToDb.New(NpgsqlDbType.Varchar, "string", "string", false, null, "") },
{ typeof(char).FullName, CsToDb.New(NpgsqlDbType.Char, "char", "char", false, null, '\0') },
{ typeof(Guid).FullName, CsToDb.New(NpgsqlDbType.Char, "symbol", "symbol", false, null, Guid.Empty) },
{ typeof(Guid?).FullName, CsToDb.New(NpgsqlDbType.Char, "symbol", "symbol", false, true, null) },
{ 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) },
{ typeof(bool).FullName, CsToDb.New(NpgsqlDbType.Boolean, "boolean", "boolean NOT NULL", null, false, false) },
{ typeof(bool?).FullName, CsToDb.New(NpgsqlDbType.Boolean, "boolean", "boolean", null, true, null) },
{ typeof(Byte[]).FullName, CsToDb.New(NpgsqlDbType.Bytea, "binary", "binary", false, null, new byte[0]) },
{ typeof(BigInteger).FullName, CsToDb.New(NpgsqlDbType.Numeric, "long256", "long256 NOT NULL", false, false, 0) },
{ typeof(BigInteger?).FullName, CsToDb.New(NpgsqlDbType.Numeric, "long256", "long256", false, true, null) }
};
public override DbInfoResult GetDbInfo(Type type)
{
if (_dicCsToDb.TryGetValue(type.FullName, out var trydc))
return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable,
trydc.defaultValue);
if (type.IsArray)
return null;
return null;
}
protected override string GetComparisonDDLStatements(params TypeSchemaAndName[] objects)
{
var sb = new StringBuilder();
var seqcols = new List<NativeTuple<ColumnInfo, string[], bool>>(); //序列
foreach (var obj in objects)
{
if (sb.Length > 0) sb.Append("\r\n");
var tb = obj.tableSchema;
if (tb == null) throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.tableSchema.Type.FullName));
if (tb.Columns.Any() == false)
throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.tableSchema.Type.FullName));
var tbname = tb.DbName;
var tboldname = tb.DbOldName;
if (string.IsNullOrEmpty(obj.tableName) == false)
{
var tbtmpname = obj.tableName;
if (tbname != tbtmpname)
{
tbname = tbtmpname;
tboldname = null;
}
}
var sbalter = new StringBuilder();
var allTable = _orm.Ado.Query<string>(CommandType.Text,
@"SHOW TABLES");
//如果旧表名和现表名均不存在,则直接创建表
if (string.IsNullOrWhiteSpace(tboldname) && allTable.Any(s => s.Equals(tbname)) == false)
{
//创建表
var createTableName = _commonUtils.QuoteSqlName(tbname);
sbalter.Append("CREATE TABLE ").Append(createTableName).Append(" ( ");
foreach (var tbcol in tb.ColumnsByPosition)
{
sbalter.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ")
.Append(tbcol.Attribute.DbType);
if (tbcol.Attribute.IsIdentity == true)
{
//No IsIdentity
}
sbalter.Append(",");
}
sbalter.Remove(sbalter.Length - 1, 1);
sbalter.Append(") ");
if (tb.Indexes.Any())
{
sbalter.Append(",\r\n");
}
//创建表的索引
foreach (var uk in tb.Indexes)
{
sbalter.Append($"INDEX (");
foreach (var tbcol in uk.Columns)
{
if (tbcol.Column.Attribute.DbType != "SYMBOL")
throw new Exception("索引只能是string类型且[Column(DbType = \"symbol\")]");
sbalter.Append($"{_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)}");
}
sbalter.Append($"),");
}
sbalter.Remove(sbalter.Length - 1, 1);
//是否存在分表
foreach (var propety in obj.tableSchema.Type.GetProperties())
{
var timeAttr = propety.GetCustomAttribute<AutoSubtableAttribute>();
if (timeAttr != null)
{
var ckey = propety.Name;
//如果存在Column.Name
var colNameAttr = propety.GetCustomAttribute<ColumnAttribute>();
if (!string.IsNullOrWhiteSpace(colNameAttr?.Name))
//则以Column中的Name为主
ckey = colNameAttr.Name;
var colName = tb.Columns.FirstOrDefault(it => it.Key == ckey).Value;
sbalter.Append(
$" TIMESTAMP({colName.Attribute.Name}) PARTITION BY {timeAttr.SubtableType};{Environment.NewLine}");
}
}
}
//如果旧表名特性存在,旧表名在数据库中存在,现表名在数据库中不存在,直接走修改表名逻辑
else if (string.IsNullOrWhiteSpace(tboldname) == false && allTable.Any(s => s.Equals(tboldname)) &&
allTable.Any(s => s.Equals(tbname)) == false)
{
//修改表名
sbalter.Append("RENAME TABLE ")
.Append(_commonUtils.QuoteSqlName(tboldname))
.Append(" TO ").Append(_commonUtils.QuoteSqlName(tbname))
.Append($";{Environment.NewLine}");
}
//如果旧表名特性存在,旧表名在数据库中不存在,现表名在数据库中存在,对比列
//如果旧表名特性不存在 现表名在数据库中存在,对比列
else if ((string.IsNullOrWhiteSpace(tboldname) == false &&
allTable.Any(s => s.Equals(tboldname)) == false &&
allTable.Any(s => s.Equals(tbname)) == true)
|| (string.IsNullOrWhiteSpace(tboldname) == true &&
allTable.Any(s => s.Equals(tbname)) == true))
{
//查询列
var questDbColumnInfo = _orm.Ado.ExecuteArray($"SHOW COLUMNS FROM '{tbname}'").Select(o => new
{
columnName = o[0].ToString(),
indexed = Convert.ToBoolean(o[2])
}).ToList();
//对比列
foreach (var tbcol in tb.ColumnsByPosition)
{
//如果旧列名存在 现列名均不存在 直接添加列
if (questDbColumnInfo.Any(a => a.columnName.Equals(tbcol.Attribute.OldName)) == false
&& questDbColumnInfo.Any(a => a.columnName.Equals(tbcol.Attribute.Name)) ==
false)
{
sbalter.Append("ALTER TABLE ").Append(tbname)
.Append(" ADD COLUMN ").Append(tbcol.Attribute.Name).Append(" ")
.Append(tbcol.Attribute.DbType).Append($";{Environment.NewLine}");
questDbColumnInfo.Add(new
{
columnName = tbcol.Attribute.Name,
indexed = false
});
}
//如果旧列名存在,现列名不存在,直接修改列名
else if (questDbColumnInfo.Any(a =>
a.columnName.ToString().Equals(tbcol.Attribute.OldName)) == true
&& questDbColumnInfo.Any(a => a.columnName.ToString().Equals(tbcol.Attribute.Name)) ==
false)
{
sbalter.Append("ALTER TABLE ").Append(tbname)
.Append(" RENAME COLUMN ").Append(tbcol.Attribute.OldName).Append(" TO ")
.Append(tbcol.Attribute.Name).Append($";{Environment.NewLine}");
}
}
//对比索引
foreach (var uk in tb.Indexes)
{
if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false)
continue;
var ukname = ReplaceIndexName(uk.Name, tbname);
//先判断表中有没此字段的索引
var isIndex = questDbColumnInfo
.Where(a => a.columnName.ToString().Equals(uk.Columns.First().Column.Attribute.Name))
.FirstOrDefault()?.indexed;
//如果此字段不是索引
if (isIndex != null && isIndex == false)
{
//创建索引
sbalter.Append($"ALTER TABLE {tbname} ALTER COLUMN ");
foreach (var tbcol in uk.Columns)
{
if (tbcol.Column.Attribute.DbType != "SYMBOL")
throw new Exception("索引只能是string类型且[Column(DbType = \"symbol\")]");
sbalter.Append($"{tbcol.Column.Attribute.Name}");
}
sbalter.Append($" ADD INDEX;{Environment.NewLine}");
}
}
}
sb.Append(sbalter);
}
return sb.Length == 0 ? null : sb.ToString();
}
}
}