@ -112,477 +112,22 @@ namespace FreeSql.Internal
continue ;
}
if ( tp = = null & & colattr ! = null ) colattr . IsIgnore = true ; //无法匹配的属性,认定是导航属性,且自动过滤
var colattrIsNullable = colattr ? . _IsNullable ;
var colattrIsNull = colattr = = null ;
if ( colattr = = null )
colattr = new ColumnAttribute
{
Name = p . Name ,
DbType = tp . dbtypeFull ,
IsNullable = tp . isnullable ? ? true ,
MapType = p . PropertyType
} ;
if ( colattr . _IsNullable = = null ) colattr . _IsNullable = tp ? . isnullable ;
if ( string . IsNullOrEmpty ( colattr . DbType ) ) colattr . DbType = tp ? . dbtypeFull ? ? "varchar(255)" ;
if ( colattr . DbType . StartsWith ( "set(" ) | | colattr . DbType . StartsWith ( "enum(" ) )
{
var leftBt = colattr . DbType . IndexOf ( '(' ) ;
colattr . DbType = colattr . DbType . Substring ( 0 , leftBt ) . ToUpper ( ) + colattr . DbType . Substring ( leftBt ) ;
}
else if ( common . _orm . Ado . DataType ! = DataType . ClickHouse )
colattr . DbType = colattr . DbType . ToUpper ( ) ;
if ( colattrIsNull = = false & & colattrIsNullable = = tru e) colattr . DbType = colattr . DbType . Replace ( "NOT NULL" , "" ) ;
if ( colattrIsNull = = false & & colattrIsNullable = = false & & colattr . DbType . C onta ins ( "NOT NULL" ) = = false ) colattr . DbType = Regex . Replace ( colattr . DbType , @"\bNULL\b" , "" ) . Trim ( ) + " NOT NULL" ;
if ( colattr . _IsNullable = = null & & tp ! = null & & tp . isnullable = = null ) colattr . IsNullable = tp . dbtypeFull . Contains ( "NOT NULL" ) = = false ;
if ( colattr . DbType ? . Contains ( "NOT NULL" ) = = true ) colattr . IsNullable = false ;
if ( string . IsNullOrEmpty ( colattr . Name ) ) colattr . Name = p . Name ;
if ( common . CodeFirst . IsSyncStructureToLower ) colattr . Name = colattr . Name . ToLower ( ) ;
if ( common . CodeFirst . IsSyncStructureToUpper ) colattr . Name = colattr . Name . ToUpper ( ) ;
var col = ColumnAttributeToInfo ( trytb , entityDefault , p . Nam e, p . PropertyType , setMethod = = null , ref colattr , tp , common ) ;
if ( col = = null ) c ontinue ;
if ( ( colattr . IsNullable ! = true | | colattr . IsIdentity = = true | | colattr . IsPrimary = = true ) & & colattr . DbType . Contains ( "NOT NULL" ) = = false & & common . _orm . Ado . DataType ! = DataType . ClickHouse )
{
colattr . IsNullable = false ;
colattr . DbType = Regex . Replace ( colattr . DbType , @"\bNULL\b" , "" ) . Trim ( ) + " NOT NULL" ;
}
if ( colattr . IsNullable = = true & & colattr . DbType . Contains ( "NOT NULL" ) ) colattr . DbType = colattr . DbType . Replace ( "NOT NULL" , "" ) ;
else if ( colattr . IsNullable = = true & & ! colattr . DbType . Contains ( "Nullable" ) & & common . _orm . Ado . DataType = = DataType . ClickHouse ) colattr . DbType = $"Nullable({colattr.DbType})" ;
colattr . DbType = Regex . Replace ( colattr . DbType , @"\([^\)]+\)" , m = >
{
var tmpLt = Regex . Replace ( m . Groups [ 0 ] . Value , @"\s" , "" ) ;
if ( tmpLt . Contains ( "CHAR" ) ) tmpLt = tmpLt . Replace ( "CHAR" , " CHAR" ) ;
if ( tmpLt . Contains ( "BYTE" ) ) tmpLt = tmpLt . Replace ( "BYTE" , " BYTE" ) ;
return tmpLt ;
} ) ;
if ( colattr . IsIdentity = = true & & colattr . MapType . IsNumberType ( ) = = false )
colattr . IsIdentity = false ;
if ( setMethod = = null ) colattr . IsIgnore = true ;
if ( propsComment ! = null & & propsComment . TryGetValue ( p . Name , out var trycomment ) )
col . Comment = trycomment ;
if ( string . IsNullOrEmpty ( col . Comment ) & & propsCommentByDescAttr ! = null & & propsCommentByDescAttr . TryGetValue ( p . Name , out trycomment ) )
col . Comment = trycomment ;
var col = new C olumnInfo
{
Table = trytb ,
CsName = p . Name ,
CsType = p . PropertyType ,
Attribute = colattr
} ;
if ( propsComment ! = null & & propsComment . TryGetValue ( p . Name , out var trycomment ) )
col . Comment = trycomment ;
if ( string . IsNullOrEmpty ( col . Comment ) & & propsCommentByDescAttr ! = null & & propsCommentByDescAttr . TryGetValue ( p . Name , out trycomment ) )
col . Comment = trycomment ;
if ( colattr . IsIgnore )
{
trytb . ColumnsByCsIgnore . Add ( p . Name , col ) ;
continue ;
}
object defaultValue = null ;
if ( entityDefault ! = null ) defaultValue = trytb . Properties [ p . Name ] . GetValue ( entityDefault , null ) ;
if ( p . PropertyType . IsEnum )
{
var isEqualsEnumValue = false ;
var enumValues = Enum . GetValues ( p . PropertyType ) ;
for ( var a = 0 ; a < enumValues . Length ; a + + )
if ( object . Equals ( defaultValue , enumValues . GetValue ( a ) ) )
{
isEqualsEnumValue = true ;
break ;
}
if ( isEqualsEnumValue = = false & & enumValues . Length > 0 )
defaultValue = enumValues . GetValue ( 0 ) ;
}
if ( defaultValue ! = null & & p . PropertyType ! = colattr . MapType ) defaultValue = Utils . GetDataReaderValue ( colattr . MapType , defaultValue ) ;
if ( defaultValue = = null ) defaultValue = tp ? . defaultValue ;
if ( colattr . IsNullable = = false & & defaultValue = = null )
{
var citype = colattr . MapType . IsNullableType ( ) ? colattr . MapType . GetGenericArguments ( ) . FirstOrDefault ( ) : colattr . MapType ;
defaultValue = citype . CreateInstanceGetDefaultValue ( ) ;
}
try
{
var initParms = new List < DbParameter > ( ) ;
col . DbDefaultValue = common . GetNoneParamaterSqlValue ( initParms , "init" , col , colattr . MapType , defaultValue ) ;
if ( initParms . Any ( ) ) col . DbDefaultValue = "NULL" ;
}
catch
{
col . DbDefaultValue = "NULL" ;
}
//if (defaultValue != null && colattr.MapType.NullableTypeOrThis() == typeof(DateTime))
//{
// var dt = (DateTime)defaultValue;
// if (Math.Abs(dt.Subtract(DateTime.Now).TotalSeconds) < 60)
// col.DbDefaultValue = common.Now;
// else if (Math.Abs(dt.Subtract(DateTime.UtcNow).TotalSeconds) < 60)
// col.DbDefaultValue = common.NowUtc;
//}
if ( common . _orm . Ado . DataType = = DataType . GBase )
{
if ( colattr . IsIdentity = = true )
{
var colType = col . CsType . NullableTypeOrThis ( ) ;
if ( colType = = typeof ( int ) | | colType = = typeof ( uint ) )
colattr . DbType = "SERIAL" ;
else if ( colType = = typeof ( long ) | | colType = = typeof ( ulong ) )
colattr . DbType = "SERIAL8" ;
}
if ( colattr . MapType . NullableTypeOrThis ( ) = = typeof ( DateTime ) )
{
if ( colattr . _Precision = = null )
{
colattr . DbType = "DATETIME YEAR TO FRACTION(3)" ;
colattr . Precision = 3 ;
col . DbPrecision = 3 ;
}
else if ( colattr . _Precision = = 0 )
{
colattr . DbType = "DATETIME YEAR TO SECOND" ;
}
else if ( colattr . _Precision > 0 )
{
colattr . DbType = $"DATETIME YEAR TO FRACTION({colattr.Precision})" ;
col . DbPrecision = ( byte ) colattr . Precision ;
}
}
}
if ( colattr . ServerTime ! = DateTimeKind . Unspecified & & new [ ] { typeof ( DateTime ) , typeof ( DateTimeOffset ) } . Contains ( colattr . MapType . NullableTypeOrThis ( ) ) )
{
var commonNow = common . Now ;
var commonNowUtc = common . NowUtc ;
switch ( common . _orm . Ado . DataType )
{
case DataType . MySql :
case DataType . OdbcMySql : //处理毫秒
case DataType . CustomMySql :
var timeLength = 0 ;
var mTimeLength = Regex . Match ( colattr . DbType , @"(DATETIME|TIMESTAMP)\s*\((\d+)\)" ) ;
if ( mTimeLength . Success ) timeLength = int . Parse ( mTimeLength . Groups [ 2 ] . Value ) ;
if ( timeLength > 0 & & timeLength < 7 )
{
commonNow = $"{commonNow.TrimEnd('(', ')')}({timeLength})" ;
commonNowUtc = $"{commonNowUtc.TrimEnd('(', ')')}({timeLength})" ;
}
//https://github.com/dotnetcore/FreeSql/issues/1604 mysql 不支持默认值 utc_timestamp DDL
if ( colattr . ServerTime = = DateTimeKind . Local )
col . DbDefaultValue = commonNow ;
break ;
default :
col . DbDefaultValue = colattr . ServerTime = = DateTimeKind . Local ? commonNow : commonNowUtc ;
break ;
}
col . DbInsertValue = colattr . ServerTime = = DateTimeKind . Local ? commonNow : commonNowUtc ;
col . DbUpdateValue = colattr . ServerTime = = DateTimeKind . Local ? commonNow : commonNowUtc ;
}
if ( string . IsNullOrEmpty ( colattr . InsertValueSql ) = = false )
{
col . DbDefaultValue = colattr . InsertValueSql ;
col . DbInsertValue = colattr . InsertValueSql ;
}
if ( colattr . MapType . NullableTypeOrThis ( ) = = typeof ( string ) & & colattr . StringLength ! = 0 )
{
int strlen = colattr . StringLength ;
var charPatten = @"(CHARACTER|CHAR2|CHAR)\s*(\([^\)]*\))?" ;
var strNotNull = colattr . IsNullable = = false ? " NOT NULL" : "" ;
switch ( common . _orm . Ado . DataType )
{
case DataType . MySql :
case DataType . OdbcMySql :
case DataType . CustomMySql :
if ( strlen = = - 2 ) colattr . DbType = $"LONGTEXT{strNotNull}" ;
else if ( strlen < 0 ) colattr . DbType = $"TEXT{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . SqlServer :
case DataType . OdbcSqlServer :
case DataType . CustomSqlServer :
if ( strlen < 0 ) colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1(MAX)" ) ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . PostgreSQL :
case DataType . OdbcPostgreSQL :
case DataType . CustomPostgreSQL :
case DataType . KingbaseES :
case DataType . OdbcKingbaseES :
case DataType . ShenTong :
if ( strlen < 0 ) colattr . DbType = $"TEXT{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . Oracle :
case DataType . CustomOracle :
if ( strlen < 0 ) colattr . DbType = $"NCLOB{strNotNull}" ; //v1.3.2+ https://github.com/dotnetcore/FreeSql/issues/259
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . Dameng :
if ( strlen < 0 ) colattr . DbType = $"TEXT{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . OdbcOracle :
case DataType . OdbcDameng :
if ( strlen < 0 ) colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1(4000)" ) ; //ODBC 不支持 NCLOB
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . Sqlite :
if ( strlen < 0 ) colattr . DbType = $"TEXT{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . MsAccess :
charPatten = @"(CHAR|CHAR2|CHARACTER|TEXT)\s*(\([^\)]*\))?" ;
if ( strlen < 0 ) colattr . DbType = $"LONGTEXT{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . Firebird :
charPatten = @"(CHAR|CHAR2|CHARACTER|TEXT)\s*(\([^\)]*\))?" ;
if ( strlen < 0 ) colattr . DbType = $"BLOB SUB_TYPE 1{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . GBase :
if ( strlen < 0 ) colattr . DbType = $"TEXT{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
}
}
if ( colattr . MapType = = typeof ( string ) & & colattr . IsVersion = = true ) colattr . StringLength = 40 ;
if ( colattr . MapType = = typeof ( byte [ ] ) & & colattr . IsVersion = = true ) colattr . StringLength = 16 ; // 8=sqlserver timestamp, 16=GuidToBytes
if ( colattr . MapType = = typeof ( byte [ ] ) & & colattr . StringLength ! = 0 )
{
int strlen = colattr . StringLength ;
var bytePatten = @"(VARBINARY|BINARY|BYTEA)\s*(\([^\)]*\))?" ;
var strNotNull = colattr . IsNullable = = false ? " NOT NULL" : "" ;
switch ( common . _orm . Ado . DataType )
{
case DataType . MySql :
case DataType . OdbcMySql :
case DataType . CustomMySql :
if ( strlen = = - 2 ) colattr . DbType = $"LONGBLOB{strNotNull}" ;
else if ( strlen < 0 ) colattr . DbType = $"BLOB{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , bytePatten , $"$1({strlen})" ) ;
break ;
case DataType . SqlServer :
case DataType . OdbcSqlServer :
case DataType . CustomSqlServer :
if ( strlen < 0 ) colattr . DbType = Regex . Replace ( colattr . DbType , bytePatten , $"$1(MAX)" ) ;
else colattr . DbType = Regex . Replace ( colattr . DbType , bytePatten , $"$1({strlen})" ) ;
break ;
case DataType . PostgreSQL :
case DataType . OdbcPostgreSQL :
case DataType . CustomPostgreSQL :
case DataType . KingbaseES :
case DataType . OdbcKingbaseES :
case DataType . ShenTong : //驱动引发的异常:“System.Data.OscarClient.OscarException”(位于 System.Data.OscarClient.dll 中)
colattr . DbType = $"BYTEA{strNotNull}" ; //变长二进制串
break ;
case DataType . Oracle :
case DataType . CustomOracle :
colattr . DbType = $"BLOB{strNotNull}" ;
break ;
case DataType . Dameng :
colattr . DbType = $"BLOB{strNotNull}" ;
break ;
case DataType . OdbcOracle :
case DataType . OdbcDameng :
colattr . DbType = $"BLOB{strNotNull}" ;
break ;
case DataType . Sqlite :
colattr . DbType = $"BLOB{strNotNull}" ;
break ;
case DataType . MsAccess :
if ( strlen < 0 ) colattr . DbType = $"BLOB{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , bytePatten , $"$1({strlen})" ) ;
break ;
case DataType . Firebird :
colattr . DbType = $"BLOB{strNotNull}" ;
break ;
case DataType . GBase :
colattr . DbType = $"BYTE{strNotNull}" ;
break ;
}
}
if ( colattr . MapType . NullableTypeOrThis ( ) = = typeof ( decimal ) & & ( colattr . Precision > 0 | | colattr . Scale > 0 ) )
{
if ( colattr . Precision < = 0 ) colattr . Precision = 10 ;
if ( colattr . Scale < = 0 ) colattr . Scale = 0 ;
var decimalPatten = @"(DECIMAL|NUMERIC|NUMBER)\s*(\([^\)]*\))?" ;
colattr . DbType = Regex . Replace ( colattr . DbType , decimalPatten , $"$1({colattr.Precision},{colattr.Scale})" ) ;
}
if ( trytb . Columns . ContainsKey ( colattr . Name ) ) throw new Exception ( CoreStrings . Duplicate_ColumnAttribute ( colattr . Name ) ) ;
if ( trytb . ColumnsByCs . ContainsKey ( p . Name ) ) throw new Exception ( CoreStrings . Duplicate_PropertyName ( p . Name ) ) ;
trytb . Columns . Add ( colattr . Name , col ) ;
trytb . Columns . Add ( colattr . Name , c ol) ;
trytb . ColumnsByCs . Add ( p . Name , col ) ;
columnsList . Add ( col ) ;
}
trytb . VersionColumn = trytb . Columns . Values . Where ( a = > a . Attribute . IsVersion = = true ) . LastOrDefault ( ) ;
if ( trytb . VersionColumn ! = null )
{
if ( trytb . VersionColumn . Attribute . MapType . IsNullableType ( ) | |
trytb . VersionColumn . Attribute . MapType . IsNumberType ( ) = = false & & ! new [ ] { typeof ( byte [ ] ) , typeof ( string ) } . Contains ( trytb . VersionColumn . Attribute . MapType ) )
throw new Exception ( CoreStrings . Properties_AsRowLock_Must_Numeric_Byte ( trytb . VersionColumn . CsName ) ) ;
}
tbattr ? . ParseAsTable ( trytb ) ;
var indexesDict = new Dictionary < string , IndexInfo > ( StringComparer . CurrentCultureIgnoreCase ) ;
//从数据库查找主键、自增、索引
if ( common . CodeFirst . IsConfigEntityFromDbFirst )
{
try
{
if ( common . _orm . DbFirst ! = null )
{
if ( common . dbTables = = null )
lock ( common . dbTablesLock )
if ( common . dbTables = = null )
common . dbTables = common . _orm . DbFirst . GetTablesByDatabase ( ) ;
var finddbtbs = common . dbTables . Where ( a = > string . Compare ( a . Name , trytb . CsName , true ) = = 0 | | string . Compare ( a . Name , trytb . DbName , true ) = = 0 ) ;
foreach ( var dbtb in finddbtbs )
{
foreach ( var dbident in dbtb . Identitys )
{
if ( trytb . Columns . TryGetValue ( dbident . Name , out var trycol ) & & trycol . Attribute . MapType . NullableTypeOrThis ( ) = = dbident . CsType . NullableTypeOrThis ( ) | |
trytb . ColumnsByCs . TryGetValue ( dbident . Name , out trycol ) & & trycol . Attribute . MapType . NullableTypeOrThis ( ) = = dbident . CsType . NullableTypeOrThis ( ) )
trycol . Attribute . IsIdentity = true ;
}
foreach ( var dbpk in dbtb . Primarys )
{
if ( trytb . Columns . TryGetValue ( dbpk . Name , out var trycol ) & & trycol . Attribute . MapType . NullableTypeOrThis ( ) = = dbpk . CsType . NullableTypeOrThis ( ) | |
trytb . ColumnsByCs . TryGetValue ( dbpk . Name , out trycol ) & & trycol . Attribute . MapType . NullableTypeOrThis ( ) = = dbpk . CsType . NullableTypeOrThis ( ) )
trycol . Attribute . IsPrimary = true ;
}
foreach ( var dbidx in dbtb . IndexesDict )
{
var indexColumns = new List < IndexColumnInfo > ( ) ;
foreach ( var dbcol in dbidx . Value . Columns )
{
if ( trytb . Columns . TryGetValue ( dbcol . Column . Name , out var trycol ) & & trycol . Attribute . MapType . NullableTypeOrThis ( ) = = dbcol . Column . CsType . NullableTypeOrThis ( ) | |
trytb . ColumnsByCs . TryGetValue ( dbcol . Column . Name , out trycol ) & & trycol . Attribute . MapType . NullableTypeOrThis ( ) = = dbcol . Column . CsType . NullableTypeOrThis ( ) )
indexColumns . Add ( new IndexColumnInfo
{
Column = trycol ,
IsDesc = dbcol . IsDesc
} ) ;
}
if ( indexColumns . Any ( ) = = false ) continue ;
if ( indexesDict . ContainsKey ( dbidx . Key ) ) indexesDict . Remove ( dbidx . Key ) ;
indexesDict . Add ( dbidx . Key , new IndexInfo
{
Name = dbidx . Key ,
Columns = indexColumns . ToArray ( ) ,
IsUnique = dbidx . Value . IsUnique ,
IndexMethod = IndexMethod . B_Tree
} ) ;
}
}
}
}
catch { }
}
//索引和唯一键
var indexes = common . GetEntityIndexAttribute ( trytb . Type ) ;
foreach ( var index in indexes )
{
var val = index . Fields ? . Trim ( ' ' , '\t' , ',' ) ;
if ( string . IsNullOrEmpty ( val ) ) continue ;
var arr = val . Split ( ',' ) . Select ( a = > a . Trim ( ' ' , '\t' ) . Trim ( ) ) . Where ( a = > ! string . IsNullOrEmpty ( a ) ) . ToArray ( ) ;
if ( arr . Any ( ) = = false ) continue ;
var indexColumns = new List < IndexColumnInfo > ( ) ;
foreach ( var field in arr )
{
var idxcol = new IndexColumnInfo ( ) ;
if ( field . EndsWith ( " DESC" , StringComparison . CurrentCultureIgnoreCase ) ) idxcol . IsDesc = true ;
var colname = Regex . Replace ( field , " (DESC|ASC)" , "" , RegexOptions . IgnoreCase ) ;
if ( trytb . ColumnsByCs . TryGetValue ( colname , out var trycol ) | | trytb . Columns . TryGetValue ( colname , out trycol ) )
{
idxcol . Column = trycol ;
indexColumns . Add ( idxcol ) ;
}
}
if ( indexColumns . Any ( ) = = false ) continue ;
var indexName = common . CodeFirst . IsSyncStructureToLower ? index . Name . ToLower ( ) : ( common . CodeFirst . IsSyncStructureToUpper ? index . Name . ToUpper ( ) : index . Name ) ;
if ( indexesDict . ContainsKey ( indexName ) ) indexesDict . Remove ( indexName ) ;
indexesDict . Add ( indexName , new IndexInfo
{
Name = indexName ,
Columns = indexColumns . ToArray ( ) ,
IsUnique = index . IsUnique ,
IndexMethod = index . IndexMethod
} ) ;
}
trytb . Indexes = indexesDict . Values . ToArray ( ) ;
trytb . Primarys = trytb . Columns . Values . Where ( a = > a . Attribute . IsPrimary = = true ) . ToArray ( ) ;
if ( trytb . Primarys . Any ( ) = = false )
{
trytb . Primarys = trytb . Columns . Values . Where ( a = > a . Attribute . _IsPrimary = = null & & string . Compare ( a . Attribute . Name , "id" , true ) = = 0 ) . ToArray ( ) ;
if ( trytb . Primarys . Any ( ) = = false )
{
var identcol = trytb . Columns . Values . Where ( a = > a . Attribute . IsIdentity = = true ) . FirstOrDefault ( ) ;
if ( identcol ! = null ) trytb . Primarys = new [ ] { identcol } ;
if ( trytb . Primarys . Any ( ) = = false )
{
trytb . Primarys = trytb . Columns . Values . Where ( a = > a . Attribute . _IsPrimary = = null & & string . Compare ( a . Attribute . Name , $"{trytb.DbName}id" , true ) = = 0 ) . ToArray ( ) ;
if ( trytb . Primarys . Any ( ) = = false )
{
trytb . Primarys = trytb . Columns . Values . Where ( a = > a . Attribute . _IsPrimary = = null & & string . Compare ( a . Attribute . Name , $"{trytb.DbName}_id" , true ) = = 0 ) . ToArray ( ) ;
}
}
}
foreach ( var col in trytb . Primarys )
col . Attribute . IsPrimary = true ;
}
foreach ( var col in trytb . Primarys )
{
col . Attribute . IsNullable = false ;
col . Attribute . DbType = col . Attribute . DbType . Replace ( "NOT NULL" , "" ) . Replace ( " NULL" , "" ) . Trim ( ) ;
switch ( common . _orm . Ado . DataType )
{
case DataType . Sqlite :
col . Attribute . DbType + = " NOT NULL" ; //sqlite 主键也可以插入 null
break ;
}
}
foreach ( var col in trytb . Columns . Values )
{
if ( col . Attribute . IsPrimary = = false & & col . Attribute . IsIdentity ) col . Attribute . CanUpdate = false ;
var ltp = @"\(([^\)]+)\)" ;
col . DbTypeText = Regex . Replace ( col . Attribute . DbType . Replace ( "NOT NULL" , "" ) . Replace ( " NULL" , "" ) . Trim ( ) , ltp , "" ) ;
var m = Regex . Match ( col . Attribute . DbType , ltp ) ;
if ( m . Success = = false ) continue ;
var sizeStr = m . Groups [ 1 ] . Value . Trim ( ) ;
if ( sizeStr . EndsWith ( " BYTE" ) | | sizeStr . EndsWith ( " CHAR" ) ) sizeStr = sizeStr . Remove ( sizeStr . Length - 5 ) ; //ORACLE
if ( string . Compare ( sizeStr , "max" , true ) = = 0 )
{
col . DbSize = - 1 ;
continue ;
}
var sizeArr = sizeStr . Split ( ',' ) ;
if ( int . TryParse ( sizeArr [ 0 ] . Trim ( ) , out var size ) = = false ) continue ;
if ( col . Attribute . MapType . NullableTypeOrThis ( ) = = typeof ( DateTime ) )
{
col . DbScale = ( byte ) size ;
if ( col . Attribute . Scale < = 0 ) col . Attribute . Scale = col . DbScale ;
continue ;
}
if ( sizeArr . Length = = 1 )
{
col . DbSize = size ;
if ( col . Attribute . StringLength < = 0 ) col . Attribute . StringLength = col . DbSize ;
continue ;
}
if ( byte . TryParse ( sizeArr [ 1 ] , out var scale ) = = false ) continue ;
col . DbPrecision = ( byte ) size ;
col . DbScale = scale ;
if ( col . Attribute . Precision < = 0 )
{
col . Attribute . Precision = col . DbPrecision ;
col . Attribute . Scale = col . DbScale ;
}
}
trytb . IsRereadSql = trytb . Columns . Where ( a = > string . IsNullOrWhiteSpace ( a . Value . Attribute . RereadSql ) = = false ) . Any ( ) ;
trytb . ColumnsByPosition = columnsList . Where ( a = > a . Attribute . Position > 0 ) . OrderBy ( a = > a . Attribute . Position )
. Concat ( columnsList . Where ( a = > a . Attribute . Position = = 0 ) )
. Concat ( columnsList . Where ( a = > a . Attribute . Position < 0 ) . OrderBy ( a = > a . Attribute . Position ) ) . ToArray ( ) ;
trytb . ColumnsByCanUpdateDbUpdateValue = columnsList . Where ( a = > a . Attribute . CanUpdate = = true & & string . IsNullOrEmpty ( a . DbUpdateValue ) = = false ) . ToArray ( ) ;
AuditTableInfo ( trytb , tbattr , indexes , columnsList , common ) ;
tbc . AddOrUpdate ( entity , trytb , ( oldkey , oldval ) = > trytb ) ;
#region 查 找 导 航 属 性 的 关 系 、 virtual 属 性 延 时 加 载 , 动 态 产 生 新 的 重 写 类
@ -635,6 +180,475 @@ namespace FreeSql.Internal
return tbc . TryGetValue ( entity , out var trytb2 ) ? trytb2 : trytb ;
}
public static ColumnInfo ColumnAttributeToInfo ( TableInfo trytb , object entityDefault , string csName , Type mapType , bool isIgnore , ref ColumnAttribute colattr , DbInfoResult tp , CommonUtils common )
{
var colattrIsNullable = colattr ? . _IsNullable ;
var colattrIsNull = colattr = = null ;
if ( colattr = = null )
colattr = new ColumnAttribute
{
Name = csName ,
DbType = tp . dbtypeFull ,
IsNullable = tp . isnullable ? ? true ,
MapType = mapType
} ;
if ( colattr . _IsNullable = = null ) colattr . _IsNullable = tp ? . isnullable ;
if ( string . IsNullOrEmpty ( colattr . DbType ) ) colattr . DbType = tp ? . dbtypeFull ? ? "varchar(255)" ;
if ( colattr . DbType . StartsWith ( "set(" ) | | colattr . DbType . StartsWith ( "enum(" ) )
{
var leftBt = colattr . DbType . IndexOf ( '(' ) ;
colattr . DbType = colattr . DbType . Substring ( 0 , leftBt ) . ToUpper ( ) + colattr . DbType . Substring ( leftBt ) ;
}
else if ( common . _orm . Ado . DataType ! = DataType . ClickHouse )
colattr . DbType = colattr . DbType . ToUpper ( ) ;
if ( colattrIsNull = = false & & colattrIsNullable = = true ) colattr . DbType = colattr . DbType . Replace ( "NOT NULL" , "" ) ;
if ( colattrIsNull = = false & & colattrIsNullable = = false & & colattr . DbType . Contains ( "NOT NULL" ) = = false ) colattr . DbType = Regex . Replace ( colattr . DbType , @"\bNULL\b" , "" ) . Trim ( ) + " NOT NULL" ;
if ( colattr . _IsNullable = = null & & tp ! = null & & tp . isnullable = = null ) colattr . IsNullable = tp . dbtypeFull . Contains ( "NOT NULL" ) = = false ;
if ( colattr . DbType ? . Contains ( "NOT NULL" ) = = true ) colattr . IsNullable = false ;
if ( string . IsNullOrEmpty ( colattr . Name ) ) colattr . Name = csName ;
if ( common . CodeFirst . IsSyncStructureToLower ) colattr . Name = colattr . Name . ToLower ( ) ;
if ( common . CodeFirst . IsSyncStructureToUpper ) colattr . Name = colattr . Name . ToUpper ( ) ;
if ( ( colattr . IsNullable ! = true | | colattr . IsIdentity = = true | | colattr . IsPrimary = = true ) & & colattr . DbType . Contains ( "NOT NULL" ) = = false & & common . _orm . Ado . DataType ! = DataType . ClickHouse )
{
colattr . IsNullable = false ;
colattr . DbType = Regex . Replace ( colattr . DbType , @"\bNULL\b" , "" ) . Trim ( ) + " NOT NULL" ;
}
if ( colattr . IsNullable = = true & & colattr . DbType . Contains ( "NOT NULL" ) ) colattr . DbType = colattr . DbType . Replace ( "NOT NULL" , "" ) ;
else if ( colattr . IsNullable = = true & & ! colattr . DbType . Contains ( "Nullable" ) & & common . _orm . Ado . DataType = = DataType . ClickHouse ) colattr . DbType = $"Nullable({colattr.DbType})" ;
colattr . DbType = Regex . Replace ( colattr . DbType , @"\([^\)]+\)" , m = >
{
var tmpLt = Regex . Replace ( m . Groups [ 0 ] . Value , @"\s" , "" ) ;
if ( tmpLt . Contains ( "CHAR" ) ) tmpLt = tmpLt . Replace ( "CHAR" , " CHAR" ) ;
if ( tmpLt . Contains ( "BYTE" ) ) tmpLt = tmpLt . Replace ( "BYTE" , " BYTE" ) ;
return tmpLt ;
} ) ;
if ( colattr . IsIdentity = = true & & colattr . MapType . IsNumberType ( ) = = false )
colattr . IsIdentity = false ;
if ( isIgnore ) colattr . IsIgnore = true ;
var col = new ColumnInfo
{
Table = trytb ,
CsName = csName ,
CsType = mapType ,
Attribute = colattr
} ;
if ( colattr . IsIgnore )
{
trytb . ColumnsByCsIgnore . Add ( csName , col ) ;
return null ;
}
object defaultValue = null ;
if ( entityDefault ! = null ) defaultValue = trytb . Properties [ csName ] . GetValue ( entityDefault , null ) ;
if ( defaultValue ! = null & & mapType . IsEnum )
{
var isEqualsEnumValue = false ;
var enumValues = Enum . GetValues ( mapType ) ;
for ( var a = 0 ; a < enumValues . Length ; a + + )
if ( object . Equals ( defaultValue , enumValues . GetValue ( a ) ) )
{
isEqualsEnumValue = true ;
break ;
}
if ( isEqualsEnumValue = = false & & enumValues . Length > 0 )
defaultValue = enumValues . GetValue ( 0 ) ;
}
if ( defaultValue ! = null & & mapType ! = colattr . MapType ) defaultValue = Utils . GetDataReaderValue ( colattr . MapType , defaultValue ) ;
if ( defaultValue = = null ) defaultValue = tp ? . defaultValue ;
if ( colattr . IsNullable = = false & & defaultValue = = null )
{
var citype = colattr . MapType . IsNullableType ( ) ? colattr . MapType . GetGenericArguments ( ) . FirstOrDefault ( ) : colattr . MapType ;
defaultValue = citype . CreateInstanceGetDefaultValue ( ) ;
}
try
{
var initParms = new List < DbParameter > ( ) ;
col . DbDefaultValue = common . GetNoneParamaterSqlValue ( initParms , "init" , col , colattr . MapType , defaultValue ) ;
if ( initParms . Any ( ) ) col . DbDefaultValue = "NULL" ;
}
catch
{
col . DbDefaultValue = "NULL" ;
}
//if (defaultValue != null && colattr.MapType.NullableTypeOrThis() == typeof(DateTime))
//{
// var dt = (DateTime)defaultValue;
// if (Math.Abs(dt.Subtract(DateTime.Now).TotalSeconds) < 60)
// col.DbDefaultValue = common.Now;
// else if (Math.Abs(dt.Subtract(DateTime.UtcNow).TotalSeconds) < 60)
// col.DbDefaultValue = common.NowUtc;
//}
if ( common . _orm . Ado . DataType = = DataType . GBase )
{
if ( colattr . IsIdentity = = true )
{
var colType = col . CsType . NullableTypeOrThis ( ) ;
if ( colType = = typeof ( int ) | | colType = = typeof ( uint ) )
colattr . DbType = "SERIAL" ;
else if ( colType = = typeof ( long ) | | colType = = typeof ( ulong ) )
colattr . DbType = "SERIAL8" ;
}
if ( colattr . MapType . NullableTypeOrThis ( ) = = typeof ( DateTime ) )
{
if ( colattr . _Precision = = null )
{
colattr . DbType = "DATETIME YEAR TO FRACTION(3)" ;
colattr . Precision = 3 ;
col . DbPrecision = 3 ;
}
else if ( colattr . _Precision = = 0 )
{
colattr . DbType = "DATETIME YEAR TO SECOND" ;
}
else if ( colattr . _Precision > 0 )
{
colattr . DbType = $"DATETIME YEAR TO FRACTION({colattr.Precision})" ;
col . DbPrecision = ( byte ) colattr . Precision ;
}
}
}
if ( colattr . ServerTime ! = DateTimeKind . Unspecified & & new [ ] { typeof ( DateTime ) , typeof ( DateTimeOffset ) } . Contains ( colattr . MapType . NullableTypeOrThis ( ) ) )
{
var commonNow = common . Now ;
var commonNowUtc = common . NowUtc ;
switch ( common . _orm . Ado . DataType )
{
case DataType . MySql :
case DataType . OdbcMySql : //处理毫秒
case DataType . CustomMySql :
var timeLength = 0 ;
var mTimeLength = Regex . Match ( colattr . DbType , @"(DATETIME|TIMESTAMP)\s*\((\d+)\)" ) ;
if ( mTimeLength . Success ) timeLength = int . Parse ( mTimeLength . Groups [ 2 ] . Value ) ;
if ( timeLength > 0 & & timeLength < 7 )
{
commonNow = $"{commonNow.TrimEnd('(', ')')}({timeLength})" ;
commonNowUtc = $"{commonNowUtc.TrimEnd('(', ')')}({timeLength})" ;
}
//https://github.com/dotnetcore/FreeSql/issues/1604 mysql 不支持默认值 utc_timestamp DDL
if ( colattr . ServerTime = = DateTimeKind . Local )
col . DbDefaultValue = commonNow ;
break ;
default :
col . DbDefaultValue = colattr . ServerTime = = DateTimeKind . Local ? commonNow : commonNowUtc ;
break ;
}
col . DbInsertValue = colattr . ServerTime = = DateTimeKind . Local ? commonNow : commonNowUtc ;
col . DbUpdateValue = colattr . ServerTime = = DateTimeKind . Local ? commonNow : commonNowUtc ;
}
if ( string . IsNullOrEmpty ( colattr . InsertValueSql ) = = false )
{
col . DbDefaultValue = colattr . InsertValueSql ;
col . DbInsertValue = colattr . InsertValueSql ;
}
if ( colattr . MapType . NullableTypeOrThis ( ) = = typeof ( string ) & & colattr . StringLength ! = 0 )
{
int strlen = colattr . StringLength ;
var charPatten = @"(CHARACTER|CHAR2|CHAR)\s*(\([^\)]*\))?" ;
var strNotNull = colattr . IsNullable = = false ? " NOT NULL" : "" ;
switch ( common . _orm . Ado . DataType )
{
case DataType . MySql :
case DataType . OdbcMySql :
case DataType . CustomMySql :
if ( strlen = = - 2 ) colattr . DbType = $"LONGTEXT{strNotNull}" ;
else if ( strlen < 0 ) colattr . DbType = $"TEXT{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . SqlServer :
case DataType . OdbcSqlServer :
case DataType . CustomSqlServer :
if ( strlen < 0 ) colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1(MAX)" ) ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . PostgreSQL :
case DataType . OdbcPostgreSQL :
case DataType . CustomPostgreSQL :
case DataType . KingbaseES :
case DataType . OdbcKingbaseES :
case DataType . ShenTong :
if ( strlen < 0 ) colattr . DbType = $"TEXT{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . Oracle :
case DataType . CustomOracle :
if ( strlen < 0 ) colattr . DbType = $"NCLOB{strNotNull}" ; //v1.3.2+ https://github.com/dotnetcore/FreeSql/issues/259
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . Dameng :
if ( strlen < 0 ) colattr . DbType = $"TEXT{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . OdbcOracle :
case DataType . OdbcDameng :
if ( strlen < 0 ) colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1(4000)" ) ; //ODBC 不支持 NCLOB
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . Sqlite :
if ( strlen < 0 ) colattr . DbType = $"TEXT{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . MsAccess :
charPatten = @"(CHAR|CHAR2|CHARACTER|TEXT)\s*(\([^\)]*\))?" ;
if ( strlen < 0 ) colattr . DbType = $"LONGTEXT{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . Firebird :
charPatten = @"(CHAR|CHAR2|CHARACTER|TEXT)\s*(\([^\)]*\))?" ;
if ( strlen < 0 ) colattr . DbType = $"BLOB SUB_TYPE 1{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
case DataType . GBase :
if ( strlen < 0 ) colattr . DbType = $"TEXT{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , charPatten , $"$1({strlen})" ) ;
break ;
}
}
if ( colattr . MapType = = typeof ( string ) & & colattr . IsVersion = = true ) colattr . StringLength = 40 ;
if ( colattr . MapType = = typeof ( byte [ ] ) & & colattr . IsVersion = = true ) colattr . StringLength = 16 ; // 8=sqlserver timestamp, 16=GuidToBytes
if ( colattr . MapType = = typeof ( byte [ ] ) & & colattr . StringLength ! = 0 )
{
int strlen = colattr . StringLength ;
var bytePatten = @"(VARBINARY|BINARY|BYTEA)\s*(\([^\)]*\))?" ;
var strNotNull = colattr . IsNullable = = false ? " NOT NULL" : "" ;
switch ( common . _orm . Ado . DataType )
{
case DataType . MySql :
case DataType . OdbcMySql :
case DataType . CustomMySql :
if ( strlen = = - 2 ) colattr . DbType = $"LONGBLOB{strNotNull}" ;
else if ( strlen < 0 ) colattr . DbType = $"BLOB{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , bytePatten , $"$1({strlen})" ) ;
break ;
case DataType . SqlServer :
case DataType . OdbcSqlServer :
case DataType . CustomSqlServer :
if ( strlen < 0 ) colattr . DbType = Regex . Replace ( colattr . DbType , bytePatten , $"$1(MAX)" ) ;
else colattr . DbType = Regex . Replace ( colattr . DbType , bytePatten , $"$1({strlen})" ) ;
break ;
case DataType . PostgreSQL :
case DataType . OdbcPostgreSQL :
case DataType . CustomPostgreSQL :
case DataType . KingbaseES :
case DataType . OdbcKingbaseES :
case DataType . ShenTong : //驱动引发的异常:“System.Data.OscarClient.OscarException”(位于 System.Data.OscarClient.dll 中)
colattr . DbType = $"BYTEA{strNotNull}" ; //变长二进制串
break ;
case DataType . Oracle :
case DataType . CustomOracle :
colattr . DbType = $"BLOB{strNotNull}" ;
break ;
case DataType . Dameng :
colattr . DbType = $"BLOB{strNotNull}" ;
break ;
case DataType . OdbcOracle :
case DataType . OdbcDameng :
colattr . DbType = $"BLOB{strNotNull}" ;
break ;
case DataType . Sqlite :
colattr . DbType = $"BLOB{strNotNull}" ;
break ;
case DataType . MsAccess :
if ( strlen < 0 ) colattr . DbType = $"BLOB{strNotNull}" ;
else colattr . DbType = Regex . Replace ( colattr . DbType , bytePatten , $"$1({strlen})" ) ;
break ;
case DataType . Firebird :
colattr . DbType = $"BLOB{strNotNull}" ;
break ;
case DataType . GBase :
colattr . DbType = $"BYTE{strNotNull}" ;
break ;
}
}
if ( colattr . MapType . NullableTypeOrThis ( ) = = typeof ( decimal ) & & ( colattr . Precision > 0 | | colattr . Scale > 0 ) )
{
if ( colattr . Precision < = 0 ) colattr . Precision = 10 ;
if ( colattr . Scale < = 0 ) colattr . Scale = 0 ;
var decimalPatten = @"(DECIMAL|NUMERIC|NUMBER)\s*(\([^\)]*\))?" ;
colattr . DbType = Regex . Replace ( colattr . DbType , decimalPatten , $"$1({colattr.Precision},{colattr.Scale})" ) ;
}
if ( trytb . Columns . ContainsKey ( colattr . Name ) ) throw new Exception ( CoreStrings . Duplicate_ColumnAttribute ( colattr . Name ) ) ;
if ( trytb . ColumnsByCs . ContainsKey ( csName ) ) throw new Exception ( CoreStrings . Duplicate_PropertyName ( csName ) ) ;
return col ;
}
public static void AuditTableInfo ( TableInfo trytb , TableAttribute tbattr , IEnumerable < IndexAttribute > indexes , List < ColumnInfo > columnsList , CommonUtils common )
{
trytb . VersionColumn = trytb . Columns . Values . Where ( a = > a . Attribute . IsVersion = = true ) . LastOrDefault ( ) ;
if ( trytb . VersionColumn ! = null )
{
if ( trytb . VersionColumn . Attribute . MapType . IsNullableType ( ) | |
trytb . VersionColumn . Attribute . MapType . IsNumberType ( ) = = false & & ! new [ ] { typeof ( byte [ ] ) , typeof ( string ) } . Contains ( trytb . VersionColumn . Attribute . MapType ) )
throw new Exception ( CoreStrings . Properties_AsRowLock_Must_Numeric_Byte ( trytb . VersionColumn . CsName ) ) ;
}
tbattr ? . ParseAsTable ( trytb ) ;
var indexesDict = new Dictionary < string , IndexInfo > ( StringComparer . CurrentCultureIgnoreCase ) ;
//从数据库查找主键、自增、索引
if ( common . CodeFirst . IsConfigEntityFromDbFirst )
{
try
{
if ( common . _orm . DbFirst ! = null )
{
if ( common . dbTables = = null )
lock ( common . dbTablesLock )
if ( common . dbTables = = null )
common . dbTables = common . _orm . DbFirst . GetTablesByDatabase ( ) ;
var finddbtbs = common . dbTables . Where ( a = > string . Compare ( a . Name , trytb . CsName , true ) = = 0 | | string . Compare ( a . Name , trytb . DbName , true ) = = 0 ) ;
foreach ( var dbtb in finddbtbs )
{
foreach ( var dbident in dbtb . Identitys )
{
if ( trytb . Columns . TryGetValue ( dbident . Name , out var trycol ) & & trycol . Attribute . MapType . NullableTypeOrThis ( ) = = dbident . CsType . NullableTypeOrThis ( ) | |
trytb . ColumnsByCs . TryGetValue ( dbident . Name , out trycol ) & & trycol . Attribute . MapType . NullableTypeOrThis ( ) = = dbident . CsType . NullableTypeOrThis ( ) )
trycol . Attribute . IsIdentity = true ;
}
foreach ( var dbpk in dbtb . Primarys )
{
if ( trytb . Columns . TryGetValue ( dbpk . Name , out var trycol ) & & trycol . Attribute . MapType . NullableTypeOrThis ( ) = = dbpk . CsType . NullableTypeOrThis ( ) | |
trytb . ColumnsByCs . TryGetValue ( dbpk . Name , out trycol ) & & trycol . Attribute . MapType . NullableTypeOrThis ( ) = = dbpk . CsType . NullableTypeOrThis ( ) )
trycol . Attribute . IsPrimary = true ;
}
foreach ( var dbidx in dbtb . IndexesDict )
{
var indexColumns = new List < IndexColumnInfo > ( ) ;
foreach ( var dbcol in dbidx . Value . Columns )
{
if ( trytb . Columns . TryGetValue ( dbcol . Column . Name , out var trycol ) & & trycol . Attribute . MapType . NullableTypeOrThis ( ) = = dbcol . Column . CsType . NullableTypeOrThis ( ) | |
trytb . ColumnsByCs . TryGetValue ( dbcol . Column . Name , out trycol ) & & trycol . Attribute . MapType . NullableTypeOrThis ( ) = = dbcol . Column . CsType . NullableTypeOrThis ( ) )
indexColumns . Add ( new IndexColumnInfo
{
Column = trycol ,
IsDesc = dbcol . IsDesc
} ) ;
}
if ( indexColumns . Any ( ) = = false ) continue ;
if ( indexesDict . ContainsKey ( dbidx . Key ) ) indexesDict . Remove ( dbidx . Key ) ;
indexesDict . Add ( dbidx . Key , new IndexInfo
{
Name = dbidx . Key ,
Columns = indexColumns . ToArray ( ) ,
IsUnique = dbidx . Value . IsUnique ,
IndexMethod = IndexMethod . B_Tree
} ) ;
}
}
}
}
catch { }
}
//索引和唯一键
foreach ( var index in indexes )
{
var val = index . Fields ? . Trim ( ' ' , '\t' , ',' ) ;
if ( string . IsNullOrEmpty ( val ) ) continue ;
var arr = val . Split ( ',' ) . Select ( a = > a . Trim ( ' ' , '\t' ) . Trim ( ) ) . Where ( a = > ! string . IsNullOrEmpty ( a ) ) . ToArray ( ) ;
if ( arr . Any ( ) = = false ) continue ;
var indexColumns = new List < IndexColumnInfo > ( ) ;
foreach ( var field in arr )
{
var idxcol = new IndexColumnInfo ( ) ;
if ( field . EndsWith ( " DESC" , StringComparison . CurrentCultureIgnoreCase ) ) idxcol . IsDesc = true ;
var colname = Regex . Replace ( field , " (DESC|ASC)" , "" , RegexOptions . IgnoreCase ) ;
if ( trytb . ColumnsByCs . TryGetValue ( colname , out var trycol ) | | trytb . Columns . TryGetValue ( colname , out trycol ) )
{
idxcol . Column = trycol ;
indexColumns . Add ( idxcol ) ;
}
}
if ( indexColumns . Any ( ) = = false ) continue ;
var indexName = common . CodeFirst . IsSyncStructureToLower ? index . Name . ToLower ( ) : ( common . CodeFirst . IsSyncStructureToUpper ? index . Name . ToUpper ( ) : index . Name ) ;
if ( indexesDict . ContainsKey ( indexName ) ) indexesDict . Remove ( indexName ) ;
indexesDict . Add ( indexName , new IndexInfo
{
Name = indexName ,
Columns = indexColumns . ToArray ( ) ,
IsUnique = index . IsUnique ,
IndexMethod = index . IndexMethod
} ) ;
}
trytb . Indexes = indexesDict . Values . ToArray ( ) ;
trytb . Primarys = trytb . Columns . Values . Where ( a = > a . Attribute . IsPrimary = = true ) . ToArray ( ) ;
if ( trytb . Primarys . Any ( ) = = false )
{
trytb . Primarys = trytb . Columns . Values . Where ( a = > a . Attribute . _IsPrimary = = null & & string . Compare ( a . Attribute . Name , "id" , true ) = = 0 ) . ToArray ( ) ;
if ( trytb . Primarys . Any ( ) = = false )
{
var identcol = trytb . Columns . Values . Where ( a = > a . Attribute . IsIdentity = = true ) . FirstOrDefault ( ) ;
if ( identcol ! = null ) trytb . Primarys = new [ ] { identcol } ;
if ( trytb . Primarys . Any ( ) = = false )
{
trytb . Primarys = trytb . Columns . Values . Where ( a = > a . Attribute . _IsPrimary = = null & & string . Compare ( a . Attribute . Name , $"{trytb.DbName}id" , true ) = = 0 ) . ToArray ( ) ;
if ( trytb . Primarys . Any ( ) = = false )
{
trytb . Primarys = trytb . Columns . Values . Where ( a = > a . Attribute . _IsPrimary = = null & & string . Compare ( a . Attribute . Name , $"{trytb.DbName}_id" , true ) = = 0 ) . ToArray ( ) ;
}
}
}
foreach ( var col in trytb . Primarys )
col . Attribute . IsPrimary = true ;
}
foreach ( var col in trytb . Primarys )
{
col . Attribute . IsNullable = false ;
col . Attribute . DbType = col . Attribute . DbType . Replace ( "NOT NULL" , "" ) . Replace ( " NULL" , "" ) . Trim ( ) ;
switch ( common . _orm . Ado . DataType )
{
case DataType . Sqlite :
col . Attribute . DbType + = " NOT NULL" ; //sqlite 主键也可以插入 null
break ;
}
}
foreach ( var col in trytb . Columns . Values )
{
if ( col . Attribute . IsPrimary = = false & & col . Attribute . IsIdentity ) col . Attribute . CanUpdate = false ;
var ltp = @"\(([^\)]+)\)" ;
col . DbTypeText = Regex . Replace ( col . Attribute . DbType . Replace ( "NOT NULL" , "" ) . Replace ( " NULL" , "" ) . Trim ( ) , ltp , "" ) ;
var m = Regex . Match ( col . Attribute . DbType , ltp ) ;
if ( m . Success = = false ) continue ;
var sizeStr = m . Groups [ 1 ] . Value . Trim ( ) ;
if ( sizeStr . EndsWith ( " BYTE" ) | | sizeStr . EndsWith ( " CHAR" ) ) sizeStr = sizeStr . Remove ( sizeStr . Length - 5 ) ; //ORACLE
if ( string . Compare ( sizeStr , "max" , true ) = = 0 )
{
col . DbSize = - 1 ;
continue ;
}
var sizeArr = sizeStr . Split ( ',' ) ;
if ( int . TryParse ( sizeArr [ 0 ] . Trim ( ) , out var size ) = = false ) continue ;
if ( col . Attribute . MapType . NullableTypeOrThis ( ) = = typeof ( DateTime ) )
{
col . DbScale = ( byte ) size ;
if ( col . Attribute . Scale < = 0 ) col . Attribute . Scale = col . DbScale ;
continue ;
}
if ( sizeArr . Length = = 1 )
{
col . DbSize = size ;
if ( col . Attribute . StringLength < = 0 ) col . Attribute . StringLength = col . DbSize ;
continue ;
}
if ( byte . TryParse ( sizeArr [ 1 ] , out var scale ) = = false ) continue ;
col . DbPrecision = ( byte ) size ;
col . DbScale = scale ;
if ( col . Attribute . Precision < = 0 )
{
col . Attribute . Precision = col . DbPrecision ;
col . Attribute . Scale = col . DbScale ;
}
}
trytb . IsRereadSql = trytb . Columns . Where ( a = > string . IsNullOrWhiteSpace ( a . Value . Attribute . RereadSql ) = = false ) . Any ( ) ;
trytb . ColumnsByPosition = columnsList . Where ( a = > a . Attribute . Position > 0 ) . OrderBy ( a = > a . Attribute . Position )
. Concat ( columnsList . Where ( a = > a . Attribute . Position = = 0 ) )
. Concat ( columnsList . Where ( a = > a . Attribute . Position < 0 ) . OrderBy ( a = > a . Attribute . Position ) ) . ToArray ( ) ;
trytb . ColumnsByCanUpdateDbUpdateValue = columnsList . Where ( a = > a . Attribute . CanUpdate = = true & & string . IsNullOrEmpty ( a . DbUpdateValue ) = = false ) . ToArray ( ) ;
}
public static void AddTableRef ( CommonUtils common , TableInfo trytb , PropertyInfo pnv , bool isLazy , NativeTuple < PropertyInfo , bool , bool , MethodInfo , MethodInfo > vp , StringBuilder cscode )
{
var getMethod = vp ? . Item4 ;