From dc6f42cd68299409874e8caa9c308274f2eebb36 Mon Sep 17 00:00:00 2001
From: 2881099 <2881099@qq.com>
Date: Sat, 28 Nov 2020 04:16:58 +0800
Subject: [PATCH] =?UTF-8?q?-=20=E4=BC=98=E5=8C=96=20=E5=8D=95=E8=A1=A8?=
=?UTF-8?q?=E6=9F=A5=E8=AF=A2=20ExpressionTree=20=E6=80=A7=E8=83=BD?=
=?UTF-8?q?=EF=BC=9B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Oracle/OracleCodeFirstTest.cs | 8 +
FreeSql.sln | 1 +
FreeSql/FreeSql.xml | 183 ++++++++++++++++++
.../SelectProvider/Select0ProviderReader.cs | 90 +++++++--
README.md | 29 ++-
5 files changed, 283 insertions(+), 28 deletions(-)
diff --git a/FreeSql.Tests/FreeSql.Tests/Oracle/OracleCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests/Oracle/OracleCodeFirstTest.cs
index 78e554ef..1ce4f716 100644
--- a/FreeSql.Tests/FreeSql.Tests/Oracle/OracleCodeFirstTest.cs
+++ b/FreeSql.Tests/FreeSql.Tests/Oracle/OracleCodeFirstTest.cs
@@ -51,6 +51,14 @@ namespace FreeSql.Tests.Oracle
item2 = repo.Get(item1.Id);
Assert.Equal(item1.CreatorId, item2.CreatorId);
+
+ fsql.Aop.AuditDataReader -= fsql.Aop.AuditDataReaderHandler;
+
+ item1 = new TS_SL361 { CreatorId = "" };
+ repo.Insert(item1);
+ item2 = repo.Get(item1.Id);
+
+ Assert.Null(item2.CreatorId);
}
}
class TS_SNTE
diff --git a/FreeSql.sln b/FreeSql.sln
index fa28ac8e..fb6b29f9 100644
--- a/FreeSql.sln
+++ b/FreeSql.sln
@@ -8,6 +8,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{C6A74E2A-6660-473D-8852-B1D8348DB4E9}"
ProjectSection(SolutionItems) = preProject
readme.md = readme.md
+ README.zh-CN.md = README.zh-CN.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{94C8A78D-AA15-47B2-A348-530CD86BFC1B}"
diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml
index a06a844f..f5d2d1db 100644
--- a/FreeSql/FreeSql.xml
+++ b/FreeSql/FreeSql.xml
@@ -3089,6 +3089,177 @@
+
+
+ 测试数据库是否连接正确,本方法执行如下命令:
+ MySql/SqlServer/PostgreSQL/达梦/人大金仓/神通: SELECT 1
+ Oracle: SELECT 1 FROM dual
+
+ 命令超时设置(秒)
+
+ true: 成功, false: 失败
+
+
+
+ 查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
+
+
+
+
+
+
+
+
+
+ 查询,ExecuteReaderAsync(dr => {}, "select * from user where age > @age", new { age = 25 })
+ 提示:parms 参数还可以传 Dictionary<string, object>
+
+
+
+
+
+
+
+
+ 查询
+
+
+
+
+
+
+
+
+ 查询,ExecuteArrayAsync("select * from user where age > @age", new { age = 25 })
+ 提示:parms 参数还可以传 Dictionary<string, object>
+
+
+
+
+
+
+
+
+ 查询
+
+
+
+
+
+
+
+
+ 查询,ExecuteDataSetAsync("select * from user where age > @age; select 2", new { age = 25 })
+ 提示:parms 参数还可以传 Dictionary<string, object>
+
+
+
+
+
+
+
+
+ 查询
+
+
+
+
+
+
+
+
+ 查询,ExecuteDataTableAsync("select * from user where age > @age", new { age = 25 })
+ 提示:parms 参数还可以传 Dictionary<string, object>
+
+
+
+
+
+
+
+
+ 在【主库】执行
+
+
+
+
+
+
+
+
+ 在【主库】执行,ExecuteNonQueryAsync("delete from user where age > @age", new { age = 25 })
+ 提示:parms 参数还可以传 Dictionary<string, object>
+
+
+
+
+
+
+
+
+ 在【主库】执行
+
+
+
+
+
+
+
+
+ 在【主库】执行,ExecuteScalarAsync("select 1 from user where age > @age", new { age = 25 })
+ 提示:parms 参数还可以传 Dictionary<string, object>
+
+
+
+
+
+
+
+
+ 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new SqlParameter { ParameterName = "age", Value = 25 })
+
+
+
+
+
+
+
+
+
+
+ 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new { age = 25 })
+ 提示:parms 参数还可以传 Dictionary<string, object>
+
+
+
+
+
+
+
+
+
+ 执行SQL返回对象集合,Query<User>("select * from user where age > @age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 })
+
+
+
+
+
+
+
+
+
+
+
+ 执行SQL返回对象集合,Query<User, Address>("select * from user where age > @age; select * from address", new { age = 25 })
+ 提示:parms 参数还可以传 Dictionary<string, object>
+
+
+
+
+
+
+
+
可自定义解析表达式
@@ -3917,6 +4088,12 @@
超时
+
+
+ 获取资源
+
+
+
使用完毕后,归还资源
@@ -3987,6 +4164,12 @@
资源对象
+
+
+ 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象
+
+ 资源对象
+
归还对象给对象池的时候触发
diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0ProviderReader.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0ProviderReader.cs
index 954eb0fc..ff4cf074 100644
--- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0ProviderReader.cs
+++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0ProviderReader.cs
@@ -513,8 +513,14 @@ namespace FreeSql.Internal.CommonProvider
};
});
}
+ static EventHandler _OldAuditDataReaderHandler;
public GetAllFieldExpressionTreeInfo GetAllFieldExpressionTreeLevel2()
{
+ if (_OldAuditDataReaderHandler != _orm.Aop.AuditDataReaderHandler)
+ {
+ _OldAuditDataReaderHandler = _orm.Aop.AuditDataReaderHandler; //清除单表 ExppressionTree
+ _dicGetAllFieldExpressionTree.TryRemove($"{_orm.Ado.DataType}-{_tables[0].Table.DbName}-{_tables[0].Alias}-{_tables[0].Type}", out var oldet);
+ }
return _dicGetAllFieldExpressionTree.GetOrAdd(string.Join("+", _tables.Select(a => $"{_orm.Ado.DataType}-{a.Table.DbName}-{a.Alias}-{a.Type}")), s =>
{
var tb1 = _tables.First().Table;
@@ -621,18 +627,6 @@ namespace FreeSql.Internal.CommonProvider
)
});
}
- if (otherindex == 0)
- { //不读导航属性,优化单表读取性能
- blockExp.Clear();
- blockExp.AddRange(new Expression[] {
- Expression.Assign(dataIndexExp, Expression.Constant(0)),
- Expression.Assign(readExp, Expression.Call(Utils.MethodExecuteArrayRowReadClassOrTuple, new Expression[] { Expression.Constant(null, typeof(string)), Expression.Constant(type), Expression.Constant(null, typeof(int[])), rowExp, dataIndexExp, Expression.Constant(_commonUtils) })),
- Expression.IfThen(
- Expression.NotEqual(readExpValue, Expression.Constant(null)),
- Expression.Assign(retExp, Expression.Convert(readExpValue, type))
- )
- });
- }
if (tb1.TypeLazy != null)
blockExp.Add(
Expression.IfThen(
@@ -640,6 +634,66 @@ namespace FreeSql.Internal.CommonProvider
Expression.Call(retExp, tb1.TypeLazySetOrm, ormExp)
)
); //将 orm 传递给 lazy
+ if (otherindex == 0)
+ {
+ //不读导航属性,优化单表读取性能
+ blockExp.Clear();
+ blockExp.AddRange(new Expression[]{
+ Expression.Assign(retExp, type.InternalNewExpression()),
+ Expression.Assign(dataIndexExp, Expression.Constant(0))
+ });
+ var colidx = 0;
+ foreach (var col in tb.Table.Columns.Values)
+ {
+ var drvalType = col.Attribute.MapType.NullableTypeOrThis();
+ var propGetSetMethod = tb.Table.Properties[col.CsName].GetSetMethod(true);
+ if (col.CsType == col.Attribute.MapType &&
+ _orm.Aop.AuditDataReaderHandler == null &&
+ _dicMethodDataReaderGetValue.TryGetValue(col.Attribute.MapType.NullableTypeOrThis(), out var drGetValueMethod))
+ {
+ Expression drvalExp = Expression.Call(rowExp, drGetValueMethod, Expression.Constant(colidx));
+ if (col.CsType.IsNullableType()) drvalExp = Expression.Convert(drvalExp, col.CsType);
+ drvalExp = Expression.Condition(Expression.Call(rowExp, _MethodDataReaderIsDBNull, Expression.Constant(colidx)), Expression.Default(col.CsType), drvalExp);
+
+ if (drvalType.IsArray || drvalType.IsEnum || Utils.dicExecuteArrayRowReadClassOrTuple.ContainsKey(drvalType))
+ {
+ var drvalExpCatch = Utils.GetDataReaderValueBlockExpression(
+ col.CsType,
+ Expression.Call(Utils.MethodDataReaderGetValue, new Expression[] { Expression.Constant(_commonUtils), rowExp, Expression.Constant(colidx) })
+ );
+ blockExp.Add(Expression.TryCatch(
+ Expression.Call(retExp, propGetSetMethod, drvalExp),
+ Expression.Catch(typeof(Exception),
+ Expression.Call(retExp, propGetSetMethod, Expression.Convert(drvalExpCatch, col.CsType))
+ //Expression.Throw(Expression.Constant(new Exception($"{_commonUtils.QuoteSqlName(col.Attribute.Name)} is NULL,除非设置特性 [Column(IsNullable = false)]")))
+ )));
+ }
+ else
+ {
+ blockExp.Add(Expression.TryCatch(
+ Expression.Call(retExp, propGetSetMethod, drvalExp),
+ Expression.Catch(typeof(Exception),
+ Expression.Call(retExp, propGetSetMethod, Expression.Default(col.CsType))
+ //Expression.Throw(Expression.Constant(new Exception($"{_commonUtils.QuoteSqlName(col.Attribute.Name)} is NULL,除非设置特性 [Column(IsNullable = false)]")))
+ )));
+ }
+ }
+ else
+ {
+ if (drvalType.IsArray || drvalType.IsEnum || Utils.dicExecuteArrayRowReadClassOrTuple.ContainsKey(drvalType))
+ {
+ var drvalExp = Utils.GetDataReaderValueBlockExpression(
+ col.CsType,
+ Expression.Call(Utils.MethodDataReaderGetValue, new Expression[] { Expression.Constant(_commonUtils), rowExp, Expression.Constant(colidx) })
+ );
+ blockExp.Add(Expression.Call(retExp, propGetSetMethod, Expression.Convert(drvalExp, col.CsType)));
+ }
+ }
+ colidx++;
+ }
+ if (tb1.TypeLazy != null)
+ blockExp.Add(Expression.Call(retExp, tb1.TypeLazySetOrm, ormExp)); //将 orm 传递给 lazy
+ }
blockExp.AddRange(new Expression[] {
Expression.Return(returnTarget, retExp),
Expression.Label(returnTarget, Expression.Default(type))
@@ -651,6 +705,18 @@ namespace FreeSql.Internal.CommonProvider
};
});
}
+ static MethodInfo _MethodDataReaderIsDBNull = typeof(DbDataReader).GetMethod("IsDBNull", new Type[] { typeof(int) });
+ static Dictionary _dicMethodDataReaderGetValue = new Dictionary
+ {
+ [typeof(bool)] = typeof(DbDataReader).GetMethod("GetBoolean", new Type[] { typeof(int) }),
+ [typeof(int)] = typeof(DbDataReader).GetMethod("GetInt32", new Type[] { typeof(int) }),
+ [typeof(long)] = typeof(DbDataReader).GetMethod("GetInt64", new Type[] { typeof(int) }),
+ [typeof(double)] = typeof(DbDataReader).GetMethod("GetDouble", new Type[] { typeof(int) }),
+ [typeof(float)] = typeof(DbDataReader).GetMethod("GetFloat", new Type[] { typeof(int) }),
+ [typeof(decimal)] = typeof(DbDataReader).GetMethod("GetDecimal", new Type[] { typeof(int) }),
+ [typeof(DateTime)] = typeof(DbDataReader).GetMethod("GetDateTime", new Type[] { typeof(int) }),
+ [typeof(string)] = typeof(DbDataReader).GetMethod("GetString", new Type[] { typeof(int) }),
+ };
protected double InternalAvg(Expression exp)
{
diff --git a/README.md b/README.md
index 6d677cfe..6b976a39 100644
--- a/README.md
+++ b/README.md
@@ -14,12 +14,12 @@ FreeSql is a powerful O/RM component, supports .NET Core 2.1+, .NET Framework 4.
-- 🛠 Support CodeFirst mode, support data migration even when using Access database.
-- 💻 Support DbFirst mode, support import entity class from database, or use [Entity Class Generation Tool](https://github.com/2881099/FreeSql/wiki/DbFirst) to generate entity class.
+- 🛠 Support CodeFirst data migration.
+- 💻 Support DbFirst import entity class from database, or use [Generation Tool](https://github.com/2881099/FreeSql/wiki/DbFirst).
- ⛳ Support advanced type mapping, such as PostgreSQL array type, etc.
-- ✒ Support large number of expression functions, and highly customizable analysis.
-- 🏁 Support one-to-many and many-to-many greedy loading of navigation properties, and lazy loading.
-- 📃 Support Read/Write separation, Splitting Table/Database, Filters, Optimistic Locking and pessimistic locking.
+- 🌲 Support expression functions, and customizable analysis.
+- 🏁 Support one-to-many and many-to-many navigation properties, include and lazy loading.
+- 📃 Support Read/Write separation, Splitting Table/Database, Global filters, Optimistic and pessimistic locker.
- 🌳 Support MySql/SqlServer/PostgreSQL/Oracle/Sqlite/Firebird/达梦/人大金仓/神舟通用/翰高/Access, etc.
QQ Groups:4336577(full)、**8578575(available)**、**52508226(available)**
@@ -28,25 +28,22 @@ QQ Groups:4336577(full)、**8578575(available)**、**52508226(available)**
| | |
| - | - |
-|
| [Introduction](https://www.cnblogs.com/FreeSql/p/11531300.html) \| [Select](https://github.com/2881099/FreeSql/wiki/%e6%9f%a5%e8%af%a2) \| [Update](https://github.com/2881099/FreeSql/wiki/%e4%bf%ae%e6%94%b9) \| [Insert](https://github.com/2881099/FreeSql/wiki/%e6%b7%bb%e5%8a%a0) \| [Delete](https://github.com/2881099/FreeSql/wiki/%e5%88%a0%e9%99%a4) |
-|
| [Expression Functions](https://github.com/2881099/FreeSql/wiki/%e8%a1%a8%e8%be%be%e5%bc%8f%e5%87%bd%e6%95%b0) \| [CodeFirst](https://github.com/2881099/FreeSql/wiki/CodeFirst) \| [DbFirst](https://github.com/2881099/FreeSql/wiki/DbFirst) \| [Filters](https://github.com/2881099/FreeSql/wiki/%e8%bf%87%e6%bb%a4%e5%99%a8) |
-|
| [Repository](https://github.com/2881099/FreeSql/wiki/Repository) \| [UnitOfWork](https://github.com/2881099/FreeSql/wiki/%e5%b7%a5%e4%bd%9c%e5%8d%95%e5%85%83) \| [AOP](https://github.com/2881099/FreeSql/wiki/AOP) \| [DbContext](https://github.com/2881099/FreeSql/wiki/DbContext) |
-|
| [Read/Write Separation](https://github.com/2881099/FreeSql/wiki/%e8%af%bb%e5%86%99%e5%88%86%e7%a6%bb) \| [Splitting Table/Database](https://github.com/2881099/FreeSql/wiki/%e5%88%86%e8%a1%a8%e5%88%86%e5%ba%93) \| [Mysterious Technology](https://github.com/2881099/FreeSql/wiki/%E9%AA%9A%E6%93%8D%E4%BD%9C) \| [FAQ](https://github.com/dotnetcore/FreeSql/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98) \| [*Update Notes*](https://github.com/2881099/FreeSql/wiki/%e6%9b%b4%e6%96%b0%e6%97%a5%e5%bf%97) |
+| [Select](https://github.com/2881099/FreeSql/wiki/%e6%9f%a5%e8%af%a2) \| [Update](https://github.com/2881099/FreeSql/wiki/%e4%bf%ae%e6%94%b9) \| [Insert](https://github.com/2881099/FreeSql/wiki/%e6%b7%bb%e5%8a%a0) \| [Delete](https://github.com/2881099/FreeSql/wiki/%e5%88%a0%e9%99%a4) [FAQ](https://github.com/dotnetcore/FreeSql/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98) \| [*Update Notes*](https://github.com/2881099/FreeSql/wiki/%e6%9b%b4%e6%96%b0%e6%97%a5%e5%bf%97) |
+| [Expression Functions](https://github.com/2881099/FreeSql/wiki/%e8%a1%a8%e8%be%be%e5%bc%8f%e5%87%bd%e6%95%b0) \| [CodeFirst](https://github.com/2881099/FreeSql/wiki/CodeFirst) \| [DbFirst](https://github.com/2881099/FreeSql/wiki/DbFirst) \| [Filters](https://github.com/2881099/FreeSql/wiki/%e8%bf%87%e6%bb%a4%e5%99%a8) |
+| [Repository](https://github.com/2881099/FreeSql/wiki/Repository) \| [UnitOfWork](https://github.com/2881099/FreeSql/wiki/%e5%b7%a5%e4%bd%9c%e5%8d%95%e5%85%83) \| [AOP](https://github.com/2881099/FreeSql/wiki/AOP) \| [DbContext](https://github.com/2881099/FreeSql/wiki/DbContext) |
+| [Read/Write Separation](https://github.com/2881099/FreeSql/wiki/%e8%af%bb%e5%86%99%e5%88%86%e7%a6%bb) \| [Splitting Table/Database](https://github.com/2881099/FreeSql/wiki/%e5%88%86%e8%a1%a8%e5%88%86%e5%ba%93) \| [Mysterious Technology](https://github.com/2881099/FreeSql/wiki/%E9%AA%9A%E6%93%8D%E4%BD%9C) \| |
> FreeSql provides a variety of usage habits, and there is always one that suits you:
- Use FreeSql, keep the original usage.
-- Use [FreeSql.Repository](https://github.com/2881099/FreeSql/wiki/Repository), for those who are accustomed to storage models and work units.
-- Use [FreeSql.DbContext](https://github.com/2881099/FreeSql/wiki/DbContext), a bit like how efcore is used.
-- Or use [FreeSql.BaseEntity](https://github.com/2881099/FreeSql/tree/master/Examples/base_entity), which is extremely simple.
+- Use [FreeSql.Repository](https://github.com/2881099/FreeSql/wiki/Repository), Repository + UnitOfWork.
+- Use [FreeSql.DbContext](https://github.com/2881099/FreeSql/wiki/DbContext), Like efcore.
+- Or use [FreeSql.BaseEntity](https://github.com/2881099/FreeSql/tree/master/Examples/base_entity), Simple mode.
> Some open source projects that use FreeSql:
-- [Zhontai.net Admin, Management System](https://github.com/zhontai/Admin.Core)
+- [Zhontai.net Admin Management System](https://github.com/zhontai/Admin.Core)
- [A simple and practical CMS implemented by .NET Core](https://github.com/luoyunchong/lin-cms-dotnetcore)
-- [iusaas.com SaaS, Enterprise Application Management System](https://github.com/alonsoalon/TenantSite.Server)
-- [EasyCms, CMS management system used by enterprises and institutions](https://github.com/jasonyush/EasyCMS)
-- [Content management system](https://github.com/hejiyong/fscms)