-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Query: Enable translations that generate different SQL depending on a value to be cached #12764
Comments
@MikeDempseyFL - We will need more information on this to effectively understand the issue. You are saying that your design works for 3 out of 5 scenarios. Can you elaborate those scenarios? Further can you also describe what information are you trying to pass on and why you need to look at the expressions specifically? |
Currently, in the translator, if the term is either a constant or a simple column reference we replace it with a new [string] constant expression that includes all required quotes and the suffix.
In VisitStringCompare, if the term is [now] a constant we simply append the value to the SQL rather than calling a visitor. (The visitors would have added the quotes in the wrong place.) If a term is a parameter, or a more complex expression, we call its visitor as usual, but then append the extracted term (in parens) if we have one. So as long as at least one of the terms is either a constant or a simple column reference we will successfully generate the SQL with the required '(CS)' or '(Not CS)' suffixes on both sides of the comparison operator. The issue is that if BOTH terms are complex references, or one is a complex reference and the other is a parameter, we have no way to know what suffix to add. This would require somehow passing the value of the ignoreCase switch to the VisitStringCompare() method. |
I would suggest not doing any processing based on type of Expression because it complicates thing and generally not a good idea since it breaks the ability to evaluate each part of Expression Tree independently. In the meantime, I suggest getting rid of StringCompareExpression totally at provider level. You can add your custom CaseSensitiveStringCompareExpression which contains all the information you need. You can create it from your method call translator and visit it in QueryGen. |
Thanks. |
I derived my own Expression from StringCompareExpression adding one extra field for the IgnoreCase switch. Is it possible to get the value of a parameter from within the Visit methods or is that value not assigned until a later stage? (I saw references to command reuse which would imply that no value is assigned yet.) |
Which |
The |
Of course! The only issue I have now is that since LINQ thinks this ParameterExpression represents a parameter passed to the database - rather than a value that will be used in the visitor to generate the SQL - link will not call the visitor again if this is the only thing that changes before another call. |
@MikeDempseyFL - Can your method on server take parameter as arg (or whatever represents the casing)? If not then perhaps the best place to look for is to avoid parametrization. For user defined methods, we use |
Thanks. I'll look into the ParameterExtractingExpressionVisitor. |
On the surface it looks like I should just derive my own type from ParameterExtractingExpressionVisitor and override the VisitMethodCall() method as follows:
Unfortunately all the fields in this type are private and there are no properties defined on them. Also, I didn't see an interface that appears to be intended for this type in order to hook my derived type into the service collection. |
Another way to solve it would be to set |
Triage: we should make IsCachable protected, but then also consider this case as part of the overall query work for 3.0, so adding a reference to #12795. |
This allows providers to block caching SQL in second level cache Resolves #12764
This allows providers to block caching SQL in second level cache Resolves #12764
@smitpatel let’s either keep this open or create a new issue to try to provide a solution that doesn’t disable caching in the longer term. |
Moving this to 3.0 and linking to #12795 to consider as part of Query3. |
This allows providers to block caching SQL in second level cache Resolves dotnet#12764
@MikeDempseyFL, @smitpatel made IsCachable protected in #12857. I just want to make sure that you were able to understand his suggestion and that you have been able to address this scenario in your provider. We would like to re-purpose this issue to track the possibility of handling this kind of scenario in a way that doesn't disable the ability to cache the SQL translation. |
Yes I think I understand the solution. The IsCachable property is currently initialized to true in GenerateSql() and then the SelectExpression is visited. So I would set IsCachable to false in my VisitTeradataStringCompare() method. This method is in my class that derives from DefaultQuerySqlGenerator. |
@smitpatel to follow up with new issue on parameterization. |
Filed #14507 Trying to update second level cache to account for parameter value too (rather than just nullability), would bring in a lot of complexity along with inconsistency when to consider value and when not to. Rather than playing with second level cache, we should allow providers to control what can be parameterized. While it is true that SQL is only different and may not need a different compilation but at least for now we should try to keep second level cache only related to null semantics on parameters |
The current implementation of the relational StringCompareTranslator only handles the String.Compare(s1, s2) method.
On our database that would be indeterminate since the database session may be set to use case specific, or not specific, comparisons.
I want to force this method to always use case specific comparisons and to also support the String.Compare(s1, s2, ignoreCase) method in our EF provider.
In order to do this it appears that I need to add our own StringCompareTranslator and also add an override for the VisitStringCompare method in our QuerySqlGenerator.
My current design does work for 3 of the 5 possible scenarios but the remaining 2 [less common] cases would require some other way to pass information from the translator to the visitor.
I am currently adding the required text decoration in the translator and using it in the visitor, but I can only decorate constant expressions and simple column references.
If one term is a more complex column reference [e.g. e.name.Substring(1,3) rather than just e.name.] and the other term is either a variable [i.e. a parameter] or another complex column reference then I can't add the required information.
Note that in order to support simple column references I essentially have to 'visit' the column reference in the translator in order to turn it into a constant expression [e.g. "e"."name" (CS)] which kind of bends the rules already.
An example of a case specific comparison between a column reference and a variable would be:
"e"."name" = ? (CS)
Can anyone suggest an alternative way to handle this without jumping through hoops to only partially support the requirement.
Further technical details
EF Core version: 2.1
Database Provider: Teradata
Operating system: Windows 10
IDE: Visual Studio 2017 15.6
The text was updated successfully, but these errors were encountered: