Skip to content
This repository was archived by the owner on Feb 1, 2025. It is now read-only.

Commit 68e1c5e

Browse files
committed
Merge branch 'master' into release
2 parents 73c095d + bfa5871 commit 68e1c5e

36 files changed

+1211
-227
lines changed

Source/LinqToDB.EntityFrameworkCore/EFCoreMetadataReader.cs

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,38 @@
44
using System.Linq;
55
using System.Linq.Expressions;
66
using System.Reflection;
7-
using LinqToDB.Common;
8-
using LinqToDB.EntityFrameworkCore.Internal;
9-
using LinqToDB.SqlQuery;
107
using Microsoft.EntityFrameworkCore;
11-
using Microsoft.EntityFrameworkCore.Internal;
128
using Microsoft.EntityFrameworkCore.Metadata;
13-
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;
149
using Microsoft.EntityFrameworkCore.Metadata.Internal;
15-
using Microsoft.EntityFrameworkCore.Query.Expressions;
16-
using Microsoft.EntityFrameworkCore.Query.ExpressionVisitors;
10+
using Microsoft.EntityFrameworkCore.Query;
11+
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
12+
using Microsoft.EntityFrameworkCore.Storage;
1713

1814
namespace LinqToDB.EntityFrameworkCore
1915
{
2016
using Mapping;
2117
using Metadata;
2218
using Extensions;
19+
using Common;
20+
using Internal;
21+
using SqlQuery;
22+
using SqlExpression = Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlExpression;
2323

2424
/// <summary>
2525
/// LINQ To DB metadata reader for EF.Core model.
2626
/// </summary>
2727
internal class EFCoreMetadataReader : IMetadataReader
2828
{
2929
readonly IModel _model;
30-
private readonly SqlTranslatingExpressionVisitorDependencies _dependencies;
30+
private readonly RelationalSqlTranslatingExpressionVisitorDependencies _dependencies;
31+
private readonly IRelationalTypeMappingSource _mappingSource;
3132
private readonly ConcurrentDictionary<MemberInfo, EFCoreExpressionAttribute> _calculatedExtensions = new ConcurrentDictionary<MemberInfo, EFCoreExpressionAttribute>();
3233

33-
public EFCoreMetadataReader(IModel model, SqlTranslatingExpressionVisitorDependencies dependencies)
34+
public EFCoreMetadataReader(IModel model, RelationalSqlTranslatingExpressionVisitorDependencies dependencies, IRelationalTypeMappingSource mappingSource)
3435
{
3536
_model = model;
3637
_dependencies = dependencies;
38+
_mappingSource = mappingSource;
3739
}
3840

3941
public T[] GetAttributes<T>(Type type, bool inherit = true) where T : Attribute
@@ -43,8 +45,7 @@ public T[] GetAttributes<T>(Type type, bool inherit = true) where T : Attribute
4345
{
4446
if (typeof(T) == typeof(TableAttribute))
4547
{
46-
var relational = et.Relational();
47-
return new[] { (T)(Attribute)new TableAttribute(relational.TableName) { Schema = relational.Schema } };
48+
return new[] { (T)(Attribute)new TableAttribute(et.GetTableName()) { Schema = et.GetSchema() } };
4849
}
4950
}
5051

@@ -76,19 +77,17 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
7677
var primaryKeyOrder = 0;
7778
if (isPrimaryKey)
7879
{
79-
var pk = prop.GetContainingPrimaryKey();
80+
var pk = prop.FindContainingPrimaryKey();
8081
primaryKeyOrder = pk.Properties.Select((p, i) => new { p, index = i })
8182
.FirstOrDefault(v => v.p.GetIdentifyingMemberInfo() == memberInfo)?.index ?? 0;
8283
}
8384

84-
var relational = prop.Relational();
85-
8685
return new T[]{(T)(Attribute) new ColumnAttribute
8786
{
88-
Name = relational.ColumnName,
87+
Name = prop.GetColumnName(),
8988
Length = prop.GetMaxLength() ?? 0,
9089
CanBeNull = prop.IsNullable,
91-
DbType = relational.ColumnType,
90+
DbType = prop.GetColumnType(),
9291
IsPrimaryKey = isPrimaryKey,
9392
PrimaryKeyOrder = primaryKeyOrder,
9493
IsIdentity = prop.ValueGenerated == ValueGenerated.OnAdd,
@@ -170,21 +169,21 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
170169
{
171170
var method = (MethodInfo) memberInfo;
172171

173-
var func = _model?.Relational().DbFunctions.FirstOrDefault(f => f.MethodInfo == method);
172+
var func = _model?.GetDbFunctions().FirstOrDefault(f => f.MethodInfo == method);
174173
if (func != null)
175174
return new T[]
176175
{
177176
(T) (Attribute) new Sql.FunctionAttribute
178177
{
179-
Name = func.FunctionName,
178+
Name = func.Name,
180179
ServerSideOnly = true
181180
}
182181
};
183182

184183
var functionAttributes = memberInfo.GetCustomAttributes<DbFunctionAttribute>(inherit);
185184
return functionAttributes.Select(f => (T) (Attribute) new Sql.FunctionAttribute
186185
{
187-
Name = f.FunctionName,
186+
Name = f.Name,
188187
ServerSideOnly = true,
189188
}).ToArray();
190189
}
@@ -193,6 +192,21 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
193192
return Array.Empty<T>();
194193
}
195194

195+
class SqlTransparentExpression : SqlExpression
196+
{
197+
public Expression Expression { get; }
198+
199+
public SqlTransparentExpression(Expression expression, RelationalTypeMapping typeMapping) : base(expression.Type, typeMapping)
200+
{
201+
Expression = expression;
202+
}
203+
204+
public override void Print(ExpressionPrinter expressionPrinter)
205+
{
206+
expressionPrinter.Print(Expression);
207+
}
208+
}
209+
196210
private Sql.ExpressionAttribute GetDbFunctionFromMethodCall(Type type, MethodInfo methodInfo)
197211
{
198212
if (_dependencies == null || _model == null)
@@ -206,19 +220,19 @@ private Sql.ExpressionAttribute GetDbFunctionFromMethodCall(Type type, MethodInf
206220

207221
if (!methodInfo.IsGenericMethodDefinition && !mi.GetCustomAttributes<Sql.ExpressionAttribute>().Any())
208222
{
209-
var objExpr = Expression.Constant(DefaultValue.GetValue(type), type);
223+
var objExpr = new SqlTransparentExpression(Expression.Constant(DefaultValue.GetValue(type), type), _mappingSource.FindMapping(type));
210224
var parameterInfos = methodInfo.GetParameters();
211225
var parametersArray = parameterInfos
212226
.Select(p =>
213-
(Expression) Expression.Constant(DefaultValue.GetValue(p.ParameterType), p.ParameterType)).ToArray();
214-
215-
var mcExpr = Expression.Call(methodInfo.IsStatic ? null : objExpr, methodInfo, parametersArray);
227+
(SqlExpression)new SqlTransparentExpression(
228+
Expression.Constant(DefaultValue.GetValue(p.ParameterType), p.ParameterType),
229+
_mappingSource.FindMapping(p.ParameterType))).ToArray();
216230

217-
var newExpression = _dependencies.MethodCallTranslator.Translate(mcExpr, _model);
218-
if (newExpression != null && newExpression != mcExpr)
231+
var newExpression = _dependencies.MethodCallTranslatorProvider.Translate(_model, objExpr, methodInfo, parametersArray);
232+
if (newExpression != null)
219233
{
220234
if (!methodInfo.IsStatic)
221-
parametersArray = new Expression[] { objExpr }.Concat(parametersArray).ToArray();
235+
parametersArray = new SqlExpression[] { objExpr }.Concat(parametersArray).ToArray();
222236

223237
result = ConvertToExpressionAttribute(methodInfo, newExpression, parametersArray);
224238
}
@@ -243,11 +257,10 @@ private Sql.ExpressionAttribute GetDbFunctionFromProperty(Type type, PropertyInf
243257

244258
if ((propInfo.GetMethod?.IsStatic != true) && !mi.GetCustomAttributes<Sql.ExpressionAttribute>().Any())
245259
{
246-
var objExpr = Expression.Constant(DefaultValue.GetValue(type), type);
247-
var mcExpr = Expression.MakeMemberAccess(objExpr, propInfo);
260+
var objExpr = new SqlTransparentExpression(Expression.Constant(DefaultValue.GetValue(type), type), _mappingSource.FindMapping(propInfo));
248261

249-
var newExpression = _dependencies.MemberTranslator.Translate(mcExpr);
250-
if (newExpression != null && newExpression != mcExpr)
262+
var newExpression = _dependencies.MemberTranslatorProvider.Translate(objExpr, propInfo, propInfo.GetMemberType());
263+
if (newExpression != null)
251264
{
252265
var parametersArray = new Expression[] { objExpr };
253266
result = ConvertToExpressionAttribute(propInfo, newExpression, parametersArray);
@@ -264,7 +277,7 @@ private static EFCoreExpressionAttribute ConvertToExpressionAttribute(MemberInfo
264277
{
265278
string PrepareExpressionText(Expression expr)
266279
{
267-
var idx = parameters.IndexOf(expr);
280+
var idx = Array.IndexOf(parameters, expr);
268281
if (idx >= 0)
269282
return $"{{{idx}}}";
270283

@@ -273,9 +286,9 @@ string PrepareExpressionText(Expression expr)
273286

274287
if (expr is SqlFunctionExpression sqlFunction)
275288
{
276-
var text = sqlFunction.FunctionName;
289+
var text = sqlFunction.Name;
277290
if (!sqlFunction.Schema.IsNullOrEmpty())
278-
text = sqlFunction.Schema + "." + sqlFunction.FunctionName;
291+
text = sqlFunction.Schema + "." + sqlFunction.Name;
279292

280293
if (!sqlFunction.IsNiladic)
281294
{
@@ -328,7 +341,7 @@ private static Expression UnwrapConverted(Expression expr)
328341
{
329342
if (expr is SqlFunctionExpression func)
330343
{
331-
if (string.Equals(func.FunctionName, "COALESCE", StringComparison.InvariantCultureIgnoreCase) &&
344+
if (string.Equals(func.Name, "COALESCE", StringComparison.InvariantCultureIgnoreCase) &&
332345
func.Arguments.Count == 2 && func.Arguments[1].NodeType == ExpressionType.Default)
333346
return UnwrapConverted(func.Arguments[0]);
334347
}

Source/LinqToDB.EntityFrameworkCore/ILinqToDBForEFTools.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
using Microsoft.EntityFrameworkCore;
55
using Microsoft.EntityFrameworkCore.Infrastructure;
66
using Microsoft.EntityFrameworkCore.Metadata;
7-
using Microsoft.EntityFrameworkCore.Query.ExpressionVisitors;
7+
using Microsoft.EntityFrameworkCore.Query;
8+
using Microsoft.EntityFrameworkCore.Storage;
89
using Microsoft.Extensions.Logging;
910

1011
namespace LinqToDB.EntityFrameworkCore
@@ -37,8 +38,9 @@ public interface ILinqToDBForEFTools
3738
/// </summary>
3839
/// <param name="model">EF.Core data model.</param>
3940
/// <param name="dependencies"></param>
41+
/// <param name="mappingSource"></param>
4042
/// <returns>LINQ To DB metadata provider for specified EF.Core model. Can return <c>null</c>.</returns>
41-
IMetadataReader CreateMetadataReader(IModel model, SqlTranslatingExpressionVisitorDependencies dependencies);
43+
IMetadataReader CreateMetadataReader(IModel model, RelationalSqlTranslatingExpressionVisitorDependencies dependencies, IRelationalTypeMappingSource mappingSource);
4244

4345
/// <summary>
4446
/// Creates mapping schema using provided EF.Core data model and metadata provider.

Source/LinqToDB.EntityFrameworkCore/Internal/LinqToDBForEFQueryProvider.cs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
using System.Collections.Generic;
44
using System.Linq;
55
using System.Linq.Expressions;
6+
using System.Reflection;
67
using System.Threading;
78
using System.Threading.Tasks;
89

910
using Microsoft.EntityFrameworkCore.Query.Internal;
1011

1112
using JetBrains.Annotations;
13+
using LinqToDB.Expressions;
1214

1315
namespace LinqToDB.EntityFrameworkCore.Internal
1416
{
@@ -54,6 +56,16 @@ public TResult Execute<TResult>(Expression expression)
5456
return QueryProvider.Execute<TResult>(expression);
5557
}
5658

59+
private static MethodInfo _executeAsyncMethodInfo =
60+
MemberHelper.MethodOf((IQueryProviderAsync p) => p.ExecuteAsync<int>(null, default)).GetGenericMethodDefinition();
61+
62+
TResult IAsyncQueryProvider.ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
63+
{
64+
var item = typeof(TResult).GetGenericArguments()[0];
65+
var method = _executeAsyncMethodInfo.MakeGenericMethod(item);
66+
return (TResult) method.Invoke(QueryProvider, new object[] { expression, cancellationToken });
67+
}
68+
5769
public System.Collections.Generic.IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression)
5870
{
5971
return new AsyncEnumerableAdaper<TResult>(QueryProvider.ExecuteAsync<TResult>(expression));
@@ -87,9 +99,9 @@ IEnumerator IEnumerable.GetEnumerator()
8799

88100
#endregion
89101

90-
System.Collections.Generic.IAsyncEnumerator<T> System.Collections.Generic.IAsyncEnumerable<T>.GetEnumerator()
102+
System.Collections.Generic.IAsyncEnumerator<T> System.Collections.Generic.IAsyncEnumerable<T>.GetAsyncEnumerator(CancellationToken cancellationTokent)
91103
{
92-
return ExecuteAsync<T>(Expression).GetEnumerator();
104+
return ExecuteAsync<T>(Expression).GetAsyncEnumerator(CancellationToken.None);
93105
}
94106

95107
class AsyncEnumerableAdaper<TEntity> : System.Collections.Generic.IAsyncEnumerable<TEntity>
@@ -101,7 +113,7 @@ public AsyncEnumerableAdaper(IAsyncEnumerable<TEntity> asyncEnumerable)
101113
AsyncEnumerable = asyncEnumerable;
102114
}
103115

104-
public System.Collections.Generic.IAsyncEnumerator<TEntity> GetEnumerator()
116+
public System.Collections.Generic.IAsyncEnumerator<TEntity> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken())
105117
{
106118
return new AsyncEnumeratorAdapter<TEntity>(AsyncEnumerable.GetEnumerator());
107119
}
@@ -116,17 +128,18 @@ public AsyncEnumeratorAdapter(IAsyncEnumerator<TEntity> asyncEnumerator)
116128
AsyncEnumerator = asyncEnumerator;
117129
}
118130

119-
public void Dispose()
131+
public ValueTask<bool> MoveNextAsync()
120132
{
121-
AsyncEnumerator?.Dispose();
133+
return new ValueTask<bool>(AsyncEnumerator.MoveNext(CancellationToken.None));
122134
}
123135

124-
public Task<bool> MoveNext(CancellationToken cancellationToken)
136+
public TEntity Current => AsyncEnumerator.Current;
137+
138+
public ValueTask DisposeAsync()
125139
{
126-
return AsyncEnumerator.MoveNext(cancellationToken);
140+
AsyncEnumerator?.Dispose();
141+
return default;
127142
}
128-
129-
public TEntity Current => AsyncEnumerator.Current;
130143
}
131144

132145
}

Source/LinqToDB.EntityFrameworkCore/LinqToDBForEFTools.Mapping.cs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -93,25 +93,25 @@ static void InitializeSqlServerMapping()
9393
Linq.Expressions.MapMember(method, lambda);
9494
}
9595

96-
var freeTextMethod = sqlServerMethods.FirstOrDefault(m => m.Name == "FreeText" && m.GetParameters().Length == 3);
97-
if (freeTextMethod != null)
98-
{
99-
var propertyReferenceParam = Expression.Parameter(typeof(string), "propertyReference");
100-
var freeTextParam = Expression.Parameter(typeof(string), "freeText");
101-
102-
var lambda = Expression.Lambda(
103-
Expression.Call(
104-
MemberHelper.MethodOf(() => Sql.FreeText(null, null)),
105-
propertyReferenceParam,
106-
freeTextParam
107-
),
108-
dbFunctionsParameter,
109-
propertyReferenceParam,
110-
freeTextParam
111-
);
112-
113-
Linq.Expressions.MapMember(freeTextMethod, lambda);
114-
}
96+
// var freeTextMethod = sqlServerMethods.FirstOrDefault(m => m.Name == "FreeText" && m.GetParameters().Length == 3);
97+
// if (freeTextMethod != null)
98+
// {
99+
// var propertyReferenceParam = Expression.Parameter(typeof(string), "propertyReference");
100+
// var freeTextParam = Expression.Parameter(typeof(string), "freeText");
101+
//
102+
// var lambda = Expression.Lambda(
103+
// Expression.Call(
104+
// MemberHelper.MethodOf(() => Sql.FreeText(null, null)),
105+
// propertyReferenceParam,
106+
// freeTextParam
107+
// ),
108+
// dbFunctionsParameter,
109+
// propertyReferenceParam,
110+
// freeTextParam
111+
// );
112+
//
113+
// Linq.Expressions.MapMember(freeTextMethod, lambda);
114+
// }
115115

116116
}
117117

0 commit comments

Comments
 (0)