mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	- 增加 linq to sql 的查询语法,以及单元测试;
This commit is contained in:
		@@ -770,7 +770,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
							if (mp?.Expression != null) { //导航条件,OneToOne、ManyToOne
 | 
			
		||||
								var firstTb = tsc._tables.First().Table;
 | 
			
		||||
								var parentTb = _common.GetTableByEntity(mp.Expression.Type);
 | 
			
		||||
								var parentTbRef = parentTb.GetTableRef(mp.Member.Name, tsc.style == ExpressionStyle.AsSelect);
 | 
			
		||||
								var parentTbRef = parentTb?.GetTableRef(mp.Member.Name, tsc.style == ExpressionStyle.AsSelect);
 | 
			
		||||
								if (parentTbRef != null) {
 | 
			
		||||
									Expression navCondExp = null;
 | 
			
		||||
									for (var mn = 0; mn < parentTbRef.Columns.Count; mn++) {
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
		protected DbConnection _connection;
 | 
			
		||||
		protected Action<object> _trackToList;
 | 
			
		||||
		protected bool _distinct;
 | 
			
		||||
		protected Expression _selectExpression;
 | 
			
		||||
 | 
			
		||||
		internal static void CopyData(Select0Provider<TSelect, T1> from, object to, ReadOnlyCollection<ParameterExpression> lambParms) {
 | 
			
		||||
			var toType = to?.GetType();
 | 
			
		||||
@@ -43,19 +44,22 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			toType.GetField("_having", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._having);
 | 
			
		||||
			toType.GetField("_where", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new StringBuilder().Append(from._where.ToString()));
 | 
			
		||||
			toType.GetField("_params", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<DbParameter>(from._params.ToArray()));
 | 
			
		||||
			//toType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<SelectTableInfo>(from._tables.ToArray()));
 | 
			
		||||
			var _multiTables = toType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(to) as List<SelectTableInfo>;
 | 
			
		||||
			_multiTables[0] = from._tables[0];
 | 
			
		||||
			for (var a = 1; a < lambParms.Count; a++) {
 | 
			
		||||
				var tb = from._tables.Where(b => b.Alias == lambParms[a].Name && b.Table.Type == lambParms[a].Type).FirstOrDefault();
 | 
			
		||||
				if (tb != null) _multiTables[a] = tb;
 | 
			
		||||
				else {
 | 
			
		||||
					_multiTables[a].Alias = lambParms[a].Name;
 | 
			
		||||
					_multiTables[a].Parameter = lambParms[a];
 | 
			
		||||
			if (lambParms == null)
 | 
			
		||||
				toType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<SelectTableInfo>(from._tables.ToArray()));
 | 
			
		||||
			else {
 | 
			
		||||
				var _multiTables = toType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(to) as List<SelectTableInfo>;
 | 
			
		||||
				_multiTables[0] = from._tables[0];
 | 
			
		||||
				for (var a = 1; a < lambParms.Count; a++) {
 | 
			
		||||
					var tb = from._tables.Where(b => b.Alias == lambParms[a].Name && b.Table.Type == lambParms[a].Type).FirstOrDefault();
 | 
			
		||||
					if (tb != null) _multiTables[a] = tb;
 | 
			
		||||
					else {
 | 
			
		||||
						_multiTables[a].Alias = lambParms[a].Name;
 | 
			
		||||
						_multiTables[a].Parameter = lambParms[a];
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if (_multiTables.Count < from._tables.Count)
 | 
			
		||||
					_multiTables.AddRange(from._tables.GetRange(_multiTables.Count, from._tables.Count - _multiTables.Count));
 | 
			
		||||
			}
 | 
			
		||||
			if (_multiTables.Count < from._tables.Count)
 | 
			
		||||
				_multiTables.AddRange(from._tables.GetRange(_multiTables.Count, from._tables.Count - _multiTables.Count));
 | 
			
		||||
			toType.GetField("_tableRules", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._tableRules);
 | 
			
		||||
			toType.GetField("_join", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new StringBuilder().Append(from._join.ToString()));
 | 
			
		||||
			toType.GetField("_cache", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._cache);
 | 
			
		||||
@@ -66,6 +70,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			toType.GetField("_connection", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._connection);
 | 
			
		||||
			toType.GetField("_trackToList", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._trackToList);
 | 
			
		||||
			toType.GetField("_distinct", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._distinct);
 | 
			
		||||
			toType.GetField("_selectExpression", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._selectExpression);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Select0Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) {
 | 
			
		||||
@@ -366,10 +371,14 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
				return ret;
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
		public List<T1> ToList(bool includeNestedMembers = false) => 
 | 
			
		||||
			this.ToListPrivate(includeNestedMembers == false ? this.GetAllFieldExpressionTreeLevel2() : this.GetAllFieldExpressionTreeLevelAll());
 | 
			
		||||
		public Task<List<T1>> ToListAsync(bool includeNestedMembers = false) => 
 | 
			
		||||
			this.ToListPrivateAsync(includeNestedMembers == false ? this.GetAllFieldExpressionTreeLevel2() : this.GetAllFieldExpressionTreeLevelAll());
 | 
			
		||||
		public List<T1> ToList(bool includeNestedMembers = false) {
 | 
			
		||||
			if (_selectExpression != null) return this.InternalToList<T1>(_selectExpression);
 | 
			
		||||
			return this.ToListPrivate(includeNestedMembers == false ? this.GetAllFieldExpressionTreeLevel2() : this.GetAllFieldExpressionTreeLevelAll());
 | 
			
		||||
		}
 | 
			
		||||
		public Task<List<T1>> ToListAsync(bool includeNestedMembers = false) {
 | 
			
		||||
			if (_selectExpression != null) return this.InternalToListAsync<T1>(_selectExpression);
 | 
			
		||||
			return this.ToListPrivateAsync(includeNestedMembers == false ? this.GetAllFieldExpressionTreeLevel2() : this.GetAllFieldExpressionTreeLevelAll());
 | 
			
		||||
		}
 | 
			
		||||
		public T1 ToOne() {
 | 
			
		||||
			this.Limit(1);
 | 
			
		||||
			return this.ToList().FirstOrDefault();
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ using System.Data;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
@@ -153,6 +154,70 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			return this.InternalToListAsync<TReturn>(select?.Body);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public ISelect<TReturn> Select<TReturn>(Expression<Func<T1, TReturn>> select) where TReturn : class {
 | 
			
		||||
			if (typeof(TReturn) == typeof(T1)) return this as ISelect<TReturn>;
 | 
			
		||||
			_tables[0].Parameter = select.Parameters[0];
 | 
			
		||||
			_selectExpression = select.Body;
 | 
			
		||||
			var ret = _orm.Select<TReturn>();
 | 
			
		||||
			Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, null);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		public ISelect<TResult> Join<TInner, TKey, TResult>(ISelect<TInner> inner, Expression<Func<T1, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<T1, TInner, TResult>> resultSelector) where TInner : class where TResult : class {
 | 
			
		||||
			_tables[0].Parameter = resultSelector.Parameters[0];
 | 
			
		||||
			_commonExpression.ExpressionLambdaToSql(outerKeySelector, new CommonExpression.ExpTSC { _tables = _tables });
 | 
			
		||||
			this.InternalJoin(Expression.Lambda<Func<T1, TInner, bool>>(
 | 
			
		||||
				Expression.Equal(outerKeySelector.Body, innerKeySelector.Body), 
 | 
			
		||||
				new[] { outerKeySelector.Parameters[0], innerKeySelector.Parameters[0] }
 | 
			
		||||
			), SelectTableInfoType.InnerJoin);
 | 
			
		||||
			if (typeof(TResult) == typeof(T1)) return this as ISelect<TResult>;
 | 
			
		||||
			_selectExpression = resultSelector.Body;
 | 
			
		||||
			var ret = _orm.Select<TResult>() as Select1Provider<TResult>;
 | 
			
		||||
			Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, null);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		public ISelect<TResult> GroupJoin<TInner, TKey, TResult>(ISelect<TInner> inner, Expression<Func<T1, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<T1, ISelect<TInner>, TResult>> resultSelector) where TInner : class where TResult : class {
 | 
			
		||||
			_tables[0].Parameter = resultSelector.Parameters[0];
 | 
			
		||||
			_commonExpression.ExpressionLambdaToSql(outerKeySelector, new CommonExpression.ExpTSC { _tables = _tables });
 | 
			
		||||
			this.InternalJoin(Expression.Lambda<Func<T1, TInner, bool>>(
 | 
			
		||||
				Expression.Equal(outerKeySelector.Body, innerKeySelector.Body),
 | 
			
		||||
				new[] { outerKeySelector.Parameters[0], innerKeySelector.Parameters[0] }
 | 
			
		||||
			), SelectTableInfoType.InnerJoin);
 | 
			
		||||
			if (typeof(TResult) == typeof(T1)) return this as ISelect<TResult>;
 | 
			
		||||
			_selectExpression = resultSelector.Body;
 | 
			
		||||
			var ret = _orm.Select<TResult>() as Select1Provider<TResult>;
 | 
			
		||||
			Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, null);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		public ISelect<TResult> SelectMany<TCollection, TResult>(Expression<Func<T1, ISelect<TCollection>>> collectionSelector, Expression<Func<T1, TCollection, TResult>> resultSelector) where TCollection : class where TResult : class {
 | 
			
		||||
			SelectTableInfo find = null;
 | 
			
		||||
			if (collectionSelector.Body.NodeType == ExpressionType.Call) {
 | 
			
		||||
				var callExp = collectionSelector.Body as MethodCallExpression;
 | 
			
		||||
				if (callExp.Method.Name == "DefaultIfEmpty" && callExp.Object.Type.GenericTypeArguments.Any()) {
 | 
			
		||||
					find = _tables.Where((a, idx) => idx > 0 && a.Type == SelectTableInfoType.InnerJoin && a.Table.Type == callExp.Object.Type.GenericTypeArguments[0]).LastOrDefault();
 | 
			
		||||
					if (find != null) {
 | 
			
		||||
						if (!string.IsNullOrEmpty(find.On)) find.On = Regex.Replace(find.On, $@"\b{find.Alias}\.", $"{resultSelector.Parameters[1].Name}.");
 | 
			
		||||
						if (!string.IsNullOrEmpty(find.NavigateCondition)) find.NavigateCondition = Regex.Replace(find.NavigateCondition, $@"\b{find.Alias}\.", $"{resultSelector.Parameters[1].Name}.");
 | 
			
		||||
						find.Type = SelectTableInfoType.LeftJoin;
 | 
			
		||||
						find.Alias = resultSelector.Parameters[1].Name;
 | 
			
		||||
						find.Parameter = resultSelector.Parameters[1];
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (find == null) {
 | 
			
		||||
				var tb = _commonUtils.GetTableByEntity(typeof(TCollection));
 | 
			
		||||
				if (tb == null) throw new Exception($"SelectMany 错误的类型:{typeof(TCollection).FullName}");
 | 
			
		||||
				_tables.Add(new SelectTableInfo { Alias = resultSelector.Parameters[1].Name, AliasInit = resultSelector.Parameters[1].Name, Parameter = resultSelector.Parameters[1], Table = tb, Type = SelectTableInfoType.From });
 | 
			
		||||
			}
 | 
			
		||||
			if (typeof(TResult) == typeof(T1)) return this as ISelect<TResult>;
 | 
			
		||||
			_selectExpression = resultSelector.Body;
 | 
			
		||||
			var ret = _orm.Select<TResult>() as Select1Provider<TResult>;
 | 
			
		||||
			Select0Provider<ISelect<T1>, T1>.CopyData(this, ret, null);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
		public ISelect<T1> DefaultIfEmpty() {
 | 
			
		||||
			return this;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public DataTable ToDataTable<TReturn>(Expression<Func<T1, TReturn>> select) {
 | 
			
		||||
			if (select == null) return this.InternalToDataTable(select?.Body);
 | 
			
		||||
			_tables[0].Parameter = select.Parameters[0];
 | 
			
		||||
 
 | 
			
		||||
@@ -110,6 +110,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
			
		||||
			method = method.MakeGenericMethod(typeof(TReturn));
 | 
			
		||||
			return method.Invoke(_select, new object[] { (map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) }) as Task<List<TReturn>>;
 | 
			
		||||
		}
 | 
			
		||||
		public List<TReturn> Select<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => ToList(select);
 | 
			
		||||
 | 
			
		||||
		public string ToSql<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) {
 | 
			
		||||
			var map = new ReadAnonymousTypeInfo();
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
 | 
			
		||||
		static ConcurrentDictionary<DataType, ConcurrentDictionary<Type, TableInfo>> _cacheGetTableByEntity = new ConcurrentDictionary<DataType, ConcurrentDictionary<Type, TableInfo>>();
 | 
			
		||||
		internal static void RemoveTableByEntity(Type entity, CommonUtils common) {
 | 
			
		||||
			if (entity.FullName.StartsWith("<>f__AnonymousType") ||
 | 
			
		||||
			if (entity.IsAnonymousType() ||
 | 
			
		||||
				entity.IsValueType ||
 | 
			
		||||
				entity.IsNullableType() ||
 | 
			
		||||
				entity.NullableTypeOrThis() == typeof(BigInteger)
 | 
			
		||||
@@ -27,7 +27,7 @@ namespace FreeSql.Internal {
 | 
			
		||||
			if (tbc.TryRemove(entity, out var trytb) && trytb?.TypeLazy != null) tbc.TryRemove(trytb.TypeLazy, out var trylz);
 | 
			
		||||
		}
 | 
			
		||||
		internal static TableInfo GetTableByEntity(Type entity, CommonUtils common) {
 | 
			
		||||
			if (entity.FullName.StartsWith("<>f__AnonymousType") ||
 | 
			
		||||
			if (entity.IsAnonymousType() ||
 | 
			
		||||
				entity.IsValueType || 
 | 
			
		||||
				entity.IsNullableType() || 
 | 
			
		||||
				entity.NullableTypeOrThis() == typeof(BigInteger)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user