-
Notifications
You must be signed in to change notification settings - Fork 872
/
Copy pathFreeSqlExtensionsLinq.cs
153 lines (147 loc) · 8.56 KB
/
FreeSqlExtensionsLinq.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
using FreeSql;
using FreeSql.Extensions.Linq;
using FreeSql.Internal;
using FreeSql.Internal.CommonProvider;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
public static class FreeSqlExtensionsLinqSql
{
/// <summary>
/// 将 ISelect<T1> 转换为 IQueryable<T1><para></para>
/// 用于扩展如:abp IRepository GetAll() 接口方法需要返回 IQueryable 对象<para></para>
/// 提示:IQueryable 方法污染严重,查询功能的实现也不理想,应尽量避免此转换<para></para>
/// IQueryable<T1> 扩展方法 RestoreToSelect() 可以还原为 ISelect<T1>
/// </summary>
/// <returns></returns>
public static IQueryable<T1> AsQueryable<T1>(this ISelect<T1> that) where T1 : class
{
return new QueryableProvider<T1, T1>(that as Select1Provider<T1>);
}
/// <summary>
/// 将 IQueryable<T1> 转换为 ISelect<T1><para></para>
/// 前提:IQueryable 必须由 FreeSql.Extensions.Linq.QueryableProvider 实现
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <param name="that"></param>
/// <returns></returns>
public static ISelect<T1> RestoreToSelect<T1>(this IQueryable<T1> that) where T1 : class
{
var queryable = that as QueryableProvider<T1, T1> ?? throw new Exception(CoreErrorStrings.S_CannotBeConverted_To_ISelect(typeof(T1).Name));
return queryable._select;
}
/// <summary>
/// 【linq to sql】专用扩展方法,不建议直接使用
/// </summary>
public static ISelect<TReturn> Select<T1, TReturn>(this ISelect<T1> that, Expression<Func<T1, TReturn>> select)
{
var s1p = that as Select1Provider<T1>;
if (typeof(TReturn) == typeof(T1)) return that as ISelect<TReturn>;
s1p._tables[0].Parameter = select.Parameters[0];
s1p._selectExpression = select.Body;
if (s1p._orm.CodeFirst.IsAutoSyncStructure)
(s1p._orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TReturn)); //._dicSyced.TryAdd(typeof(TReturn), true);
var ret = (s1p._orm as BaseDbProvider).CreateSelectProvider<TReturn>(null) as Select1Provider<TReturn>;
Select0Provider.CopyData(s1p, ret, null);
return ret;
}
/// <summary>
/// 【linq to sql】专用扩展方法,不建议直接使用
/// </summary>
public static ISelect<TResult> Join<T1, TInner, TKey, TResult>(this ISelect<T1> that, ISelect<TInner> inner, Expression<Func<T1, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<T1, TInner, TResult>> resultSelector) where T1 : class where TInner : class where TResult : class
{
var s1p = that as Select1Provider<T1>;
InternalJoin2(s1p, outerKeySelector, innerKeySelector, resultSelector);
if (typeof(TResult) == typeof(T1)) return that as ISelect<TResult>;
s1p._selectExpression = resultSelector.Body;
if (s1p._orm.CodeFirst.IsAutoSyncStructure)
(s1p._orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true);
var ret = s1p._orm.Select<TResult>() as Select1Provider<TResult>;
Select0Provider.CopyData(s1p, ret, null);
return ret;
}
internal static void InternalJoin2<T1>(Select1Provider<T1> s1p, LambdaExpression outerKeySelector, LambdaExpression innerKeySelector, LambdaExpression resultSelector) where T1 : class
{
s1p._tables[0].Parameter = resultSelector.Parameters[0];
s1p._commonExpression.ExpressionLambdaToSql(outerKeySelector, new CommonExpression.ExpTSC { _tables = s1p._tables, _tableRule = s1p._tableRule });
s1p.InternalJoin(Expression.Lambda(typeof(Func<,,>).MakeGenericType(typeof(T1), innerKeySelector.Parameters[0].Type, typeof(bool)),
Expression.Equal(outerKeySelector.Body, innerKeySelector.Body),
new[] { outerKeySelector.Parameters[0], innerKeySelector.Parameters[0] }
), SelectTableInfoType.InnerJoin);
}
/// <summary>
/// 【linq to sql】专用扩展方法,不建议直接使用
/// </summary>
public static ISelect<TResult> GroupJoin<T1, TInner, TKey, TResult>(this ISelect<T1> that, ISelect<TInner> inner, Expression<Func<T1, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<T1, ISelect<TInner>, TResult>> resultSelector) where T1 : class where TInner : class where TResult : class
{
var s1p = that as Select1Provider<T1>;
InternalJoin2(s1p, outerKeySelector, innerKeySelector, resultSelector);
if (typeof(TResult) == typeof(T1)) return that as ISelect<TResult>;
s1p._selectExpression = resultSelector.Body;
if (s1p._orm.CodeFirst.IsAutoSyncStructure)
(s1p._orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true);
var ret = s1p._orm.Select<TResult>() as Select1Provider<TResult>;
Select0Provider.CopyData(s1p, ret, null);
return ret;
}
/// <summary>
/// 【linq to sql】专用扩展方法,不建议直接使用
/// </summary>
public static ISelect<TResult> SelectMany<T1, TCollection, TResult>(this ISelect<T1> that, Expression<Func<T1, ISelect<TCollection>>> collectionSelector, Expression<Func<T1, TCollection, TResult>> resultSelector) where T1 : class where TCollection : class where TResult : class
{
var s1p = that as Select1Provider<T1>;
InternalSelectMany2(s1p, collectionSelector, resultSelector);
if (typeof(TResult) == typeof(T1)) return that as ISelect<TResult>;
s1p._selectExpression = resultSelector.Body;
if (s1p._orm.CodeFirst.IsAutoSyncStructure)
(s1p._orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(TResult)); //._dicSyced.TryAdd(typeof(TResult), true);
var ret = s1p._orm.Select<TResult>() as Select1Provider<TResult>;
Select0Provider.CopyData(s1p, ret, null);
return ret;
}
internal static void InternalSelectMany2<T1>(Select1Provider<T1> s1p, LambdaExpression collectionSelector, LambdaExpression resultSelector) where T1 : class
{
SelectTableInfo find = null;
if (collectionSelector.Body.NodeType == ExpressionType.Call)
{
var callExp = collectionSelector.Body as MethodCallExpression;
if (callExp.Method.Name == "DefaultIfEmpty" && callExp.Method.GetGenericArguments().Any())
{
find = s1p._tables.Where((a, idx) => idx > 0 && a.Type == SelectTableInfoType.InnerJoin && a.Table.Type == callExp.Method.GetGenericArguments()[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 = s1p._commonUtils.GetTableByEntity(resultSelector.Parameters[1].Type);
if (tb == null) throw new Exception($"SelectMany 错误的类型:{resultSelector.Parameters[1].Type.FullName}");
s1p._tables.Add(new SelectTableInfo { Alias = resultSelector.Parameters[1].Name, AliasInit = resultSelector.Parameters[1].Name, Parameter = resultSelector.Parameters[1], Table = tb, Type = SelectTableInfoType.From });
}
}
/// <summary>
/// 【linq to sql】专用扩展方法,不建议直接使用
/// </summary>
public static ISelect<T1> DefaultIfEmpty<T1>(this ISelect<T1> that) where T1 : class
{
return that;
}
/// <summary>
/// 【linq to sql】专用扩展方法,不建议直接使用
/// </summary>
public static ISelect<T1> ThenBy<T1, TMember>(this ISelect<T1> that, Expression<Func<T1, TMember>> column) where T1 : class => that.OrderBy(column);
/// <summary>
/// 【linq to sql】专用扩展方法,不建议直接使用
/// </summary>
public static ISelect<T1> ThenByDescending<T1, TMember>(this ISelect<T1> that, Expression<Func<T1, TMember>> column) where T1 : class => that.OrderByDescending(column);
}