v9.8.2018.0605 由DataReader直接映射实体列表,以支持netstandard的MySql和SQLite,且提升性能大石头 authored at 2018-06-05 00:45:23
diff --git a/TestST/Program.cs b/TestST/Program.cs
index d91b22e..68f609e 100644
--- a/TestST/Program.cs
+++ b/TestST/Program.cs
@@ -6,6 +6,7 @@ using Microsoft.Extensions.Configuration;
using NewLife.Log;
using NewLife.Net;
using XCode.DataAccessLayer;
+using XCode.Membership;
namespace TestST
{
@@ -67,13 +68,16 @@ namespace TestST
//var fact = MySqlClientFactory.Instance;
var fact = SqliteFactory.Instance;
- var dal = DAL.Create("Sqlite");
+ //var dal = DAL.Create("Sqlite");
//DAL.AddConnStr("Membership", "Server=.;Port=3306;Database=world;Uid=root;Pwd=root", null, "MySql");
- //var dal = DAL.Create("Membership");
+ var dal = DAL.Create("Membership");
Console.WriteLine(dal.Db.ConnectionString);
- var ds = dal.Select("select * from city");
- Console.WriteLine(ds.Tables[0].Rows.Count);
+ //var ds = dal.Select("select * from city");
+ //Console.WriteLine(ds.Tables[0].Rows.Count);
+
+ var user = UserX.FindByName("admin");
+ Console.WriteLine(user);
//var n = UserX.Meta.Count;
//Console.WriteLine(n);
diff --git a/XCode/DataAccessLayer/Common/DbBase.cs b/XCode/DataAccessLayer/Common/DbBase.cs
index 2c8740d..69609ee 100644
--- a/XCode/DataAccessLayer/Common/DbBase.cs
+++ b/XCode/DataAccessLayer/Common/DbBase.cs
@@ -818,6 +818,9 @@ namespace XCode.DataAccessLayer
/// <summary>获取 或 设置 自动关闭。每次使用完数据库连接后,是否自动关闭连接,高频操作时设为false可提升性能。默认true</summary>
public Boolean AutoClose { get; set; } = true;
+
+ /// <summary>是否支持Schema。默认true</summary>
+ public Boolean SupportSchema { get; set; } = true;
#endregion
#region 辅助函数
diff --git a/XCode/DataAccessLayer/Common/DbSession.cs b/XCode/DataAccessLayer/Common/DbSession.cs
index 04474da..17dfcfc 100644
--- a/XCode/DataAccessLayer/Common/DbSession.cs
+++ b/XCode/DataAccessLayer/Common/DbSession.cs
@@ -324,6 +324,49 @@ namespace XCode.DataAccessLayer
}
}
+ /// <summary>执行SQL查询,返回记录集</summary>
+ /// <param name="sql">SQL语句</param>
+ /// <param name="type">命令类型,默认SQL文本</param>
+ /// <param name="ps">命令参数</param>
+ /// <param name="convert">转换器</param>
+ /// <returns>记录集</returns>
+ public virtual T Query<T>(String sql, CommandType type, IDataParameter[] ps, Func<IDataReader, T> convert)
+ {
+ using (var cmd = OnCreateCommand(sql, type, ps))
+ {
+ Transaction?.Check(cmd, false);
+
+ QueryTimes++;
+ WriteSQL(cmd);
+
+ using (var pi = Database.Pool.AcquireItem())
+ {
+ try
+ {
+ //if (!Opened) Open();
+ if (cmd.Connection == null) cmd.Connection = pi.Value;
+
+ BeginTrace();
+ using (var dr = cmd.ExecuteReader())
+ {
+ return convert(dr);
+ }
+ }
+ catch (DbException ex)
+ {
+ // 数据库异常最好销毁连接
+ cmd.Connection.TryDispose();
+
+ throw OnException(ex, cmd);
+ }
+ finally
+ {
+ EndTrace(cmd);
+ }
+ }
+ }
+ }
+
private static Regex reg_QueryCount = new Regex(@"^\s*select\s+\*\s+from\s+([\w\W]+)\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>执行SQL查询,返回总记录数</summary>
/// <param name="sql">SQL语句</param>
diff --git a/XCode/DataAccessLayer/Common/IDbSession.cs b/XCode/DataAccessLayer/Common/IDbSession.cs
index d41e2f5..5f12a12 100644
--- a/XCode/DataAccessLayer/Common/IDbSession.cs
+++ b/XCode/DataAccessLayer/Common/IDbSession.cs
@@ -94,6 +94,14 @@ namespace XCode.DataAccessLayer
/// <returns>记录集</returns>
DataSet Query(DbCommand cmd);
+ /// <summary>执行SQL查询,返回记录集</summary>
+ /// <param name="sql">SQL语句</param>
+ /// <param name="type">命令类型,默认SQL文本</param>
+ /// <param name="ps">命令参数</param>
+ /// <param name="convert">转换器</param>
+ /// <returns>记录集</returns>
+ T Query<T>(String sql, CommandType type, IDataParameter[] ps, Func<IDataReader, T> convert);
+
/// <summary>执行SQL查询,返回总记录数</summary>
/// <param name="sql">SQL语句</param>
/// <param name="type">命令类型,默认SQL文本</param>
diff --git a/XCode/DataAccessLayer/DAL_DbOperate.cs b/XCode/DataAccessLayer/DAL_DbOperate.cs
index 3921097..f951671 100644
--- a/XCode/DataAccessLayer/DAL_DbOperate.cs
+++ b/XCode/DataAccessLayer/DAL_DbOperate.cs
@@ -58,6 +58,23 @@ namespace XCode.DataAccessLayer
return Session.Query(builder.ToString(), CommandType.Text, builder.Parameters.ToArray());
}
+ /// <summary>执行SQL查询,返回记录集</summary>
+ /// <param name="builder">SQL语句</param>
+ /// <param name="startRowIndex">开始行,0表示第一行</param>
+ /// <param name="maximumRows">最大返回行数,0表示所有行</param>
+ /// <param name="convert">转换器</param>
+ /// <returns></returns>
+ public T Query<T>(SelectBuilder builder, Int64 startRowIndex, Int64 maximumRows, Func<IDataReader, T> convert)
+ {
+ builder = PageSplit(builder, startRowIndex, maximumRows);
+ if (builder == null) return default(T);
+
+ CheckBeforeUseDatabase();
+
+ Interlocked.Increment(ref _QueryTimes);
+ return Session.Query(builder.ToString(), CommandType.Text, builder.Parameters.ToArray(), convert);
+ }
+
/// <summary>执行SQL查询,返回总记录数</summary>
/// <param name="sb">查询生成器</param>
/// <returns></returns>
diff --git a/XCode/DataAccessLayer/DAL.cs b/XCode/DataAccessLayer/DAL.cs
index b67b209..f6f93a1 100644
--- a/XCode/DataAccessLayer/DAL.cs
+++ b/XCode/DataAccessLayer/DAL.cs
@@ -168,9 +168,9 @@ namespace XCode.DataAccessLayer
// 读取配置文件
var css2 = new ConfigurationBuilder().AddJsonFile(settings).Build().GetSection("connectionStrings");
-// var css2 = new ConfigurationBuilder()
-//.Add(new JsonConfigurationSource { Path = "appsettings.json", ReloadOnChange = true })
-//.Build().GetSection("connectionStrings");
+ // var css2 = new ConfigurationBuilder()
+ //.Add(new JsonConfigurationSource { Path = "appsettings.json", ReloadOnChange = true })
+ //.Build().GetSection("connectionStrings");
if (css2 != null)
{
foreach (var item in css2.GetChildren())
@@ -390,6 +390,8 @@ namespace XCode.DataAccessLayer
private List<IDataTable> GetTables()
{
+ if (Db is DbBase db2 && !db2.SupportSchema) return new List<IDataTable>();
+
CheckBeforeUseDatabase();
return Db.CreateMetaData().GetTables();
}
@@ -525,6 +527,8 @@ namespace XCode.DataAccessLayer
/// <param name="tables"></param>
public void SetTables(params IDataTable[] tables)
{
+ if (Db is DbBase db2 && !db2.SupportSchema) return;
+
// 构建DataTable时也要注意表前缀,避免反向工程用错
var pf = Db.TablePrefix;
if (!pf.IsNullOrEmpty())
diff --git a/XCode/DataAccessLayer/Database/SQLite.cs b/XCode/DataAccessLayer/Database/SQLite.cs
index fd2a7b4..d989ea9 100644
--- a/XCode/DataAccessLayer/Database/SQLite.cs
+++ b/XCode/DataAccessLayer/Database/SQLite.cs
@@ -98,6 +98,8 @@ namespace XCode.DataAccessLayer
// 自动清理数据
if (builder.TryGetAndRemove("autoVacuum", out var vac)) AutoVacuum = vac.ToBoolean();
}
+ else
+ SupportSchema = false;
// 默认超时时间
//if (!builder.ContainsKey("Default Timeout")) builder["Default Timeout"] = 5 + "";
diff --git a/XCode/Entity/DataRowEntityAccessor.cs b/XCode/Entity/DataRowEntityAccessor.cs
index 695e1f2..14bf27f 100644
--- a/XCode/Entity/DataRowEntityAccessor.cs
+++ b/XCode/Entity/DataRowEntityAccessor.cs
@@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data;
-using System.Linq;
-using NewLife.Reflection;
+using System.Data.Common;
using XCode.Configuration;
using XCode.DataAccessLayer;
@@ -15,6 +14,11 @@ namespace XCode
/// <param name="dt">数据表</param>
/// <returns>实体数组</returns>
IList<T> LoadData<T>(DataTable dt) where T : Entity<T>, new();
+
+ /// <summary>加载数据表。无数据时返回空集合而不是null。</summary>
+ /// <param name="dr">数据读取器</param>
+ /// <returns>实体数组</returns>
+ IList<T> LoadData<T>(IDataReader dr) where T : Entity<T>, new();
}
/// <summary>在数据行和实体类之间映射数据接口的提供者</summary>
@@ -31,10 +35,7 @@ namespace XCode
/// <summary>创建实体类的数据行访问器</summary>
/// <param name="entityType"></param>
/// <returns></returns>
- public IDataRowEntityAccessor CreateDataRowEntityAccessor(Type entityType)
- {
- return new DataRowEntityAccessor();
- }
+ public IDataRowEntityAccessor CreateDataRowEntityAccessor(Type entityType) => new DataRowEntityAccessor();
}
class DataRowEntityAccessor : IDataRowEntityAccessor
@@ -78,6 +79,47 @@ namespace XCode
}
return list;
}
+
+ /// <summary>加载数据表。无数据时返回空集合而不是null。</summary>
+ /// <param name="dr">数据读取器</param>
+ /// <returns>实体数组</returns>
+ public IList<T> LoadData<T>(IDataReader dr) where T : Entity<T>, new()
+ {
+ // 准备好实体列表
+ var list = new List<T>();
+ if (dr == null) return list;
+
+ var dr2 = dr as DbDataReader;
+
+ // 对应数据表中字段的实体字段
+ var ps = new Dictionary<Int32, FieldItem>();
+ // 数据表中找不到对应的实体字段的数据字段
+ var exts = new Dictionary<Int32, String>();
+ var ti = Entity<T>.Meta.Table;
+ for (var i = 0; i < dr2.FieldCount; i++)
+ {
+ var name = dr2.GetName(i);
+ if (ti.FindByName(name) is FieldItem fi)
+ ps.Add(i, fi);
+ else
+ exts.Add(i, name);
+ }
+
+ // 遍历每一行数据,填充成为实体
+ while(dr.Read())
+ {
+ // 由实体操作者创建实体对象,因为实体操作者可能更换
+ var entity = Entity<T>.Meta.Factory.Create() as T;
+ foreach (var item in ps)
+ SetValue(entity, item.Value.Name, item.Value.Type, dr[item.Key]);
+
+ foreach (var item in exts)
+ SetValue(entity, item.Value, null, dr[item.Key]);
+
+ list.Add(entity);
+ }
+ return list;
+ }
#endregion
#region 方法
diff --git a/XCode/Entity/Entity_Operate.cs b/XCode/Entity/Entity_Operate.cs
index 60001dd..5fed0c8 100644
--- a/XCode/Entity/Entity_Operate.cs
+++ b/XCode/Entity/Entity_Operate.cs
@@ -75,12 +75,12 @@ namespace XCode
/// <summary>创建一个实体对象</summary>
/// <param name="forEdit">是否为了编辑而创建,如果是,可以再次做一些相关的初始化工作</param>
/// <returns></returns>
- public virtual IEntity Create(Boolean forEdit = false) { return (Default as TEntity).CreateInstance(forEdit) as TEntity; }
+ public virtual IEntity Create(Boolean forEdit = false) => (Default as TEntity).CreateInstance(forEdit) as TEntity;
/// <summary>加载记录集</summary>
/// <param name="ds">记录集</param>
/// <returns>实体数组</returns>
- public virtual IList<IEntity> LoadData(DataSet ds) { return Entity<TEntity>.LoadData(ds).Cast<IEntity>().ToList(); }
+ public virtual IList<IEntity> LoadData(DataSet ds) => Entity<TEntity>.LoadData(ds).Cast<IEntity>().ToList();
#endregion
#region 查找单个实体
diff --git a/XCode/Entity/Entity.cs b/XCode/Entity/Entity.cs
index 6745fa2..957757d 100644
--- a/XCode/Entity/Entity.cs
+++ b/XCode/Entity/Entity.cs
@@ -90,6 +90,26 @@ namespace XCode
if (dt == null) return new List<TEntity>();
var list = DreAccessor.LoadData<TEntity>(dt);
+ OnLoadData(list);
+
+ return list;
+ }
+
+ /// <summary>加载数据表。无数据时返回空集合而不是null。</summary>
+ /// <param name="dr">数据读取器</param>
+ /// <returns>实体数组</returns>
+ public static IList<TEntity> LoadData(IDataReader dr)
+ {
+ if (dr == null) return new List<TEntity>();
+
+ var list = DreAccessor.LoadData<TEntity>(dr);
+ OnLoadData(list);
+
+ return list;
+ }
+
+ private static void OnLoadData(IList<TEntity> list)
+ {
// 设置默认累加字段
EntityAddition.SetField(list.Cast<IEntity>().ToList());
foreach (var entity in list)
@@ -110,8 +130,6 @@ namespace XCode
}
});
}
-
- return list;
}
private static IDataRowEntityAccessor DreAccessor => XCodeService.CreateDataRowEntityAccessor(typeof(TEntity));
@@ -456,7 +474,8 @@ namespace XCode
// 提取参数
builder = FixParam(builder, ps);
- var list = LoadData(session.Query(builder, 0, 0));
+ //var list = LoadData(session.Query(builder, 0, 0));
+ var list = session.Query(builder, 0, 0, LoadData);
if (list == null || list.Count < 1) return null;
if (list.Count > 1 && DAL.Debug)
@@ -611,7 +630,8 @@ namespace XCode
var session = Meta.Session;
var builder = CreateBuilder(where, order, selects, startRowIndex, maximumRows);
- return LoadData(session.Query(builder, startRowIndex, maximumRows));
+ //return LoadData(session.Query(builder, startRowIndex, maximumRows));
+ return session.Query(builder, startRowIndex, maximumRows, LoadData);
}
/// <summary>最标准的查询数据。没有数据时返回空集合而不是null</summary>
@@ -707,7 +727,8 @@ namespace XCode
var start = (Int32)(count - (startRowIndex + maximumRows));
var builder2 = CreateBuilder(where, order2, selects, start, max);
- var list = LoadData(session.Query(builder2, start, max));
+ //var list = LoadData(session.Query(builder2, start, max));
+ var list = session.Query(builder2, start, max, LoadData);
if (list == null || list.Count < 1) return list;
// 因为这样取得的数据是倒过来的,所以这里需要再倒一次
list.Reverse();
@@ -718,7 +739,7 @@ namespace XCode
#endregion
var builder = CreateBuilder(where, order, selects, startRowIndex, maximumRows);
- return LoadData(session.Query(builder, startRowIndex, maximumRows));
+ return session.Query(builder, startRowIndex, maximumRows, LoadData);
}
/// <summary>同时查询满足条件的记录集和记录总数。没有数据时返回空集合而不是null</summary>
diff --git a/XCode/Entity/EntitySession.cs b/XCode/Entity/EntitySession.cs
index be631bb..970e713 100644
--- a/XCode/Entity/EntitySession.cs
+++ b/XCode/Entity/EntitySession.cs
@@ -543,9 +543,11 @@ namespace XCode
Table = FormatedTableName,
OrderBy = Table.Identity.Desc()
};
- var ds = Dal.Select(builder, 0, 1);
- if (ds.Tables[0].Rows.Count > 0)
- count = Convert.ToInt64(ds.Tables[0].Rows[0][Table.Identity.ColumnName]);
+ //var ds = Dal.Select(builder, 0, 1);
+ //if (ds.Tables[0].Rows.Count > 0)
+ // count = Convert.ToInt64(ds.Tables[0].Rows[0][Table.Identity.ColumnName]);
+ var rs = Dal.Query(builder, 0, 0, dr => dr.Read() ? dr[0].ToInt() : -1);
+ if (rs > 0) count = rs;
}
// 100w数据时,没有预热Select Count需要3000ms,预热后需要500ms
@@ -594,6 +596,19 @@ namespace XCode
/// <param name="builder">SQL语句</param>
/// <param name="startRowIndex">开始行,0表示第一行</param>
/// <param name="maximumRows">最大返回行数,0表示所有行</param>
+ /// <param name="convert">转换器</param>
+ /// <returns></returns>
+ public virtual T Query<T>(SelectBuilder builder, Int64 startRowIndex, Int64 maximumRows, Func<IDataReader, T> convert)
+ {
+ InitData();
+
+ return Dal.Query(builder, startRowIndex, maximumRows, convert);
+ }
+
+ /// <summary>执行SQL查询,返回记录集</summary>
+ /// <param name="builder">SQL语句</param>
+ /// <param name="startRowIndex">开始行,0表示第一行</param>
+ /// <param name="maximumRows">最大返回行数,0表示所有行</param>
/// <returns></returns>
public virtual DataSet Query(SelectBuilder builder, Int64 startRowIndex, Int64 maximumRows)
{
diff --git a/XCode/Properties/AssemblyInfo.cs b/XCode/Properties/AssemblyInfo.cs
index 0193620..6a12437 100644
--- a/XCode/Properties/AssemblyInfo.cs
+++ b/XCode/Properties/AssemblyInfo.cs
@@ -39,8 +39,8 @@ using XCode;
//
// 可以指定所有这些值,也可以使用“修订号”和“内部版本号”的默认值,
// 方法是按如下所示使用“*”:
-[assembly: AssemblyVersion("9.7.*")]
-[assembly: AssemblyFileVersion("9.7.2018.0421")]
+[assembly: AssemblyVersion("9.8.*")]
+[assembly: AssemblyFileVersion("9.8.2018.0605")]
/*
* XCode的重大改进
@@ -58,6 +58,8 @@ using XCode;
* /
/*
+ * v9.8.2018.0605 由DataReader直接映射实体列表,以支持netstandard的MySql和SQLite,且提升性能
+ *
* v9.7.2018.0421 支持运行时修改DAL连接字符串
*
* v9.6.2018.0326 重构权限体系,支持多角色
diff --git a/XCode/UpdateInfo.txt b/XCode/UpdateInfo.txt
index 91d6d50..a366596 100644
--- a/XCode/UpdateInfo.txt
+++ b/XCode/UpdateInfo.txt
@@ -10,6 +10,8 @@ v2.0 数据架构功能,实体和数据结构双向映射
v1.2 使用泛型基类
v1.0 创建XCode
+v9.8.2018.0605 由DataReader直接映射实体列表,以支持netstandard的MySql和SQLite,且提升性能
+
v9.7.2018.0421 支持运行时修改DAL连接字符串
v9.6.2018.0326 重构权限体系,支持多角色