44using System . Linq ;
55using System . Linq . Expressions ;
66using System . Reflection ;
7+ using System . Runtime . CompilerServices ;
78using LinqToDB . Expressions ;
89using LinqToDB . Reflection ;
910using Microsoft . EntityFrameworkCore ;
@@ -29,17 +30,17 @@ namespace LinqToDB.EntityFrameworkCore
2930 /// </summary>
3031 internal class EFCoreMetadataReader : IMetadataReader
3132 {
32- readonly IModel _model ;
33- private readonly RelationalSqlTranslatingExpressionVisitorDependencies _dependencies ;
34- private readonly IRelationalTypeMappingSource _mappingSource ;
35- private readonly ConcurrentDictionary < MemberInfo , EFCoreExpressionAttribute > _calculatedExtensions = new ConcurrentDictionary < MemberInfo , EFCoreExpressionAttribute > ( ) ;
36- private readonly IDiagnosticsLogger < DbLoggerCategory . Query > _logger ;
37-
38- public EFCoreMetadataReader ( IModel model ,
39- RelationalSqlTranslatingExpressionVisitorDependencies dependencies ,
40- IRelationalTypeMappingSource mappingSource ,
41- IDiagnosticsLogger < DbLoggerCategory . Query > logger
42- )
33+ readonly IModel ? _model ;
34+ private readonly RelationalSqlTranslatingExpressionVisitorDependencies ? _dependencies ;
35+ private readonly IRelationalTypeMappingSource ? _mappingSource ;
36+ private readonly ConcurrentDictionary < MemberInfo , EFCoreExpressionAttribute ? > _calculatedExtensions = new ConcurrentDictionary < MemberInfo , EFCoreExpressionAttribute ? > ( ) ;
37+ private readonly IDiagnosticsLogger < DbLoggerCategory . Query > ? _logger ;
38+
39+ public EFCoreMetadataReader (
40+ IModel ? model ,
41+ RelationalSqlTranslatingExpressionVisitorDependencies ? dependencies ,
42+ IRelationalTypeMappingSource ? mappingSource ,
43+ IDiagnosticsLogger < DbLoggerCategory . Query > ? logger )
4344 {
4445 _model = model ;
4546 _dependencies = dependencies ;
@@ -54,7 +55,8 @@ public T[] GetAttributes<T>(Type type, bool inherit = true) where T : Attribute
5455 {
5556 if ( typeof ( T ) == typeof ( TableAttribute ) )
5657 {
57- return new [ ] { ( T ) ( Attribute ) new TableAttribute ( et . GetTableName ( ) ) { Schema = et . GetSchema ( ) } } ;
58+ var storeObjectId = GetStoreObjectIdentifier ( et ) ;
59+ return new [ ] { ( T ) ( Attribute ) new TableAttribute ( storeObjectId ! . Value . Name ) { Schema = storeObjectId ! . Value . Schema } } ;
5860 }
5961 if ( typeof ( T ) == typeof ( QueryFilterAttribute ) )
6062 {
@@ -67,19 +69,12 @@ public T[] GetAttributes<T>(Type type, bool inherit = true) where T : Attribute
6769 var contextProp = Expression . Property ( Expression . Convert ( dcParam , typeof ( LinqToDBForEFToolsDataConnection ) ) , "Context" ) ;
6870 var filterBody = filter . Body . Transform ( e =>
6971 {
70- switch ( e )
72+ if ( typeof ( DbContext ) . IsSameOrParentOf ( e . Type ) )
7173 {
72- case ConstantExpression cnt :
73- {
74- if ( typeof ( DbContext ) . IsSameOrParentOf ( cnt . Type ) )
75- {
76- Expression newExpr = contextProp ;
77- if ( newExpr . Type != cnt . Type )
78- newExpr = Expression . Convert ( newExpr , cnt . Type ) ;
79- return newExpr ;
80- }
81- break ;
82- }
74+ Expression newExpr = contextProp ;
75+ if ( newExpr . Type != e . Type )
76+ newExpr = Expression . Convert ( newExpr , e . Type ) ;
77+ return newExpr ;
8378 }
8479
8580 return e ;
@@ -114,7 +109,7 @@ public T[] GetAttributes<T>(Type type, bool inherit = true) where T : Attribute
114109 return Array . Empty < T > ( ) ;
115110 }
116111
117- static bool CompareProperty ( MemberInfo property , MemberInfo memberInfo )
112+ static bool CompareProperty ( MemberInfo ? property , MemberInfo memberInfo )
118113 {
119114 if ( property == memberInfo )
120115 return true ;
@@ -133,13 +128,11 @@ static bool CompareProperty(MemberInfo property, MemberInfo memberInfo)
133128 return false ;
134129 }
135130
136- [ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Usage" , "EF1001:Internal EF Core API usage." , Justification = "<Pending>" ) ]
137131 static bool CompareProperty ( IProperty property , MemberInfo memberInfo )
138132 {
139133 return CompareProperty ( property . GetIdentifyingMemberInfo ( ) , memberInfo ) ;
140134 }
141135
142- [ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Usage" , "EF1001:Internal EF Core API usage." , Justification = "<Pending>" ) ]
143136 public T [ ] GetAttributes < T > ( Type type , MemberInfo memberInfo , bool inherit = true ) where T : Attribute
144137 {
145138 if ( typeof ( Expression ) . IsSameOrParentOf ( type ) )
@@ -164,9 +157,11 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
164157 . FirstOrDefault ( v => CompareProperty ( v . p , memberInfo ) ) ? . index ?? 0 ;
165158 }
166159
160+ var storeObjectId = GetStoreObjectIdentifier ( et ) ;
161+
167162 return new T [ ] { ( T ) ( Attribute ) new ColumnAttribute
168163 {
169- Name = prop . GetColumnName ( ) ,
164+ Name = prop . GetColumnName ( storeObjectId ! . Value ) ,
170165 Length = prop . GetMaxLength ( ) ?? 0 ,
171166 CanBeNull = prop . IsNullable ,
172167 DbType = prop . GetColumnType ( ) ,
@@ -314,7 +309,7 @@ class SqlTransparentExpression : SqlExpression
314309 {
315310 public Expression Expression { get ; }
316311
317- public SqlTransparentExpression ( Expression expression , RelationalTypeMapping typeMapping ) : base ( expression . Type , typeMapping )
312+ public SqlTransparentExpression ( Expression expression , RelationalTypeMapping ? typeMapping ) : base ( expression . Type , typeMapping )
318313 {
319314 Expression = expression ;
320315 }
@@ -323,18 +318,45 @@ protected override void Print(ExpressionPrinter expressionPrinter)
323318 {
324319 expressionPrinter . Print ( Expression ) ;
325320 }
321+
322+ protected bool Equals ( SqlTransparentExpression other )
323+ {
324+ return ReferenceEquals ( this , other ) ;
325+ }
326+
327+ public override bool Equals ( object obj )
328+ {
329+ if ( ReferenceEquals ( null , obj ) ) return false ;
330+ if ( ReferenceEquals ( this , obj ) ) return true ;
331+ if ( obj . GetType ( ) != this . GetType ( ) ) return false ;
332+ return Equals ( ( SqlTransparentExpression ) obj ) ;
333+ }
334+
335+ public override int GetHashCode ( )
336+ {
337+ return RuntimeHelpers . GetHashCode ( this ) ;
338+ }
339+ }
340+
341+ private StoreObjectIdentifier ? GetStoreObjectIdentifier ( IEntityType entityType )
342+ {
343+ return entityType . GetTableName ( ) switch
344+ {
345+ not null => StoreObjectIdentifier . Create ( entityType , StoreObjectType . Table ) ,
346+ null => StoreObjectIdentifier . Create ( entityType , StoreObjectType . View ) ,
347+ } ;
326348 }
327349
328- private Sql . ExpressionAttribute GetDbFunctionFromMethodCall ( Type type , MethodInfo methodInfo )
350+ private Sql . ExpressionAttribute ? GetDbFunctionFromMethodCall ( Type type , MethodInfo methodInfo )
329351 {
330352 if ( _dependencies == null || _model == null )
331353 return null ;
332354
333- methodInfo = ( MethodInfo ) type . GetMemberEx ( methodInfo ) ?? methodInfo ;
355+ methodInfo = ( MethodInfo ? ) type . GetMemberEx ( methodInfo ) ?? methodInfo ;
334356
335357 var found = _calculatedExtensions . GetOrAdd ( methodInfo , mi =>
336358 {
337- EFCoreExpressionAttribute result = null ;
359+ EFCoreExpressionAttribute ? result = null ;
338360
339361 if ( ! methodInfo . IsGenericMethodDefinition && ! mi . GetCustomAttributes < Sql . ExpressionAttribute > ( ) . Any ( ) )
340362 {
@@ -364,19 +386,19 @@ private Sql.ExpressionAttribute GetDbFunctionFromMethodCall(Type type, MethodInf
364386 return found ;
365387 }
366388
367- private Sql . ExpressionAttribute GetDbFunctionFromProperty ( Type type , PropertyInfo propInfo )
389+ private Sql . ExpressionAttribute ? GetDbFunctionFromProperty ( Type type , PropertyInfo propInfo )
368390 {
369391 if ( _dependencies == null || _model == null )
370392 return null ;
371393
372- propInfo = ( PropertyInfo ) type . GetMemberEx ( propInfo ) ?? propInfo ;
394+ propInfo = ( PropertyInfo ? ) type . GetMemberEx ( propInfo ) ?? propInfo ;
373395
374396 var found = _calculatedExtensions . GetOrAdd ( propInfo , mi =>
375397 {
376- EFCoreExpressionAttribute result = null ;
398+ EFCoreExpressionAttribute ? result = null ;
377399
378- if ( ( propInfo . GetMethod ? . IsStatic != true )
379- && ! ( mi is DynamicColumnInfo )
400+ if ( ( propInfo . GetMethod ? . IsStatic != true )
401+ && ! ( mi is DynamicColumnInfo )
380402 && ! mi . GetCustomAttributes < Sql . ExpressionAttribute > ( ) . Any ( ) )
381403 {
382404 var objExpr = new SqlTransparentExpression ( Expression . Constant ( DefaultValue . GetValue ( type ) , type ) , _mappingSource ? . FindMapping ( propInfo ) ) ;
@@ -397,9 +419,34 @@ private Sql.ExpressionAttribute GetDbFunctionFromProperty(Type type, PropertyInf
397419
398420 private static EFCoreExpressionAttribute ConvertToExpressionAttribute ( MemberInfo memberInfo , Expression newExpression , Expression [ ] parameters )
399421 {
400- string PrepareExpressionText ( Expression expr )
422+ string PrepareExpressionText ( Expression ? expr )
401423 {
402- var idx = Array . IndexOf ( parameters , expr ) ;
424+ var idx = - 1 ;
425+
426+ for ( var index = 0 ; index < parameters . Length ; index ++ )
427+ {
428+ var param = parameters [ index ] ;
429+ var found = ReferenceEquals ( expr , param ) ;
430+ if ( ! found )
431+ {
432+ if ( param is SqlTransparentExpression transparent )
433+ {
434+ if ( transparent . Expression is ConstantExpression constantExpr &&
435+ expr is SqlConstantExpression sqlConstantExpr )
436+ {
437+ //found = sqlConstantExpr.Value.Equals(constantExpr.Value);
438+ found = true ;
439+ }
440+ }
441+ }
442+
443+ if ( found )
444+ {
445+ idx = index ;
446+ break ;
447+ }
448+ }
449+
403450 if ( idx >= 0 )
404451 return $ "{{{idx}}}";
405452
@@ -429,18 +476,63 @@ string PrepareExpressionText(Expression expr)
429476 return text ;
430477 }
431478
432- if ( newExpression . GetType ( ) . GetProperty ( "Left" ) != null &&
433- newExpression . GetType ( ) . GetProperty ( "Right" ) != null &&
434- newExpression . GetType ( ) . GetProperty ( "Operator" ) != null )
479+ if ( newExpression . GetType ( ) . Name == "PostgresBinaryExpression" )
435480 {
436- // Handling NpgSql's CustomBinaryExpression
481+ // Handling NpgSql's PostgresBinaryExpression
437482
438- var left = newExpression . GetType ( ) . GetProperty ( "Left" ) ? . GetValue ( newExpression ) as Expression ;
483+ var left = newExpression . GetType ( ) . GetProperty ( "Left" ) ? . GetValue ( newExpression ) as Expression ;
439484 var right = newExpression . GetType ( ) . GetProperty ( "Right" ) ? . GetValue ( newExpression ) as Expression ;
440485
441- var operand = newExpression . GetType ( ) . GetProperty ( "Operator" ) ? . GetValue ( newExpression ) as string ;
486+ var operand = newExpression . GetType ( ) . GetProperty ( "OperatorType" ) ? . GetValue ( newExpression ) . ToString ( ) ;
487+
488+ var operandExpr = operand ;
489+
490+ operandExpr = operand switch
491+ {
492+ "Contains"
493+ when left ! . Type . Name == "NpgsqlInetTypeMapping" ||
494+ left . Type . Name == "NpgsqlCidrTypeMapping"
495+ => ">>" ,
496+ "ContainedBy"
497+ when left ! . Type . Name == "NpgsqlInetTypeMapping" ||
498+ left . Type . Name == "NpgsqlCidrTypeMapping"
499+ => "<<" ,
500+ "Contains" => "@>" ,
501+ "ContainedBy" => "<@" ,
502+ "Overlaps" => "&&" ,
503+ "AtTimeZone" => "AT TIME ZONE" ,
504+ "NetworkContainedByOrEqual" => "<<=" ,
505+ "NetworkContainsOrEqual" => ">>=" ,
506+ "NetworkContainsOrContainedBy" => "&&" ,
507+ "RangeIsStrictlyLeftOf" => "<<" ,
508+ "RangeIsStrictlyRightOf" => ">>" ,
509+ "RangeDoesNotExtendRightOf" => "&<" ,
510+ "RangeDoesNotExtendLeftOf" => "&>" ,
511+ "RangeIsAdjacentTo" => "-|-" ,
512+ "RangeUnion" => "+" ,
513+ "RangeIntersect" => "*" ,
514+ "RangeExcept" => "-" ,
515+ "TextSearchMatch" => "@@" ,
516+ "TextSearchAnd" => "&&" ,
517+ "TextSearchOr" => "||" ,
518+ "JsonExists" => "?" ,
519+ "JsonExistsAny" => "?|" ,
520+ "JsonExistsAll" => "?&" ,
521+ _ => throw new InvalidOperationException (
522+ $ "Unknown PostgresBinaryExpression.OperatorType: '{ operand } '")
523+ } ;
524+
525+ switch ( operand )
526+ {
527+ case "Contains" :
528+ operandExpr = "@>" ; break ;
529+ case "ContainedBy" :
530+ operandExpr = "<@" ; break ;
531+ case "Overlaps" :
532+ operandExpr = "&&" ; break ;
533+ }
442534
443- var text = $ "{ PrepareExpressionText ( left ) } { operand } { PrepareExpressionText ( right ) } ";
535+ var text = $ "{ PrepareExpressionText ( left ) } { operandExpr } { PrepareExpressionText ( right ) } ";
444536
445537 return text ;
446538 }
@@ -464,7 +556,7 @@ private static Expression UnwrapConverted(Expression expr)
464556 if ( expr is SqlFunctionExpression func )
465557 {
466558 if ( string . Equals ( func . Name , "COALESCE" , StringComparison . InvariantCultureIgnoreCase ) &&
467- func . Arguments . Count == 2 && func . Arguments [ 1 ] . NodeType == ExpressionType . Default )
559+ func . Arguments . Count == 2 && func . Arguments [ 1 ] . NodeType == ExpressionType . Extension )
468560 return UnwrapConverted ( func . Arguments [ 0 ] ) ;
469561 }
470562
0 commit comments