diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml
index 2d6d3409..b54d4d0e 100644
--- a/FreeSql.DbContext/FreeSql.DbContext.xml
+++ b/FreeSql.DbContext/FreeSql.DbContext.xml
@@ -509,14 +509,5 @@
-
-
- 批量注入 Repository,可以参考代码自行调整
-
-
-
-
-
-
diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml
index 751d06c0..b25afc15 100644
--- a/FreeSql/FreeSql.xml
+++ b/FreeSql/FreeSql.xml
@@ -1160,6 +1160,15 @@
+
+
+ MySql find_in_set(str, strlist)
+
+
+
+
+
+
PostgreSQL string_agg(.., ..)
@@ -1639,6 +1648,17 @@
使用属性名作为字段别名
+
+
+ 控制取消本次查询
+ * 不会产生额外的异常
+ * 取消成功,则不执行 SQL 命令
+ * 取消成功,直接返回没有记录时候的返回值
+ * 取消成功,如 List<T> 返回 0 元素列表,不是 null,仍然是旧机制
+
+ 返回 true,则不会执行 SQL 命令
+
+
指定事务对象
@@ -2331,6 +2351,15 @@
选择一个导航属性
+
+
+ 贪婪加载导航属性,如果查询中已经使用了 a.Parent.Parent 类似表达式,则可以无需此操作
+
+
+ true 时生效
+ 选择一个导航属性
+
+
贪婪加载集合的导航属性,其实是分两次查询,ToList 后进行了数据重装
@@ -2352,6 +2381,14 @@
+
+
+ 按属性名字符串进行 Include/IncludeMany 操作
+
+ true 时生效
+
+
+
实现 select .. from ( select ... from t ) a 这样的功能
diff --git a/FreeSql/Interface/Curd/ISelect/ISelect0.cs b/FreeSql/Interface/Curd/ISelect/ISelect0.cs
index 11a54853..3f0119fc 100644
--- a/FreeSql/Interface/Curd/ISelect/ISelect0.cs
+++ b/FreeSql/Interface/Curd/ISelect/ISelect0.cs
@@ -30,6 +30,17 @@ namespace FreeSql
Task CountAsync(CancellationToken cancellationToken = default);
#endif
+ ///
+ /// 控制取消本次查询
+ /// * 不会产生额外的异常
+ /// * 取消成功,则不执行 SQL 命令
+ /// * 取消成功,直接返回没有记录时候的返回值
+ /// * 取消成功,如 List<T> 返回 0 元素列表,不是 null,仍然是旧机制
+ ///
+ /// 返回 true,则不会执行 SQL 命令
+ ///
+ TSelect Cancel(Func cancel);
+
///
/// 指定事务对象
///
diff --git a/FreeSql/Interface/Curd/ISelect/ISelect1.cs b/FreeSql/Interface/Curd/ISelect/ISelect1.cs
index 74372279..4bff2524 100644
--- a/FreeSql/Interface/Curd/ISelect/ISelect1.cs
+++ b/FreeSql/Interface/Curd/ISelect/ISelect1.cs
@@ -321,6 +321,14 @@ namespace FreeSql
///
ISelect Include(Expression> navigateSelector) where TNavigate : class;
///
+ /// 贪婪加载导航属性,如果查询中已经使用了 a.Parent.Parent 类似表达式,则可以无需此操作
+ ///
+ ///
+ /// true 时生效
+ /// 选择一个导航属性
+ ///
+ ISelect IncludeIf(bool condition, Expression> navigateSelector) where TNavigate : class;
+ ///
/// 贪婪加载集合的导航属性,其实是分两次查询,ToList 后进行了数据重装
/// 文档:https://github.com/2881099/FreeSql/wiki/%e8%b4%aa%e5%a9%aa%e5%8a%a0%e8%bd%bd#%E5%AF%BC%E8%88%AA%E5%B1%9E%E6%80%A7-onetomanymanytomany
///
@@ -340,6 +348,13 @@ namespace FreeSql
///
///
ISelect IncludeByPropertyName(string property);
+ ///
+ /// 按属性名字符串进行 Include/IncludeMany 操作
+ ///
+ /// true 时生效
+ ///
+ ///
+ ISelect IncludeByPropertyNameIf(bool condition, string property);
///
/// 实现 select .. from ( select ... from t ) a 这样的功能
diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs
index ea4c9606..0e69ee7f 100644
--- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs
+++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs
@@ -42,6 +42,7 @@ namespace FreeSql.Internal.CommonProvider
public bool _distinct;
public Expression _selectExpression;
public List _whereGlobalFilter;
+ public Func _cancel;
int _disposeCounter;
~Select0Provider()
@@ -61,6 +62,7 @@ namespace FreeSql.Internal.CommonProvider
_includeInfo.Clear();
_selectExpression = null;
_whereGlobalFilter?.Clear();
+ _cancel = null;
}
public static void CopyData(Select0Provider from, Select0Provider to, ReadOnlyCollection lambParms)
@@ -119,6 +121,7 @@ namespace FreeSql.Internal.CommonProvider
to._distinct = from._distinct;
to._selectExpression = from._selectExpression;
to._whereGlobalFilter = new List(from._whereGlobalFilter.ToArray());
+ to._cancel = from._cancel;
}
public Expression ConvertStringPropertyToExpression(string property, bool fromFirstTable = false)
@@ -183,6 +186,12 @@ namespace FreeSql.Internal.CommonProvider
return this as TSelect;
}
+ public TSelect Cancel(Func cancel)
+ {
+ _cancel = cancel;
+ return this as TSelect;
+ }
+
public TSelect WithTransaction(DbTransaction transaction)
{
_transaction = transaction;
diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0ProviderReader.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0ProviderReader.cs
index 91c3f7c8..d4bf7c3d 100644
--- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0ProviderReader.cs
+++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0ProviderReader.cs
@@ -21,11 +21,12 @@ namespace FreeSql.Internal.CommonProvider
{
public DataTable ToDataTable(string field = null)
{
+ DataTable ret = null;
+ if (_cancel?.Invoke() == true) return ret;
var sql = this.ToSql(field);
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- DataTable ret = null;
Exception exception = null;
try
{
@@ -46,12 +47,13 @@ namespace FreeSql.Internal.CommonProvider
public List ToList(string field)
{
+ var ret = new List();
+ if (_cancel?.Invoke() == true) return ret;
var sql = this.ToSql(field);
var type = typeof(TTuple);
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- var ret = new List();
Exception exception = null;
try
{
@@ -81,10 +83,11 @@ namespace FreeSql.Internal.CommonProvider
}
internal List ToListAfPrivate(string sql, GetAllFieldExpressionTreeInfo af, ReadAnonymousTypeOtherInfo[] otherData)
{
+ var ret = new List();
+ if (_cancel?.Invoke() == true) return ret;
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- var ret = new List();
var retCount = 0;
Exception exception = null;
try
@@ -133,6 +136,7 @@ namespace FreeSql.Internal.CommonProvider
#region ToChunk
internal void ToListAfChunkPrivate(int chunkSize, Action>> chunkDone, string sql, GetAllFieldExpressionTreeInfo af, ReadAnonymousTypeOtherInfo[] otherData)
{
+ if (_cancel?.Invoke() == true) return;
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
@@ -208,6 +212,7 @@ namespace FreeSql.Internal.CommonProvider
internal void ToListMrChunkPrivate(int chunkSize, Action>> chunkDone, string sql, ReadAnonymousTypeAfInfo af)
{
+ if (_cancel?.Invoke() == true) return;
var type = typeof(TReturn);
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
@@ -266,12 +271,14 @@ namespace FreeSql.Internal.CommonProvider
{
if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
if (elementSelector == null) throw new ArgumentNullException(nameof(elementSelector));
+
+ var ret = new Dictionary();
+ if (_cancel?.Invoke() == true) return ret;
var af = this.GetAllFieldExpressionTreeLevel2();
var sql = this.ToSql(af.Field);
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- var ret = new Dictionary();
Exception exception = null;
try
{
@@ -297,11 +304,12 @@ namespace FreeSql.Internal.CommonProvider
internal List ToListMrPrivate(string sql, ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData)
{
+ var ret = new List();
+ if (_cancel?.Invoke() == true) return ret;
var type = typeof(TReturn);
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- var ret = new List();
var retCount = 0;
Exception exception = null;
try
@@ -715,12 +723,13 @@ namespace FreeSql.Internal.CommonProvider
}
public int InternalInsertInto(string tableName, Expression select)
{
+ int ret = 0;
+ if (_cancel?.Invoke() == true) return ret;
var sql = this.InternalGetInsertIntoToSql(tableName, select);
var dbParms = _params.ToArray();
var tb = _orm.CodeFirst.GetTableByEntity(typeof(TTargetEntity));
var before = new Aop.CurdBeforeEventArgs(tb.Type, tb, Aop.CurdType.Insert, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- int ret = 0;
Exception exception = null;
try
{
@@ -741,11 +750,12 @@ namespace FreeSql.Internal.CommonProvider
protected DataTable InternalToDataTable(Expression select)
{
+ DataTable ret = null;
+ if (_cancel?.Invoke() == true) return ret;
var sql = this.InternalToSql(select, FieldAliasOptions.AsProperty); //DataTable 使用 AsProperty
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- DataTable ret = null;
Exception exception = null;
try
{
@@ -790,11 +800,12 @@ namespace FreeSql.Internal.CommonProvider
#else
async public Task ToDataTableAsync(string field, CancellationToken cancellationToken)
{
+ DataTable ret = null;
+ if (_cancel?.Invoke() == true) return ret;
var sql = this.ToSql(field);
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- DataTable ret = null;
Exception exception = null;
try
{
@@ -815,12 +826,13 @@ namespace FreeSql.Internal.CommonProvider
async public Task> ToListAsync(string field, CancellationToken cancellationToken)
{
+ var ret = new List();
+ if (_cancel?.Invoke() == true) return ret;
var sql = this.ToSql(field);
var type = typeof(TTuple);
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- var ret = new List();
Exception exception = null;
try
{
@@ -852,10 +864,11 @@ namespace FreeSql.Internal.CommonProvider
async internal Task> ToListAfPrivateAsync(string sql, GetAllFieldExpressionTreeInfo af, ReadAnonymousTypeOtherInfo[] otherData, CancellationToken cancellationToken)
{
+ var ret = new List();
+ if (_cancel?.Invoke() == true) return ret;
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- var ret = new List();
var retCount = 0;
Exception exception = null;
try
@@ -909,12 +922,14 @@ namespace FreeSql.Internal.CommonProvider
{
if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
if (elementSelector == null) throw new ArgumentNullException(nameof(elementSelector));
+
+ var ret = new Dictionary();
+ if (_cancel?.Invoke() == true) return ret;
var af = this.GetAllFieldExpressionTreeLevel2();
var sql = this.ToSql(af.Field);
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- var ret = new Dictionary();
Exception exception = null;
try
{
@@ -941,11 +956,12 @@ namespace FreeSql.Internal.CommonProvider
async internal Task> ToListMrPrivateAsync(string sql, ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData, CancellationToken cancellationToken)
{
+ var ret = new List();
+ if (_cancel?.Invoke() == true) return ret;
var type = typeof(TReturn);
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- var ret = new List();
var retCount = 0;
Exception exception = null;
try
@@ -1006,12 +1022,13 @@ namespace FreeSql.Internal.CommonProvider
async public Task InternalInsertIntoAsync(string tableName, Expression select, CancellationToken cancellationToken)
{
+ int ret = 0;
+ if (_cancel?.Invoke() == true) return ret;
var sql = this.InternalGetInsertIntoToSql(tableName, select);
var dbParms = _params.ToArray();
var tb = _orm.CodeFirst.GetTableByEntity(typeof(TTargetEntity));
var before = new Aop.CurdBeforeEventArgs(tb.Type, tb, Aop.CurdType.Insert, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- int ret = 0;
Exception exception = null;
try
{
@@ -1032,11 +1049,12 @@ namespace FreeSql.Internal.CommonProvider
async protected Task InternalToDataTableAsync(Expression select, CancellationToken cancellationToken)
{
+ DataTable ret = null;
+ if (_cancel?.Invoke() == true) return ret;
var sql = this.InternalToSql(select, FieldAliasOptions.AsProperty); //DataTable 使用 AsProperty
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
- DataTable ret = null;
Exception exception = null;
try
{
diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs
index c336fcf0..03360ada 100644
--- a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs
+++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs
@@ -393,6 +393,7 @@ namespace FreeSql.Internal.CommonProvider
public int InsertInto(string tableName, Expression> select) where TTargetEntity : class => base.InternalInsertInto(tableName, select);
+ public ISelect IncludeByPropertyNameIf(bool condition, string property) => condition ? IncludeByPropertyName(property) : this;
public ISelect IncludeByPropertyName(string property)
{
var exp = ConvertStringPropertyToExpression(property, true);
@@ -424,6 +425,7 @@ namespace FreeSql.Internal.CommonProvider
}
bool _isIncluded = false;
+ public ISelect IncludeIf(bool condition, Expression> navigateSelector) where TNavigate : class => condition ? Include(navigateSelector) : this;
public ISelect Include(Expression> navigateSelector) where TNavigate : class
{
var expBody = navigateSelector?.Body;
diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs
index 44c1b28d..a25b713d 100644
--- a/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs
+++ b/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs
@@ -171,7 +171,7 @@ namespace FreeSql.Internal.CommonProvider
return this;
}
- public long Count() => long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_select._connection, _select._transaction, CommandType.Text, $"select count(1) from ({this.ToSql($"1{_comonExp._common.FieldAsAlias("as1")}")}) fta", _select._commandTimeout, _select._params.ToArray())), out var trylng) ? trylng : default(long);
+ public long Count() => _select._cancel?.Invoke() == true ? 0 : long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_select._connection, _select._transaction, CommandType.Text, $"select count(1) from ({this.ToSql($"1{_comonExp._common.FieldAsAlias("as1")}")}) fta", _select._commandTimeout, _select._params.ToArray())), out var trylng) ? trylng : default(long);
public ISelectGrouping Count(out long count)
{
count = this.Count();
@@ -200,7 +200,7 @@ namespace FreeSql.Internal.CommonProvider
#if net40
#else
- async public Task CountAsync(CancellationToken cancellationToken = default) => long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_select._connection, _select._transaction, CommandType.Text, $"select count(1) from ({this.ToSql($"1{_comonExp._common.FieldAsAlias("as1")}")}) fta", _select._commandTimeout, _select._params.ToArray(), cancellationToken)), out var trylng) ? trylng : default(long);
+ async public Task CountAsync(CancellationToken cancellationToken = default) => _select._cancel?.Invoke() == true ? 0 : long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_select._connection, _select._transaction, CommandType.Text, $"select count(1) from ({this.ToSql($"1{_comonExp._common.FieldAsAlias("as1")}")}) fta", _select._commandTimeout, _select._params.ToArray(), cancellationToken)), out var trylng) ? trylng : default(long);
public Task> ToListAsync(Expression, TReturn>> select, CancellationToken cancellationToken = default)
{