Merge branch 'master' of https://git.newlifex.com/NewLife/NewLife.XCode
This commit is contained in:
commit
876a7f38e8
|
@ -38,9 +38,9 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="IBM.Data.DB2.Core" Version="3.1.0.600" />
|
||||
<PackageReference Include="MySql.Data" Version="9.1.0" />
|
||||
<PackageReference Include="NewLife.Redis" Version="6.0.2025.101" />
|
||||
<PackageReference Include="NewLife.Remoting" Version="3.2.2025.101" />
|
||||
<PackageReference Include="NewLife.Stardust" Version="3.2.2025.101" />
|
||||
<PackageReference Include="NewLife.Redis" Version="6.1.2025.301" />
|
||||
<PackageReference Include="NewLife.Remoting" Version="3.3.2025.301" />
|
||||
<PackageReference Include="NewLife.Stardust" Version="3.3.2025.301" />
|
||||
<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="23.7.0" />
|
||||
<PackageReference Include="SapHana.DotNetCore.Data.Provider" Version="2.11.14" />
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.9.0" />
|
||||
|
|
|
@ -253,7 +253,7 @@ public class TableItem
|
|||
}
|
||||
|
||||
// 检查索引重复,最左原则
|
||||
for (var i = 0; i < table.Indexes.Count; i++)
|
||||
for (var i = 0; i < table.Indexes.Count && XCodeSetting.Current.CheckDuplicateIndex; i++)
|
||||
{
|
||||
var di = table.Indexes[i];
|
||||
for (var j = i + 1; j < table.Indexes.Count; j++)
|
||||
|
|
|
@ -70,7 +70,9 @@ public partial class DAL
|
|||
if (db is DbBase dbBase) dbBase.Tracer = Tracer;
|
||||
|
||||
// 设置连接字符串时,可能触发内部的一系列动作,因此放在最后
|
||||
if (!ConnStr.IsNullOrEmpty()) db.ConnectionString = DecodeConnStr(ConnStr);
|
||||
var connStr = ConnStr;
|
||||
if (!_mapConnStr.IsNullOrEmpty()) connStr = _mapConnStr;
|
||||
if (!connStr.IsNullOrEmpty()) db.ConnectionString = DecodeConnStr(connStr);
|
||||
|
||||
_Db = db;
|
||||
|
||||
|
@ -86,6 +88,7 @@ public partial class DAL
|
|||
public IAsyncDbSession AsyncSession => (Db as DbBase)!.CreateSessionForAsync();
|
||||
|
||||
private String? _mapTo;
|
||||
private String? _mapConnStr;
|
||||
private static ICache _cache = new MemoryCache();
|
||||
#endregion
|
||||
|
||||
|
@ -122,12 +125,31 @@ public partial class DAL
|
|||
AddConnStr(connName, connstr, null, "SQLite");
|
||||
}
|
||||
|
||||
ConnStr = css[connName];
|
||||
if (ConnStr.IsNullOrEmpty()) throw new XCodeException("请在使用数据库前设置[" + connName + "]连接字符串");
|
||||
var connStr = ConnStr = css[connName];
|
||||
if (connStr.IsNullOrEmpty()) throw new XCodeException("请在使用数据库前设置[" + connName + "]连接字符串");
|
||||
|
||||
// 连接映射
|
||||
var vs = ConnStr.SplitAsDictionary("=", ",", true);
|
||||
if (vs.TryGetValue("MapTo", out var map) && !map.IsNullOrEmpty()) _mapTo = map;
|
||||
var vs = connStr.SplitAsDictionary("=", ";", true);
|
||||
if (vs.TryGetValue("MapTo", out var map) && !map.IsNullOrEmpty() && !map.EqualIgnoreCase(connName))
|
||||
{
|
||||
// 如果连接字符串除了MapTo还有其它设置,则需要复制后覆盖
|
||||
if (vs.Count <= 1)
|
||||
_mapTo = map;
|
||||
else
|
||||
{
|
||||
var dal = Create(map);
|
||||
var builder = new ConnectionStringBuilder(dal.ConnStr);
|
||||
foreach (var item in vs)
|
||||
{
|
||||
if (!item.Key.EqualIgnoreCase("MapTo"))
|
||||
builder[item.Key] = item.Value;
|
||||
}
|
||||
|
||||
_mapConnStr = builder.ToString();
|
||||
ProviderType = dal.ProviderType;
|
||||
DbType = dal.DbType;
|
||||
}
|
||||
}
|
||||
|
||||
if (_infos!.TryGetValue(connName, out var t) && t.Type != null)
|
||||
{
|
||||
|
@ -620,7 +642,7 @@ public partial class DAL
|
|||
//CheckDatabase();
|
||||
var tables = Db.CreateMetaData().GetTables();
|
||||
|
||||
if (span != null) span.Tag += ": " + tables.Join(",");
|
||||
span?.AppendTag(tables.Join(","), tables.Count);
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Net;
|
|||
using NewLife.Collections;
|
||||
using NewLife.Data;
|
||||
using NewLife.Log;
|
||||
using NewLife.Web;
|
||||
|
||||
namespace XCode.DataAccessLayer;
|
||||
|
||||
|
@ -18,8 +19,14 @@ internal class MySql : RemoteDb
|
|||
/// <returns></returns>
|
||||
protected override DbProviderFactory? CreateFactory()
|
||||
{
|
||||
//_Factory = GetProviderFactory("NewLife.MySql.dll", "NewLife.MySql.MySqlClientFactory") ??
|
||||
// GetProviderFactory("MySql.Data.dll", "MySql.Data.MySqlClient.MySqlClientFactory");
|
||||
var type = PluginHelper.LoadPlugin("NewLife.MySql.MySqlClientFactory", null, "NewLife.MySql.dll", null);
|
||||
var factory = GetProviderFactory(type);
|
||||
if (factory != null) return factory;
|
||||
|
||||
type = PluginHelper.LoadPlugin("MySql.Data.MySqlClient.MySqlClientFactory", null, "MySql.Data.dll", null);
|
||||
factory = GetProviderFactory(type);
|
||||
if (factory != null) return factory;
|
||||
|
||||
// MewLife.MySql 在开发过程中,数据驱动下载站点没有它的包,暂时不支持下载
|
||||
return GetProviderFactory("NewLife.MySql", "NewLife.MySql.dll", "NewLife.MySql.MySqlClientFactory", true, true) ??
|
||||
GetProviderFactory(null, "MySql.Data.dll", "MySql.Data.MySqlClient.MySqlClientFactory");
|
||||
|
|
|
@ -847,7 +847,7 @@ internal class SQLiteMetaData : FileDbMetaData
|
|||
/// <returns></returns>
|
||||
public override String DropIndexSQL(IDataIndex index) => $"Drop Index {index.Name}";
|
||||
|
||||
protected override String CheckColumnsChange(IDataTable entitytable, IDataTable dbtable, Boolean onlySql, Boolean noDelete)
|
||||
protected override String CheckColumnsChange(IDataTable entitytable, IDataTable dbtable, Boolean onlySql, Boolean noDelete, XCodeSetting set)
|
||||
{
|
||||
foreach (var item in entitytable.Columns)
|
||||
{
|
||||
|
@ -864,7 +864,7 @@ internal class SQLiteMetaData : FileDbMetaData
|
|||
}
|
||||
|
||||
// 把onlySql设为true,让基类只产生语句而不执行
|
||||
var sql = base.CheckColumnsChange(entitytable, dbtable, onlySql, true);
|
||||
var sql = base.CheckColumnsChange(entitytable, dbtable, onlySql, true, set);
|
||||
if (sql.IsNullOrEmpty()) return sql;
|
||||
|
||||
// SQLite 3.35.0 起支持 Drop Column
|
||||
|
@ -879,7 +879,7 @@ internal class SQLiteMetaData : FileDbMetaData
|
|||
|
||||
Database.CreateSession().Execute(sql);
|
||||
|
||||
return null;
|
||||
return "";
|
||||
}
|
||||
if (sql.Contains("Drop Column") && v != null && v >= new Version(3, 35))
|
||||
{
|
||||
|
@ -887,11 +887,11 @@ internal class SQLiteMetaData : FileDbMetaData
|
|||
|
||||
Database.CreateSession().Execute(sql);
|
||||
|
||||
return null;
|
||||
return "";
|
||||
}
|
||||
|
||||
var db = Database as DbBase;
|
||||
using var span = db.Tracer?.NewSpan($"db:{db.ConnName}:SetSchema:RebuildTable", sql);
|
||||
using var span = db!.Tracer?.NewSpan($"db:{db.ConnName}:SetSchema:RebuildTable", sql);
|
||||
|
||||
var sql2 = sql;
|
||||
|
||||
|
@ -941,7 +941,7 @@ internal class SQLiteMetaData : FileDbMetaData
|
|||
throw;
|
||||
}
|
||||
|
||||
return null;
|
||||
return "";
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@ -965,16 +965,17 @@ internal class SQLiteMetaData : FileDbMetaData
|
|||
/// <param name="entitytable"></param>
|
||||
/// <param name="dbtable"></param>
|
||||
/// <param name="mode"></param>
|
||||
protected override void CheckTable(IDataTable entitytable, IDataTable dbtable, Migration mode)
|
||||
/// <param name="set"></param>
|
||||
protected override void CheckTable(IDataTable entitytable, IDataTable? dbtable, Migration mode, XCodeSetting set)
|
||||
{
|
||||
if (dbtable == null && (Database as SQLite).IsMemoryDatabase)
|
||||
if (dbtable == null && (Database as SQLite)!.IsMemoryDatabase)
|
||||
{
|
||||
if (memoryTables.Any(t => t.TableName.EqualIgnoreCase(entitytable.TableName))) return;
|
||||
|
||||
memoryTables.Add(entitytable);
|
||||
}
|
||||
|
||||
base.CheckTable(entitytable, dbtable, mode);
|
||||
base.CheckTable(entitytable, dbtable, mode, set);
|
||||
}
|
||||
|
||||
protected override Boolean PerformSchema(StringBuilder sb, Boolean onlySql, DDLSchema schema, params Object[] values)
|
||||
|
|
|
@ -69,14 +69,16 @@ internal partial class DbMetaData
|
|||
{
|
||||
if (mode == Migration.Off) return;
|
||||
|
||||
OnSetTables(tables, mode);
|
||||
var set = XCodeSetting.Current;
|
||||
|
||||
OnSetTables(tables, mode, set);
|
||||
}
|
||||
|
||||
protected virtual void OnSetTables(IDataTable[] tables, Migration mode)
|
||||
protected virtual void OnSetTables(IDataTable[] tables, Migration mode, XCodeSetting set)
|
||||
{
|
||||
var dbExist = CheckDatabase(mode);
|
||||
|
||||
CheckAllTables(tables, mode, dbExist);
|
||||
CheckAllTables(tables, mode, dbExist, set);
|
||||
}
|
||||
|
||||
private Boolean? hasCheckedDatabase;
|
||||
|
@ -119,7 +121,7 @@ internal partial class DbMetaData
|
|||
return dbExist;
|
||||
}
|
||||
|
||||
private void CheckAllTables(IDataTable[] tables, Migration mode, Boolean dbExit)
|
||||
private void CheckAllTables(IDataTable[] tables, Migration mode, Boolean dbExit, XCodeSetting set)
|
||||
{
|
||||
IList<IDataTable>? dbtables = null;
|
||||
if (dbExit)
|
||||
|
@ -141,9 +143,9 @@ internal partial class DbMetaData
|
|||
|
||||
// 判断指定表是否存在于数据库中,以决定是创建表还是修改表
|
||||
if (dbtable != null)
|
||||
CheckTable(item, dbtable, mode);
|
||||
CheckTable(item, dbtable, mode, set);
|
||||
else
|
||||
CheckTable(item, null, mode);
|
||||
CheckTable(item, null, mode, set);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -152,7 +154,7 @@ internal partial class DbMetaData
|
|||
}
|
||||
}
|
||||
|
||||
protected virtual void CheckTable(IDataTable entitytable, IDataTable? dbtable, Migration mode)
|
||||
protected virtual void CheckTable(IDataTable entitytable, IDataTable? dbtable, Migration mode, XCodeSetting set)
|
||||
{
|
||||
var @readonly = mode <= Migration.ReadOnly;
|
||||
if (dbtable == null)
|
||||
|
@ -174,19 +176,30 @@ internal partial class DbMetaData
|
|||
var onlyCreate = mode < Migration.Full;
|
||||
var sb = new StringBuilder();
|
||||
|
||||
var sql = CheckTableDescription(entitytable, dbtable, mode);
|
||||
if (!sql.IsNullOrEmpty()) Append(sb, ";" + Environment.NewLine, sql);
|
||||
if (set.CheckComment)
|
||||
{
|
||||
var sql = CheckTableDescription(entitytable, dbtable, mode);
|
||||
if (!sql.IsNullOrEmpty()) Append(sb, ";" + Environment.NewLine, sql);
|
||||
}
|
||||
|
||||
// 先删除索引,后面才有可能删除字段
|
||||
sql = CheckDeleteIndex(entitytable, dbtable, mode);
|
||||
if (!sql.IsNullOrEmpty()) Append(sb, ";" + Environment.NewLine, sql);
|
||||
if (set.CheckDeleteIndex)
|
||||
{
|
||||
// 先删除索引,后面才有可能删除字段
|
||||
var sql = CheckDeleteIndex(entitytable, dbtable, mode);
|
||||
if (!sql.IsNullOrEmpty()) Append(sb, ";" + Environment.NewLine, sql);
|
||||
}
|
||||
|
||||
sql = CheckColumnsChange(entitytable, dbtable, @readonly, onlyCreate);
|
||||
if (!sql.IsNullOrEmpty()) Append(sb, ";" + Environment.NewLine, sql);
|
||||
{
|
||||
var sql = CheckColumnsChange(entitytable, dbtable, @readonly, onlyCreate, set);
|
||||
if (!sql.IsNullOrEmpty()) Append(sb, ";" + Environment.NewLine, sql);
|
||||
}
|
||||
|
||||
// 新增字段后,可能需要删除索引
|
||||
sql = CheckAddIndex(entitytable, dbtable, mode);
|
||||
if (!sql.IsNullOrEmpty()) Append(sb, ";" + Environment.NewLine, sql);
|
||||
if (set.CheckAddIndex)
|
||||
{
|
||||
// 新增字段后,可能需要删除索引
|
||||
var sql = CheckAddIndex(entitytable, dbtable, mode);
|
||||
if (!sql.IsNullOrEmpty()) Append(sb, ";" + Environment.NewLine, sql);
|
||||
}
|
||||
|
||||
if (sb.Length > 0) WriteLog($"DDL模式[{mode}],请手工修改表[{dbtable.TableName}]:{Environment.NewLine}{sb}");
|
||||
}
|
||||
|
@ -197,8 +210,9 @@ internal partial class DbMetaData
|
|||
/// <param name="dbtable"></param>
|
||||
/// <param name="readonly"></param>
|
||||
/// <param name="onlyCreate"></param>
|
||||
/// <param name="set"></param>
|
||||
/// <returns>返回未执行语句</returns>
|
||||
protected virtual String CheckColumnsChange(IDataTable entitytable, IDataTable dbtable, Boolean @readonly, Boolean onlyCreate)
|
||||
protected virtual String CheckColumnsChange(IDataTable entitytable, IDataTable dbtable, Boolean @readonly, Boolean onlyCreate, XCodeSetting set)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var etdic = entitytable.Columns.ToDictionary(e => FormatName(e), e => e, StringComparer.OrdinalIgnoreCase);
|
||||
|
@ -279,7 +293,7 @@ internal partial class DbMetaData
|
|||
PerformSchema(sb, @readonly || onlyCreate, DDLSchema.AlterColumn, item, dbf);
|
||||
|
||||
//if (item.Description + "" != dbf.Description + "")
|
||||
if (FormatDescription(item.Description) != FormatDescription(dbf.Description))
|
||||
if (set.CheckComment && FormatDescription(item.Description) != FormatDescription(dbf.Description))
|
||||
{
|
||||
// 先删除旧注释
|
||||
//if (dbf.Description != null) PerformSchema(sb, noDelete, DDLSchema.DropColumnDescription, dbf);
|
||||
|
|
|
@ -6,9 +6,9 @@ using System.Runtime.Serialization;
|
|||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using NewLife;
|
||||
using NewLife.Log;
|
||||
using NewLife.Reflection;
|
||||
using XCode.Code;
|
||||
|
||||
namespace XCode.DataAccessLayer;
|
||||
|
||||
|
@ -231,14 +231,15 @@ public static class ModelHelper
|
|||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
var nameFormat = option is EntityBuilderOption opt ? opt.NameFormat : NameFormats.Default;
|
||||
{
|
||||
writer.WriteStartElement("Tables");
|
||||
|
||||
// 回写xml模型,排除IsHistory=true的表单,仅仅保留原始表单
|
||||
foreach (var item in tables.Where(x => x is not XTable xt || !xt.IsHistory))
|
||||
foreach (var table in tables.Where(x => x is not XTable xt || !xt.IsHistory))
|
||||
{
|
||||
writer.WriteStartElement("Table");
|
||||
(item as IXmlSerializable)!.WriteXml(writer);
|
||||
table.WriteXml(writer, nameFormat);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
|
@ -312,10 +313,10 @@ public static class ModelHelper
|
|||
{
|
||||
if (option != null)
|
||||
{
|
||||
if (option is IXmlSerializable xml2)
|
||||
xml2.ReadXml(reader);
|
||||
else
|
||||
ReadXml(reader, option);
|
||||
//if (option is IXmlSerializable xml2)
|
||||
// xml2.ReadXml(reader);
|
||||
//else
|
||||
ReadXml(reader, option);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -345,7 +346,7 @@ public static class ModelHelper
|
|||
static void ReadTable(XmlReader reader, Func<IDataTable> createTable, IList<IDataTable> list)
|
||||
{
|
||||
var table = createTable();
|
||||
(table as IXmlSerializable)!.ReadXml(reader);
|
||||
table.ReadXml(reader);
|
||||
|
||||
// 判断是否存在属性NeedHistory设置且为true
|
||||
var needHistory = table.Properties.FirstOrDefault(x => x.Key.EqualIgnoreCase("NeedHistory"));
|
||||
|
@ -433,7 +434,9 @@ public static class ModelHelper
|
|||
// 清空默认的原始类型,让其从xml读取
|
||||
dc.RawType = null;
|
||||
}
|
||||
(dc as IXmlSerializable)!.ReadXml(reader);
|
||||
ReadXmlAttribute(reader, dc);
|
||||
// 跳过当前节点
|
||||
reader.Skip();
|
||||
|
||||
// 未指定DataType,但指定了Type,修正为枚举整型
|
||||
if (dc.DataType == null && dc.Properties.ContainsKey("Type")) dc.DataType = typeof(Int32);
|
||||
|
@ -454,7 +457,10 @@ public static class ModelHelper
|
|||
while (reader.IsStartElement())
|
||||
{
|
||||
var di = table.CreateIndex();
|
||||
(di as IXmlSerializable)!.ReadXml(reader);
|
||||
ReadXmlAttribute(reader, di);
|
||||
// 跳过当前节点
|
||||
reader.Skip();
|
||||
|
||||
di.Fix();
|
||||
table.Indexes.Add(di);
|
||||
}
|
||||
|
@ -483,18 +489,21 @@ public static class ModelHelper
|
|||
/// <summary>写入</summary>
|
||||
/// <param name="table"></param>
|
||||
/// <param name="writer"></param>
|
||||
public static IDataTable WriteXml(this IDataTable table, XmlWriter writer)
|
||||
/// <param name="nameFormat"></param>
|
||||
public static IDataTable WriteXml(this IDataTable table, XmlWriter writer, NameFormats nameFormat = NameFormats.Default)
|
||||
{
|
||||
WriteXml(writer, table);
|
||||
var ignoreNameCase = nameFormat <= NameFormats.Default;
|
||||
|
||||
WriteXml(writer, table, false, ignoreNameCase);
|
||||
|
||||
// 写字段
|
||||
if (table.Columns.Count > 0)
|
||||
{
|
||||
writer.WriteStartElement("Columns");
|
||||
foreach (IXmlSerializable item in table.Columns)
|
||||
foreach (var dc in table.Columns)
|
||||
{
|
||||
writer.WriteStartElement("Column");
|
||||
item.WriteXml(writer);
|
||||
WriteXml(writer, dc, false, ignoreNameCase);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
|
@ -502,10 +511,10 @@ public static class ModelHelper
|
|||
if (table.Indexes.Count > 0)
|
||||
{
|
||||
writer.WriteStartElement("Indexes");
|
||||
foreach (IXmlSerializable item in table.Indexes)
|
||||
foreach (var di in table.Indexes)
|
||||
{
|
||||
writer.WriteStartElement("Index");
|
||||
item.WriteXml(writer);
|
||||
WriteXml(writer, di, false, true);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
|
@ -634,7 +643,8 @@ public static class ModelHelper
|
|||
/// <param name="writer"></param>
|
||||
/// <param name="value">数值</param>
|
||||
/// <param name="writeDefaultValueMember">是否写数值为默认值的成员。为了节省空间,默认不写。</param>
|
||||
public static void WriteXml(XmlWriter writer, Object value, Boolean writeDefaultValueMember = false)
|
||||
/// <param name="ignoreNameCase">忽略名称大小写</param>
|
||||
public static void WriteXml(XmlWriter writer, Object value, Boolean writeDefaultValueMember = false, Boolean ignoreNameCase = true)
|
||||
{
|
||||
var type = value.GetType();
|
||||
var def = GetDefault(type);
|
||||
|
@ -681,16 +691,24 @@ public static class ModelHelper
|
|||
if (code == TypeCode.String && "" + obj == "" + dobj) continue;
|
||||
}
|
||||
|
||||
if (code == TypeCode.String)
|
||||
if (code == TypeCode.String && obj is String str)
|
||||
{
|
||||
// 如果别名与名称相同,则跳过,不区分大小写
|
||||
// 改为区分大小写,避免linux环境下 mysql 数据库存在
|
||||
if (pi.Name == "Name")
|
||||
name = (String)obj;
|
||||
name = str;
|
||||
else if (pi.Name is "TableName" or "ColumnName")
|
||||
{
|
||||
if (name == (String)obj) continue;
|
||||
if (/*ignoreNameCase &&*/ name.EqualIgnoreCase((String)obj)) continue;
|
||||
if (name == str) continue;
|
||||
if (ignoreNameCase)
|
||||
{
|
||||
if (name.EqualIgnoreCase(str)) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果全小写或者全大写,也不缺分大小写比较
|
||||
if ((str == str.ToLower() || str == str.ToUpper()) && name.EqualIgnoreCase(str)) continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (code == TypeCode.Object)
|
||||
|
@ -723,9 +741,8 @@ public static class ModelHelper
|
|||
if (obj != null) writer.WriteAttributeString(pi.Name, obj + "");
|
||||
}
|
||||
|
||||
if (value is IDataTable)
|
||||
if (value is IDataTable table)
|
||||
{
|
||||
var table = value as IDataTable;
|
||||
// 写入扩展属性作为特性
|
||||
if (table.Properties.Count > 0)
|
||||
{
|
||||
|
@ -735,9 +752,8 @@ public static class ModelHelper
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (value is IDataColumn)
|
||||
else if (value is IDataColumn column)
|
||||
{
|
||||
var column = value as IDataColumn;
|
||||
// 写入扩展属性作为特性
|
||||
if (column.Properties.Count > 0)
|
||||
{
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System.Runtime.Serialization;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using NewLife;
|
||||
using NewLife.Collections;
|
||||
|
||||
namespace XCode.DataAccessLayer;
|
||||
|
@ -12,7 +11,7 @@ namespace XCode.DataAccessLayer;
|
|||
[DisplayName("字段模型")]
|
||||
[Description("字段模型")]
|
||||
[XmlRoot("Column")]
|
||||
class XField : SerializableDataMember, IDataColumn, ICloneable
|
||||
class XField : /*SerializableDataMember,*/ IDataColumn, ICloneable
|
||||
{
|
||||
#region 属性
|
||||
/// <summary>名称</summary>
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Xml.Serialization;
|
||||
using NewLife;
|
||||
|
||||
namespace XCode.DataAccessLayer;
|
||||
|
||||
|
@ -11,7 +9,7 @@ namespace XCode.DataAccessLayer;
|
|||
[DisplayName("索引模型")]
|
||||
[Description("索引模型")]
|
||||
[XmlRoot("Index")]
|
||||
class XIndex : SerializableDataMember, IDataIndex, ICloneable
|
||||
class XIndex : /*SerializableDataMember,*/ IDataIndex, ICloneable
|
||||
{
|
||||
#region 属性
|
||||
/// <summary>名称</summary>
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace XCode.DataAccessLayer;
|
|||
[DisplayName("表模型")]
|
||||
[Description("表模型")]
|
||||
[XmlRoot("Table")]
|
||||
class XTable : IDataTable, ICloneable, IXmlSerializable
|
||||
class XTable : IDataTable, ICloneable//, IXmlSerializable
|
||||
{
|
||||
#region 基本属性
|
||||
///// <summary>编号</summary>
|
||||
|
@ -243,16 +243,16 @@ class XTable : IDataTable, ICloneable, IXmlSerializable
|
|||
#endregion
|
||||
|
||||
#region IXmlSerializable 成员
|
||||
/// <summary>获取架构</summary>
|
||||
/// <returns></returns>
|
||||
XmlSchema IXmlSerializable.GetSchema() => null;
|
||||
///// <summary>获取架构</summary>
|
||||
///// <returns></returns>
|
||||
//XmlSchema IXmlSerializable.GetSchema() => null;
|
||||
|
||||
/// <summary>读取</summary>
|
||||
/// <param name="reader"></param>
|
||||
void IXmlSerializable.ReadXml(XmlReader reader) => ModelHelper.ReadXml(this, reader);
|
||||
///// <summary>读取</summary>
|
||||
///// <param name="reader"></param>
|
||||
//void IXmlSerializable.ReadXml(XmlReader reader) => ModelHelper.ReadXml(this, reader);
|
||||
|
||||
/// <summary>写入</summary>
|
||||
/// <param name="writer"></param>
|
||||
void IXmlSerializable.WriteXml(XmlWriter writer) => ModelHelper.WriteXml(this, writer);
|
||||
///// <summary>写入</summary>
|
||||
///// <param name="writer"></param>
|
||||
//void IXmlSerializable.WriteXml(XmlWriter writer) => ModelHelper.WriteXml(this, writer);
|
||||
#endregion
|
||||
}
|
|
@ -71,7 +71,7 @@
|
|||
<Column Name="Ex3" DataType="Double" Description="扩展3" Category="扩展" />
|
||||
<Column Name="Ex4" DataType="String" Description="扩展4" Category="扩展" />
|
||||
<Column Name="Ex5" DataType="String" Description="扩展5" Category="扩展" />
|
||||
<Column Name="Ex6" DataType="String" Description="扩展6" Attribute="XmlIgnore, ScriptIgnore, IgnoreDataMember" Category="扩展" />
|
||||
<Column Name="Ex6" DataType="String" Description="扩展6" Attribute="XmlIgnore, IgnoreDataMember, ScriptIgnore" Category="扩展" />
|
||||
<Column Name="UpdateUser" DataType="String" Nullable="False" DefaultValue="''" Description="更新者" Model="False" Category="扩展" />
|
||||
<Column Name="UpdateUserID" DataType="Int32" Description="更新用户" Model="False" Category="扩展" />
|
||||
<Column Name="UpdateIP" DataType="String" Description="更新地址" Model="False" Category="扩展" />
|
||||
|
|
Binary file not shown.
|
@ -1,6 +1,7 @@
|
|||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Web.Script.Serialization;
|
||||
using System.Xml.Serialization;
|
||||
|
@ -105,16 +106,21 @@ public partial class Area : Entity<Area>
|
|||
|
||||
#region 扩展属性
|
||||
/// <summary>顶级根。它的Childs就是各个省份</summary>
|
||||
[XmlIgnore, ScriptIgnore]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public static Area Root { get; } = new Area();
|
||||
|
||||
/// <summary>父级</summary>
|
||||
[XmlIgnore, ScriptIgnore]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public Area Parent => Extends.Get(nameof(Parent), k => FindByID(ParentID) ?? Root)!;
|
||||
|
||||
///// <summary>所有父级,从高到底</summary>
|
||||
//[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
//[Obsolete("=>GetAllParents")]
|
||||
//public IList<Area> AllParents => Extends.Get(nameof(AllParents), k => GetAllParents())!;
|
||||
|
||||
/// <summary>所有父级,从高到底</summary>
|
||||
[XmlIgnore, ScriptIgnore]
|
||||
public IList<Area> AllParents => Extends.Get(nameof(AllParents), k =>
|
||||
/// <returns></returns>
|
||||
public IList<Area> GetAllParents()
|
||||
{
|
||||
var list = new List<Area>();
|
||||
var entity = Parent;
|
||||
|
@ -131,14 +137,14 @@ public partial class Area : Entity<Area>
|
|||
list.Reverse();
|
||||
|
||||
return list;
|
||||
})!;
|
||||
}
|
||||
|
||||
/// <summary>父级路径</summary>
|
||||
public String ParentPath
|
||||
public String? ParentPath
|
||||
{
|
||||
get
|
||||
{
|
||||
var list = AllParents;
|
||||
var list = GetAllParents();
|
||||
if (list != null && list.Count > 0) return list.Where(r => !r.IsVirtual).Join("/", r => r.Name);
|
||||
|
||||
return Parent?.Name;
|
||||
|
@ -159,21 +165,25 @@ public partial class Area : Entity<Area>
|
|||
}
|
||||
|
||||
/// <summary>下级地区</summary>
|
||||
[XmlIgnore, ScriptIgnore]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public IList<Area> Childs => Extends.Get(nameof(Childs), k => FindAllByParentID(ID).Where(e => e.Enable).ToList())!;
|
||||
|
||||
///// <summary>子孙级区域。支持省市区,不支持乡镇街道</summary>
|
||||
//[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
//[Obsolete("=>GetAllChilds")]
|
||||
//public IList<Area> AllChilds => Extends.Get(nameof(AllChilds), k => GetAllChilds())!;
|
||||
|
||||
/// <summary>子孙级区域。支持省市区,不支持乡镇街道</summary>
|
||||
[XmlIgnore, ScriptIgnore]
|
||||
public IList<Area> AllChilds => Extends.Get(nameof(AllChilds), k =>
|
||||
public IList<Area> GetAllChilds()
|
||||
{
|
||||
var list = new List<Area>();
|
||||
foreach (var item in Childs)
|
||||
{
|
||||
list.Add(item);
|
||||
if (item.Level < 3) list.AddRange(item.AllChilds);
|
||||
if (item.Level < 3) list.AddRange(item.GetAllChilds());
|
||||
}
|
||||
return list;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>是否虚拟地区</summary>
|
||||
public Boolean IsVirtual => Name.EqualIgnoreCase("市辖区", "直辖县", "直辖镇");
|
||||
|
@ -507,7 +517,7 @@ public partial class Area : Entity<Area>
|
|||
var r = FindByNames(ss);
|
||||
if (r != null)
|
||||
{
|
||||
list.AddRange(r.AllParents);
|
||||
list.AddRange(r.GetAllParents());
|
||||
list.Add(r);
|
||||
|
||||
if (maxLevel > 0 && list.Count > maxLevel) list = list.Take(maxLevel).ToList();
|
||||
|
@ -538,7 +548,7 @@ public partial class Area : Entity<Area>
|
|||
var r = FindAddress(Root, address, maxLevel);
|
||||
if (r != null)
|
||||
{
|
||||
list.AddRange(r.AllParents);
|
||||
list.AddRange(r.GetAllParents());
|
||||
list.Add(r);
|
||||
}
|
||||
|
||||
|
|
|
@ -122,10 +122,10 @@ public partial class User : LogEntity<User>, IUser, IAuthUser, IIdentity
|
|||
#region 扩展属性
|
||||
/// <summary>物理地址</summary>
|
||||
[DisplayName("物理地址")]
|
||||
public String LastLoginAddress => LastLoginIP.IPToAddress();
|
||||
public String? LastLoginAddress => LastLoginIP?.IPToAddress();
|
||||
|
||||
///// <summary>部门</summary>
|
||||
//[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
//[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
//public Department Department => Extends.Get(nameof(Department), k => Department.FindByID(DepartmentID));
|
||||
|
||||
///// <summary>部门</summary>
|
||||
|
@ -137,7 +137,7 @@ public partial class User : LogEntity<User>, IUser, IAuthUser, IIdentity
|
|||
/// 地区名
|
||||
/// </summary>
|
||||
[Map(nameof(AreaId))]
|
||||
public String AreaName => Area.FindByID(AreaId)?.Path;
|
||||
public String? AreaName => Area.FindByID(AreaId)?.Path;
|
||||
#endregion
|
||||
|
||||
#region 扩展查询
|
||||
|
@ -602,11 +602,11 @@ public partial class User : LogEntity<User>, IUser, IAuthUser, IIdentity
|
|||
#region 权限
|
||||
/// <summary>角色</summary>
|
||||
/// <remarks>扩展属性不缓存空对象,一般来说,每个管理员都有对应的角色,如果没有,可能是在初始化</remarks>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
IRole IUser.Role => Role;
|
||||
|
||||
/// <summary>角色集合</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public virtual IRole[] Roles => Extends.Get(nameof(Roles), k => GetRoleIDs().Select(e => ManageProvider.Get<IRole>()?.FindByID(e)).Where(e => e != null).ToArray());
|
||||
|
||||
/// <summary>获取角色列表。主角色在前,其它角色升序在后</summary>
|
||||
|
@ -693,7 +693,7 @@ public partial interface IUser
|
|||
IRole[] Roles { get; }
|
||||
|
||||
/// <summary>角色名</summary>
|
||||
String RoleName { get; }
|
||||
String? RoleName { get; }
|
||||
|
||||
/// <summary>用户是否拥有当前菜单的指定权限</summary>
|
||||
/// <param name="menu">指定菜单</param>
|
||||
|
|
|
@ -286,7 +286,7 @@ public partial class User : IUser, IEntity<IUser>
|
|||
|
||||
private String? _Ex6;
|
||||
/// <summary>扩展6</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
[Category("扩展")]
|
||||
[DisplayName("扩展6")]
|
||||
[Description("扩展6")]
|
||||
|
|
|
@ -50,7 +50,7 @@ public partial class TenantUser : Entity<TenantUser>
|
|||
#region 扩展属性
|
||||
|
||||
///// <summary>租户</summary>
|
||||
//[XmlIgnore, IgnoreDataMember]
|
||||
//[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
////[ScriptIgnore]
|
||||
//public Tenant Tenant => Extends.Get(nameof(Tenant), k => Tenant.FindById(TenantId));
|
||||
|
||||
|
@ -59,7 +59,7 @@ public partial class TenantUser : Entity<TenantUser>
|
|||
//public String TenantName => Tenant?.Name;
|
||||
|
||||
///// <summary>用户</summary>
|
||||
//[XmlIgnore, IgnoreDataMember]
|
||||
//[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
////[ScriptIgnore]
|
||||
//public User User => Extends.Get(nameof(User), k => User.FindByID(UserId));
|
||||
|
||||
|
@ -68,7 +68,7 @@ public partial class TenantUser : Entity<TenantUser>
|
|||
//public String UserName => User?.Name;
|
||||
|
||||
/// <summary>角色</summary>
|
||||
[XmlIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
IRole ITenantUser.Role => Role;
|
||||
|
||||
///// <summary>角色</summary>
|
||||
|
@ -76,7 +76,7 @@ public partial class TenantUser : Entity<TenantUser>
|
|||
//public String RoleName => Role?.Name;
|
||||
|
||||
/// <summary>角色集合</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public virtual IRole[] Roles => Extends.Get(nameof(Roles), k => GetRoleIDs().Select(e => ManageProvider.Get<IRole>()?.FindByID(e)).Where(e => e != null).ToArray());
|
||||
|
||||
/// <summary>获取角色列表。主角色在前,其它角色升序在后</summary>
|
||||
|
|
|
@ -265,7 +265,7 @@ public partial class Menu : EntityTree<Menu>, IMenu
|
|||
|
||||
#region 扩展权限
|
||||
/// <summary>可选权限子项</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public Dictionary<Int32, String> Permissions { get; set; } = new Dictionary<Int32, String>();
|
||||
|
||||
private void LoadPermission()
|
||||
|
|
|
@ -231,7 +231,7 @@ public partial class Role : LogEntity<Role>, IRole, ITenantSource
|
|||
private IDictionary<Int32, PermissionFlags> _Permissions;
|
||||
|
||||
/// <summary>本角色权限集合</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public IDictionary<Int32, PermissionFlags> Permissions => _Permissions ??= new Dictionary<Int32, PermissionFlags>();
|
||||
|
||||
/// <summary>是否拥有指定资源的指定权限</summary>
|
||||
|
@ -353,7 +353,7 @@ public partial class Role : LogEntity<Role>, IRole, ITenantSource
|
|||
}
|
||||
|
||||
/// <summary>当前角色拥有的资源</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public Int32[] Resources => Permissions.Keys.ToArray();
|
||||
|
||||
#endregion 扩展权限
|
||||
|
|
|
@ -95,7 +95,7 @@ public partial class Department : Entity<Department>, ITenantSource
|
|||
|
||||
#region 扩展属性
|
||||
///// <summary>租户</summary>
|
||||
//[XmlIgnore, IgnoreDataMember]
|
||||
//[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
//public Tenant Tenant => Extends.Get(nameof(Tenant), k => Tenant.FindById(TenantId));
|
||||
|
||||
///// <summary>租户</summary>
|
||||
|
@ -103,7 +103,7 @@ public partial class Department : Entity<Department>, ITenantSource
|
|||
//public String TenantName => Tenant?.Name;
|
||||
|
||||
///// <summary>管理者</summary>
|
||||
//[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
//[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
//public User Manager => Extends.Get(nameof(Manager), k => User.FindByID(ManagerId));
|
||||
|
||||
///// <summary>管理者</summary>
|
||||
|
@ -111,7 +111,7 @@ public partial class Department : Entity<Department>, ITenantSource
|
|||
//public String ManagerName => Manager?.ToString();
|
||||
|
||||
/// <summary>父级</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public Department? Parent => Extends.Get(nameof(Department), k => FindByID(ParentID));
|
||||
|
||||
/// <summary>父级</summary>
|
||||
|
@ -155,13 +155,13 @@ public partial class Department : Entity<Department>, ITenantSource
|
|||
/// <summary>
|
||||
/// 获取子集合
|
||||
/// </summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public IEnumerable<Department>? ChildList => Extends.Get(nameof(ChildList), k => FindAllByParentId(ID).OrderBy(e => e.ID));
|
||||
|
||||
/// <summary>
|
||||
///是否存在子集
|
||||
/// </summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public Boolean subset { get; set; }
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections.Concurrent;
|
||||
using NewLife;
|
||||
using XCode.Configuration;
|
||||
using XCode.Membership;
|
||||
|
||||
|
@ -53,6 +52,7 @@ public class IPModule : EntityModule
|
|||
var fs = GetFields(entity.GetType());
|
||||
|
||||
var ip = ManageProvider.UserHost;
|
||||
ip ??= NetHelper.MyIP()?.ToString();
|
||||
if (!ip.IsNullOrEmpty())
|
||||
{
|
||||
// 如果不是IPv6,去掉后面端口
|
||||
|
|
|
@ -83,6 +83,7 @@ public class UserModule : EntityModule
|
|||
// 当前登录用户
|
||||
var prv = Provider ?? ManageProvider.Provider;
|
||||
var user = prv?.Current;
|
||||
user ??= new User { Name = Environment.UserName };
|
||||
if (user != null)
|
||||
{
|
||||
switch (method)
|
||||
|
|
|
@ -73,6 +73,22 @@ public class XCodeSetting : Config<XCodeSetting>
|
|||
[Description("反向工程。Off 关闭;ReadOnly 只读不执行;On 打开,仅新建;Full 完全,修改删除")]
|
||||
public Migration Migration { get; set; } = Migration.On;
|
||||
|
||||
/// <summary>检查注释。表注释或字段注释,反向工程,默认打开</summary>
|
||||
[Description("检查注释。表注释或字段注释,反向工程,默认打开")]
|
||||
public Boolean CheckComment { get; set; } = true;
|
||||
|
||||
/// <summary>检查删除索引。反向工程,默认打开</summary>
|
||||
[Description("检查删除索引。反向工程,默认打开")]
|
||||
public Boolean CheckDeleteIndex { get; set; } = true;
|
||||
|
||||
/// <summary>检查添加索引。反向工程,默认打开</summary>
|
||||
[Description("检查添加索引。反向工程,默认打开")]
|
||||
public Boolean CheckAddIndex { get; set; } = true;
|
||||
|
||||
/// <summary>是否检查索引重复。默认打开</summary>
|
||||
[Description("检查索引重复。默认打开")]
|
||||
public Boolean CheckDuplicateIndex { get; set; } = true;
|
||||
|
||||
/// <summary></summary>
|
||||
[Description("表名称、字段名大小写格式。Default 默认(由数据库决定);None 与模型保持一致;Upper 全大写;Lower 全小写;Underline下划线")]
|
||||
public NameFormats NameFormat { get; set; } = NameFormats.Default;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Runtime.Serialization;
|
||||
using System.Web.Script.Serialization;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace XCode.Transform;
|
||||
|
@ -33,27 +34,27 @@ public class ExtractSetting : IExtractSetting
|
|||
{
|
||||
#region 属性
|
||||
/// <summary>开始。大于等于</summary>
|
||||
[XmlIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public DateTime Start { get; set; }
|
||||
|
||||
/// <summary>结束。小于</summary>
|
||||
[XmlIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public DateTime End { get; set; }
|
||||
|
||||
/// <summary>时间偏移。距离实时时间的秒数,部分业务不能跑到实时</summary>
|
||||
[XmlIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public Int32 Offset { get; set; }
|
||||
|
||||
/// <summary>开始行。分页</summary>
|
||||
[XmlIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public Int32 Row { get; set; }
|
||||
|
||||
/// <summary>步进。最大区间大小,秒</summary>
|
||||
[XmlIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public Int32 Step { get; set; }
|
||||
|
||||
/// <summary>批大小</summary>
|
||||
[XmlIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public Int32 BatchSize { get; set; } = 5000;
|
||||
|
||||
///// <summary>启用</summary>
|
||||
|
|
|
@ -49,14 +49,14 @@ public abstract partial class EntityTree<TKey, TEntity> : Entity<TEntity>, IEnti
|
|||
}
|
||||
|
||||
/// <summary>子节点</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public virtual IList<TEntity> Childs => Extends.Get(nameof(Childs), e => FindChilds())!;
|
||||
|
||||
/// <summary>子节点</summary>
|
||||
protected virtual IList<TEntity> FindChilds() => FindAllByParent((TKey)this[Setting.Key]!);
|
||||
|
||||
/// <summary>父节点</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public virtual TEntity? Parent => Extends.Get(nameof(Parent), e => FindParent());
|
||||
|
||||
/// <summary>父节点</summary>
|
||||
|
@ -66,19 +66,19 @@ public abstract partial class EntityTree<TKey, TEntity> : Entity<TEntity>, IEnti
|
|||
protected static TEntity FindByKeyWithCache(TKey key) => Meta.Session.Cache.Find(e => Equals(e[Setting.Key], key));
|
||||
|
||||
/// <summary>子孙节点</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public virtual IList<TEntity> AllChilds => Extends.Get(nameof(AllChilds), e => FindAllChilds(this))!;
|
||||
|
||||
/// <summary>子孙节点,包含自己</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public virtual IList<TEntity> MyAllChilds => Extends.Get(nameof(MyAllChilds), e => FindAllChilds(this, true))!;
|
||||
|
||||
/// <summary>父节点集合</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public virtual IList<TEntity> AllParents => Extends.Get(nameof(AllParents), e => FindAllParents(this))!;
|
||||
|
||||
/// <summary>深度</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public virtual Int32 Deepth
|
||||
{
|
||||
get
|
||||
|
@ -109,7 +109,7 @@ public abstract partial class EntityTree<TKey, TEntity> : Entity<TEntity>, IEnti
|
|||
}
|
||||
|
||||
/// <summary>节点名</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public virtual String? NodeName
|
||||
{
|
||||
get
|
||||
|
@ -122,7 +122,7 @@ public abstract partial class EntityTree<TKey, TEntity> : Entity<TEntity>, IEnti
|
|||
}
|
||||
|
||||
/// <summary>父级节点名</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public virtual String? ParentNodeName
|
||||
{
|
||||
get
|
||||
|
@ -139,7 +139,7 @@ public abstract partial class EntityTree<TKey, TEntity> : Entity<TEntity>, IEnti
|
|||
|
||||
/// <summary>树形节点名,根据深度带全角空格前缀</summary>
|
||||
[DisplayName("节点名")]
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public virtual String TreeNodeName
|
||||
{
|
||||
get
|
||||
|
@ -156,7 +156,7 @@ public abstract partial class EntityTree<TKey, TEntity> : Entity<TEntity>, IEnti
|
|||
}
|
||||
|
||||
/// <summary>树形节点名,根据深度带全角空格前缀</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public virtual String TreeNodeName2
|
||||
{
|
||||
get
|
||||
|
@ -173,7 +173,7 @@ public abstract partial class EntityTree<TKey, TEntity> : Entity<TEntity>, IEnti
|
|||
}
|
||||
|
||||
/// <summary>树形节点名,根据深度带全角空格前缀</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public virtual String TreeNodeText
|
||||
{
|
||||
get
|
||||
|
@ -195,11 +195,11 @@ public abstract partial class EntityTree<TKey, TEntity> : Entity<TEntity>, IEnti
|
|||
}
|
||||
|
||||
/// <summary>斜杠分隔的全路径</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public String FullPath => @"\" + GetFullPath(true);
|
||||
|
||||
/// <summary>斜杠分隔的全父路径</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public String FullParentPath => @"\" + GetFullPath(false);
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NewLife.Core" Version="11.4.2025.201" />
|
||||
<PackageReference Include="NewLife.Core" Version="11.4.2025.401" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="NewLife" />
|
||||
|
@ -81,6 +81,7 @@
|
|||
<Compile Remove="DataAccessLayer\Common\ConnectionPool.cs" />
|
||||
<Compile Remove="DataAccessLayer\Database\Firebird.cs" />
|
||||
<Compile Remove="DataAccessLayer\Database\Network.cs" />
|
||||
<Compile Remove="DataAccessLayer\Model\SerializableDataMember.cs" />
|
||||
<Compile Remove="DataAccessLayer\MSPageSplit.cs" />
|
||||
<Compile Remove="Membership\IPasswordProvider.cs" />
|
||||
<Compile Remove="Membership\MenuProvider.cs" />
|
||||
|
|
|
@ -146,15 +146,15 @@ public class MemberSectionTests
|
|||
|
||||
#region 扩展属性
|
||||
/// <summary>顶级根。它的Childs就是各个省份</summary>
|
||||
[XmlIgnore, ScriptIgnore]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public static Area Root { get; } = new Area();
|
||||
|
||||
/// <summary>父级</summary>
|
||||
[XmlIgnore, ScriptIgnore]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public Area Parent => Extends.Get(nameof(Parent), k => FindByID(ParentID) ?? Root);
|
||||
|
||||
/// <summary>所有父级</summary>
|
||||
[XmlIgnore, ScriptIgnore]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public IList<Area> AllParents => Extends.Get(nameof(AllParents), k =>
|
||||
{
|
||||
var list = new List<Area>();
|
||||
|
@ -200,11 +200,11 @@ public class MemberSectionTests
|
|||
}
|
||||
|
||||
/// <summary>下级地区</summary>
|
||||
[XmlIgnore, ScriptIgnore]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public IList<Area> Childs => Extends.Get(nameof(Childs), k => FindAllByParentID(ID).Where(e => e.Enable).ToList());
|
||||
|
||||
/// <summary>子孙级区域。支持省市区,不支持乡镇街道</summary>
|
||||
[XmlIgnore, ScriptIgnore]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public IList<Area> AllChilds => Extends.Get(nameof(AllChilds), k =>
|
||||
{
|
||||
var list = new List<Area>();
|
||||
|
@ -408,13 +408,13 @@ public class MemberSectionTests
|
|||
var code =
|
||||
"""
|
||||
#region 扩展属性
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public Product Product => Extends.Get(nameof(Product), k => Product.FindById(ProductId));
|
||||
|
||||
[Map(nameof(ProductId), typeof(Product), "Id")]
|
||||
public String ProductName => Product?.Name;
|
||||
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public DeviceGroup Group => Extends.Get(nameof(Group), k => DeviceGroup.FindById(GroupId));
|
||||
|
||||
[Map(nameof(GroupId), typeof(DeviceGroup), "Id")]
|
||||
|
@ -425,7 +425,7 @@ public class MemberSectionTests
|
|||
public String AreaName => Area.FindByIDs(CityId, ProvinceId)?.Path;
|
||||
|
||||
/// <summary>父级设备</summary>
|
||||
[XmlIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
//[ScriptIgnore]
|
||||
public Device Parent => Extends.Get(nameof(Parent), k => Device.FindById(ParentId));
|
||||
|
||||
|
@ -434,18 +434,18 @@ public class MemberSectionTests
|
|||
public String ParentName => Parent?.Name;
|
||||
|
||||
/// <summary>子设备。借助扩展属性缓存</summary>
|
||||
[XmlIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public IList<Device> Childs => Extends.Get(nameof(Childs), k => FindAllByParent(Id));
|
||||
|
||||
/// <summary>设备属性。借助扩展属性缓存</summary>
|
||||
[XmlIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public IList<DeviceProperty> Properties => Extends.Get(nameof(Properties), k => DeviceProperty.FindAllByDeviceId(Id));
|
||||
|
||||
/// <summary>设备服务。借助扩展属性缓存</summary>
|
||||
[XmlIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
public IList<DeviceService> Services => Extends.Get(nameof(Services), k => DeviceService.FindAllByDeviceId(Id));
|
||||
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
protected Boolean IgnoreVaild { get; set; } = false;
|
||||
#endregion
|
||||
""";
|
||||
|
|
|
@ -287,7 +287,7 @@ public partial class User
|
|||
|
||||
private String? _Ex6;
|
||||
/// <summary>扩展6</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
[Category("扩展")]
|
||||
[DisplayName("扩展6")]
|
||||
[Description("扩展6")]
|
||||
|
|
|
@ -152,6 +152,34 @@ public class MySqlTests
|
|||
catch (Exception ex) { XTrace.WriteException(ex); }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MembershipTest()
|
||||
{
|
||||
var connStr = _ConnStr.Replace("Database=sys;", "Database=Membership;");
|
||||
DAL.AddConnStr("MySql_member", connStr, null, "MySql");
|
||||
|
||||
User.Meta.ConnName = "MySql_member";
|
||||
Role.Meta.ConnName = "MySql_member";
|
||||
|
||||
User.Meta.Session.InitData();
|
||||
Role.Meta.Session.InitData();
|
||||
|
||||
var count = User.Meta.Count;
|
||||
Assert.True(count > 0);
|
||||
|
||||
count = Role.Meta.Count;
|
||||
Assert.True(count > 0);
|
||||
|
||||
var list = Role.FindAll();
|
||||
Assert.Equal(4, list.Count);
|
||||
|
||||
var list2 = Role.FindAll(Role._.Name == "管理员");
|
||||
Assert.Single(list2);
|
||||
|
||||
var list3 = Role.Search("用户", null);
|
||||
Assert.Equal(2, list3.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TablePrefixTest()
|
||||
{
|
||||
|
|
|
@ -95,6 +95,27 @@ public class SQLiteTests
|
|||
Assert.Equal(dal1, dal2);
|
||||
Assert.Equal("sysSQLite", dal2.ConnName);
|
||||
Assert.Equal(DatabaseType.SQLite, dal2.DbType);
|
||||
Assert.Equal($"Data Source={db}", dal2.ConnStr);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MapToTest2()
|
||||
{
|
||||
var db = "Data\\Membership.db";
|
||||
var dbf = db.GetFullPath();
|
||||
|
||||
DAL.AddConnStr("sysSQLite", $"Data Source={db}", null, "SQLite");
|
||||
DAL.AddConnStr("mapTest", "MapTo=sysSQLite;TablePrefix=xcwl_", null, null);
|
||||
|
||||
var dal1 = DAL.Create("sysSQLite");
|
||||
var dal2 = DAL.Create("mapTest");
|
||||
Assert.NotNull(dal2);
|
||||
Assert.NotEqual(dal1, dal2);
|
||||
Assert.Equal("mapTest", dal2.ConnName);
|
||||
Assert.Equal(DatabaseType.SQLite, dal2.DbType);
|
||||
Assert.NotEqual($"Data Source={db};TablePrefix=xcwl_", dal2.ConnStr);
|
||||
//Assert.EndsWith(";TablePrefix=xcwl_", dal2.Db.ConnectionString);
|
||||
Assert.Equal(dbf, (dal2.Db as FileDbBase).DatabaseName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -40,16 +40,16 @@ public class AreaTests
|
|||
|
||||
XTrace.WriteLine("北京");
|
||||
r = Area.FindByName(0, "北京");
|
||||
Assert.Equal(17, r.AllChilds.Count);
|
||||
Assert.Equal("北京/延庆", r.AllChilds[^1].Path);
|
||||
Assert.Equal(17, r.GetAllChilds().Count);
|
||||
Assert.Equal("北京/延庆", r.GetAllChilds()[^1].Path);
|
||||
|
||||
XTrace.WriteLine("容县");
|
||||
r = Area.FindByID(450921);
|
||||
Assert.Equal("容县", r.Name);
|
||||
Assert.Equal(2, r.AllParents.Count);
|
||||
Assert.Equal(2, r.GetAllParents().Count);
|
||||
Assert.Equal("广西/玉林", r.ParentPath);
|
||||
Assert.Equal(15, r.AllChilds.Count);
|
||||
Assert.Equal("广西/玉林/容县/容州", r.AllChilds[0].Path);
|
||||
Assert.Equal(15, r.GetAllChilds().Count);
|
||||
Assert.Equal("广西/玉林/容县/容州", r.GetAllChilds()[0].Path);
|
||||
|
||||
var r2 = Area.FindByIDs(450921102, 450921, 450900, 450000);
|
||||
Assert.Equal("杨梅", r2.Name);
|
||||
|
@ -153,6 +153,51 @@ public class AreaTests
|
|||
}
|
||||
}
|
||||
|
||||
[TestOrder(50)]
|
||||
[Fact]
|
||||
public void ParentTest()
|
||||
{
|
||||
var ar = Area.FindByID(450921102);
|
||||
Assert.Equal("杨梅", ar.Name);
|
||||
|
||||
var ps = ar.GetAllParents();
|
||||
Assert.Equal(3, ps.Count);
|
||||
|
||||
ar = ar.Parent;
|
||||
Assert.Equal("容县", ar.Name);
|
||||
|
||||
ar = ar.Parent;
|
||||
Assert.Equal("玉林", ar.Name);
|
||||
|
||||
ar = ar.Parent;
|
||||
Assert.Equal("广西", ar.Name);
|
||||
|
||||
ar = ar.Parent;
|
||||
Assert.Equal(0, ar.ID);
|
||||
Assert.Equal(Area.Root, ar);
|
||||
}
|
||||
|
||||
[TestOrder(50)]
|
||||
[Fact]
|
||||
public void ParentTest2()
|
||||
{
|
||||
var ar = Area.FindByID(310116);
|
||||
Assert.Equal("金山", ar.Name);
|
||||
|
||||
var ps = ar.GetAllParents();
|
||||
Assert.Equal(2, ps.Count);
|
||||
|
||||
ar = ar.Parent;
|
||||
Assert.Equal("市辖区", ar.Name);
|
||||
|
||||
ar = ar.Parent;
|
||||
Assert.Equal("上海", ar.Name);
|
||||
|
||||
ar = ar.Parent;
|
||||
Assert.Equal(0, ar.ID);
|
||||
Assert.Equal(Area.Root, ar);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void Download()
|
||||
{
|
||||
|
|
|
@ -217,7 +217,7 @@ public partial class User2
|
|||
|
||||
private String _Ex6;
|
||||
/// <summary>扩展6</summary>
|
||||
[XmlIgnore, ScriptIgnore, IgnoreDataMember]
|
||||
[XmlIgnore, IgnoreDataMember, ScriptIgnore]
|
||||
[DisplayName("扩展6")]
|
||||
[Description("扩展6")]
|
||||
[DataObjectField(false, false, true, 50)]
|
||||
|
|
|
@ -84,13 +84,13 @@
|
|||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="NewLife.Core" Version="11.4.2025.201" />
|
||||
<PackageReference Include="NewLife.IP" Version="2.2.2025.101" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
|
||||
<PackageReference Include="NewLife.Core" Version="11.4.2025.401" />
|
||||
<PackageReference Include="NewLife.IP" Version="2.3.2025.202" />
|
||||
<PackageReference Include="NewLife.UnitTest" Version="1.0.2025.101" />
|
||||
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="9.0.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.1">
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
|
Loading…
Reference in New Issue