@@ -386,7 +386,14 @@ public int Execute<T>(IQueryable<T> query, Expression<Func<T, T>> updateFactory)
386386 {
387387 Executing ( command ) ;
388388 }
389+ #if NETSTANDARD2_0
390+ if ( command . GetType ( ) . Name . Contains ( "Oracle" ) )
391+ {
392+ var bindByNameProperty = command . GetType ( ) . GetProperty ( "BindByName" ) ?? command . GetType ( ) . GetProperty ( "PassParametersByName" ) ;
389393
394+ bindByNameProperty . SetValue ( command , true , null ) ;
395+ }
396+ #endif
390397 var rowAffecteds = command . ExecuteNonQuery ( ) ;
391398 return rowAffecteds ;
392399 }
@@ -701,6 +708,8 @@ public DbCommand CreateCommand(IQueryable query, IEntityType entity, List<Tuple<
701708 bool isMySql = false ;
702709 bool isMySqlPomelo = false ;
703710 bool isSQLite = false ;
711+ bool isOracle = false ;
712+ bool isDevOracle = false ;
704713
705714 if ( assemblyName == "Microsoft.EntityFrameworkCore.SqlServer" )
706715 {
@@ -738,6 +747,22 @@ public DbCommand CreateCommand(IQueryable query, IEntityType entity, List<Tuple<
738747 dynamicProviderEntityType = typeof ( RelationalMetadataExtensions ) . GetMethod ( "Relational" , new [ ] { typeof ( IEntityType ) } ) ;
739748 dynamicProviderProperty = typeof ( RelationalMetadataExtensions ) . GetMethod ( "Relational" , new [ ] { typeof ( IProperty ) } ) ;
740749 }
750+ else if ( assemblyName == "Oracle.EntityFrameworkCore" )
751+ {
752+ isOracle = true ;
753+
754+ // CHANGE all for this one?
755+ dynamicProviderEntityType = typeof ( RelationalMetadataExtensions ) . GetMethod ( "Relational" , new [ ] { typeof ( IEntityType ) } ) ;
756+ dynamicProviderProperty = typeof ( RelationalMetadataExtensions ) . GetMethod ( "Relational" , new [ ] { typeof ( IProperty ) } ) ;
757+ }
758+ else if ( assemblyName == "Devart.Data.Oracle.Entity.EFCore" )
759+ {
760+ isDevOracle = true ;
761+
762+ // CHANGE all for this one?
763+ dynamicProviderEntityType = typeof ( RelationalMetadataExtensions ) . GetMethod ( "Relational" , new [ ] { typeof ( IEntityType ) } ) ;
764+ dynamicProviderProperty = typeof ( RelationalMetadataExtensions ) . GetMethod ( "Relational" , new [ ] { typeof ( IProperty ) } ) ;
765+ }
741766 else
742767 {
743768 throw new Exception ( string . Format ( ExceptionMessage . Unsupported_Provider , assemblyName ) ) ;
@@ -865,6 +890,26 @@ public DbCommand CreateCommand(IQueryable query, IEntityType entity, List<Tuple<
865890 // GET primary key join
866891 primaryKeys = string . Join ( Environment . NewLine + "AND " , columnKeys . Select ( x => string . Concat ( tableName + ".\" " , x , "\" = B.\" " , x , "\" " ) ) ) ;
867892 }
893+ else if ( isOracle || isDevOracle )
894+ {
895+ var sqlServer = ( IRelationalEntityTypeAnnotations ) dynamicProviderEntityType. Invoke ( null , new [ ] { entity } ) ;
896+
897+ // GET mapping
898+ tableName = string . IsNullOrEmpty ( sqlServer . Schema ) ? string . Concat ( "\" " , sqlServer . TableName , "\" " ) : string . Concat ( "\" " , sqlServer . Schema , "\" .\" " , sqlServer . TableName , "\" " ) ;
899+
900+ // GET keys mappings
901+ var columnKeys = new List < string > ( ) ;
902+ foreach ( var propertyKey in entity. GetKeys ( ) . ToList ( ) [ 0 ] . Properties )
903+ {
904+ var mappingProperty = dynamicProviderProperty. Invoke( null , new [ ] { propertyKey } ) ;
905+
906+ var columnNameProperty = mappingProperty. GetType( ) . GetProperty( "ColumnName" , BindingFlags . Public | BindingFlags . Instance ) ;
907+ columnKeys . Add ( ( string ) columnNameProperty . GetValue ( mappingProperty ) ) ;
908+ }
909+
910+ // GET primary key join
911+ primaryKeys = string . Join ( Environment . NewLine + "AND " , columnKeys . Select ( x => string . Concat ( tableName + ".\" " , x , "\" = B.\" " , x , "\" " ) ) ) ;
912+ }
868913
869914 // GET command text template
870915 var commandTextTemplate =
@@ -874,11 +919,10 @@ public DbCommand CreateCommand(IQueryable query, IEntityType entity, List<Tuple<
874919 CommandTextWhileDelayTemplate :
875920 CommandTextWhileTemplate :
876921#endif
877- isPostgreSQL ? CommandTextTemplate_PostgreSQL :
878- isMySql || isMySqlPomelo ?
879- CommandTextTemplate_MySQL :
880- isSQLite ?
881- CommandTextTemplate_SQLite :
922+ isPostgreSQL ? CommandTextTemplate_PostgreSQL :
923+ isMySql || isMySqlPomelo ? CommandTextTemplate_MySQL :
924+ isSQLite ? CommandTextTemplate_SQLite :
925+ ( isOracle || isDevOracle ) ? CommandTextOracleTemplate2 :
882926 CommandTextTemplate ;
883927
884928 // GET inner query
@@ -894,6 +938,7 @@ public DbCommand CreateCommand(IQueryable query, IEntityType entity, List<Tuple<
894938
895939 // GET updateSetValues
896940 var setValues = "" ;
941+ var setColumns = "" ;
897942
898943 if ( isSqlServer )
899944 {
@@ -911,11 +956,17 @@ public DbCommand CreateCommand(IQueryable query, IEntityType entity, List<Tuple<
911956 {
912957 setValues = string . Join ( "," + Environment . NewLine , values . Select ( ( x , i ) => x . Item2 is ConstantExpression ? string . Concat ( "\" " , x . Item1 , "\" = " , ( ( ConstantExpression ) x . Item2 ) . Value ) : string . Concat ( "\" " , x . Item1 , "\" = @zzz_BatchUpdate_" , i ) ) ) ;
913958 }
959+ else if ( isOracle || isDevOracle )
960+ {
961+ setColumns = string . Join ( "," + Environment . NewLine , values . Select ( ( x ) => string . Concat ( EscapeName ( x . Item1 , isMySql , true , isPostgreSQL , false ) ) ) ) ;
962+ setValues = string . Join ( "," + Environment . NewLine , values . Select ( ( x , i ) => x . Item2 is ConstantExpression ? string . Concat ( ( ( ConstantExpression ) x . Item2 ) . Value ) : string . Concat ( ":zzz_BatchUpdate_" , i ) ) ) ;
963+ }
914964
915965 // REPLACE template
916966 commandTextTemplate = commandTextTemplate . Replace ( "{TableName}" , tableName )
917967 . Replace ( "{Select}" , querySelect )
918968 . Replace ( "{PrimaryKeys}" , primaryKeys )
969+ . Replace ( "{setColumn}" , setColumns )
919970 . Replace ( "{SetValue}" , setValues )
920971 . Replace ( "{Hint}" , UseTableLock ? "WITH ( TABLOCK )" : "" ) ;
921972
@@ -928,6 +979,21 @@ public DbCommand CreateCommand(IQueryable query, IEntityType entity, List<Tuple<
928979 foreach ( var relationalParameter in relationalCommand . Parameters )
929980 {
930981 object parameter;
982+ string name = "";
983+
984+ #if NETSTANDARD2_0
985+ if ( isOracle || isDevOracle )
986+ {
987+ name = ( ( dynamic ) relationalParameter ) . Name ;
988+ }
989+ else
990+ {
991+ #endif
992+ name = relationalParameter . InvariantName ;
993+ #if NETSTANDARD2_0
994+ }
995+ #endif
996+
931997 if ( ! queryContext . ParameterValues . TryGetValue ( relationalParameter . InvariantName , out parameter ) )
932998 {
933999 if ( relationalParameter . InvariantName . StartsWith ( "__ef_filter" ) )
@@ -941,7 +1007,7 @@ public DbCommand CreateCommand(IQueryable query, IEntityType entity, List<Tuple<
9411007 }
9421008
9431009 var param = command. CreateParameter ( ) ;
944- param. CopyFrom ( relationalParameter , parameter ) ;
1010+ param. CopyFrom ( relationalParameter , parameter , name ) ;
9451011
9461012#if ! NETSTANDARD1_3
9471013 if ( isPostgreSQL )
@@ -980,7 +1046,15 @@ public DbCommand CreateCommand(IQueryable query, IEntityType entity, List<Tuple<
9801046 }
9811047
9821048 var parameter = command . CreateParameter ( ) ;
983- parameter. ParameterName = "@zzz_BatchUpdate_" + i;
1049+
1050+ if ( isOracle || isDevOracle )
1051+ {
1052+ parameter . ParameterName = "zzz_BatchUpdate_ " + i;
1053+ }
1054+ else
1055+ {
1056+ parameter. ParameterName = "@zzz_BatchUpdate_" + i;
1057+ }
9841058
9851059 var paramValue = values [ i ] . Item2 ;
9861060 var paramNullValue = paramValue as NullValue ;
@@ -1042,6 +1116,8 @@ public List<Tuple<string, object>> GetInnerValues<T>(IQueryable<T> query, Expres
10421116 bool isMySql = false ;
10431117 bool isMySqlPomelo = false ;
10441118 bool isSQLite = false ;
1119+ bool isOracle = false ;
1120+ bool isDevOracle = false ;
10451121
10461122 if ( assemblyName == "Microsoft.EntityFrameworkCore.SqlServer" )
10471123 {
@@ -1079,6 +1155,22 @@ public List<Tuple<string, object>> GetInnerValues<T>(IQueryable<T> query, Expres
10791155 dynamicProviderEntityType = typeof ( RelationalMetadataExtensions ) . GetMethod ( "Relational" , new [ ] { typeof ( IEntityType ) } ) ;
10801156 dynamicProviderProperty = typeof ( RelationalMetadataExtensions ) . GetMethod ( "Relational" , new [ ] { typeof ( IProperty ) } ) ;
10811157 }
1158+ else if ( assemblyName == "Oracle.EntityFrameworkCore" )
1159+ {
1160+ isOracle = true ;
1161+
1162+ // CHANGE all for this one?
1163+ dynamicProviderEntityType = typeof ( RelationalMetadataExtensions ) . GetMethod ( "Relational" , new [ ] { typeof ( IEntityType ) } ) ;
1164+ dynamicProviderProperty = typeof ( RelationalMetadataExtensions ) . GetMethod ( "Relational" , new [ ] { typeof ( IProperty ) } ) ;
1165+ }
1166+ else if ( assemblyName == "Devart.Data.Oracle.Entity.EFCore" )
1167+ {
1168+ isDevOracle = true ;
1169+
1170+ // CHANGE all for this one?
1171+ dynamicProviderEntityType = typeof ( RelationalMetadataExtensions ) . GetMethod ( "Relational" , new [ ] { typeof ( IEntityType ) } ) ;
1172+ dynamicProviderProperty = typeof ( RelationalMetadataExtensions ) . GetMethod ( "Relational" , new [ ] { typeof ( IProperty ) } ) ;
1173+ }
10821174 else
10831175 {
10841176 throw new Exception ( string . Format ( ExceptionMessage . Unsupported_Provider , assemblyName ) ) ;
@@ -1248,12 +1340,19 @@ public List<Tuple<string, object>> GetInnerValues<T>(IQueryable<T> query, Expres
12481340 "\" Filter6\" " ,
12491341 } ;
12501342
1251- // Before we were replacing only the first value, we might have added an issue here by removing the break.
1343+ var isSelect = valueSql . Contains ( "SELECT" ) ;
12521344 foreach ( var itemReplace in listReplace)
12531345 {
12541346 if ( valueSql . Contains ( itemReplace ) )
12551347 {
1256- valueSql = valueSql. Replace ( itemReplace , "B" ) ;
1348+ valueSql = valueSql . Replace ( itemReplace , "B" ) ;
1349+
1350+ // If the value has a select, we break on the first item to replace found
1351+ // The fix is not perfect, but enough good for now
1352+ if ( isSelect )
1353+ {
1354+ break ;
1355+ }
12571356 }
12581357 }
12591358
0 commit comments