Skip to content
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

Add Linq parameter type detection #2365

Merged
merged 11 commits into from
Jul 14, 2020

Conversation

maca88
Copy link
Contributor

@maca88 maca88 commented Apr 27, 2020

This is a continuation of #2335 where the code was extracted from #2079. The main purpose of this PR is to gain the ability to have parameter types calculated before rewriting the query model, which we can use when building the HQL tree. Today parameter types are calculated by HQL logic which is unable to correctly calculate types is certain cases (Example: mod function discussed here).


// When MappedAs is used we have to put all sql types information in the key in order to
// distinct when different precisions/sizes are used.
if (_sessionFactory != null && value is IType type)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this PR ExpressionKeyVisitor generates different keys when MappedAs type is changed in order to avoid using the same query plan as now parameter types are always retrieved from the ParameterMetadata.

if (expression.Value == null)
type = NHibernateUtil.GuessType(expression.Type);

// Constant characters should be sent as strings
if (expression.Type == typeof(char))
// TODO 6.0: Remove
if (_queryVariables == null && expression.Type == typeof(char))
{
value = value.ToString();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This to me looks as a workaroud to fix CharIndexFunction and CharIndexOffsetNegativeFunction tests on Sql Server and Sql CE databases. Instead of converting it to string, this PR set the correct parameter size for drivers that fail without it.


namespace NHibernate.Util
{
internal static class ParameterHelper
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The methods were extracted from AbstractQueryImpl in order to be used by ConstantTypeLocator.

@maca88 maca88 changed the title Add Linq parameter type detection WIP - Add Linq parameter type detection Apr 27, 2020
@maca88 maca88 changed the title WIP - Add Linq parameter type detection Add Linq parameter type detection May 9, 2020
@fredericDelaporte
Copy link
Member

There is a failing new test.

@gliljas
Copy link
Member

gliljas commented May 10, 2020

Interesting. While developing the NodaTime integration I came upon a case where a type (DatePeriod) implements IEnumerable. It works just fine in terms of persistence, but when querying, a DatePeriod parameter will be added using SetParameterList, which falls apart completely. It's not a list. It's a composite type. The "implements IEnumerable but is not a string" check is just a bit too naïve, but given its context, it's the best that can be done.

Will this PR or its siblings open up a way for this to be remedied?

@maca88
Copy link
Contributor Author

maca88 commented May 11, 2020

Will this PR or its siblings open up a way for this to be remedied?

Originally not, but with the last commit it will no longer call SetParameterList for such types. SetParameterList method is only used for IN operator, which will only be generated when using Contains method in a linq expression. So instead of checking "is IEnumerable but is not a string" now checks for Contains method.

@maca88
Copy link
Contributor Author

maca88 commented May 16, 2020

Rebased.

@fredericDelaporte fredericDelaporte added this to the 5.3 milestone May 17, 2020
@hazzik hazzik self-requested a review May 19, 2020 11:49
@hazzik
Copy link
Member

hazzik commented May 19, 2020

Please hold off merging till weekend. I want to review this.

@gliljas
Copy link
Member

gliljas commented May 19, 2020

By pure coincidence, I'm creating something very similar in my NodaTime project (required to prevent ambiguous Linq-to-Hql processes). I wouldn't mind using this instead, but it's internal and I may need to avoid taking the shortcut of just returning the first candidate type when there's a coalesce or a conditional.

@maca88
Copy link
Contributor Author

maca88 commented May 19, 2020

I wouldn't mind using this instead, but it's internal and I may need to avoid taking the shortcut of just returning the first candidate type when there's a coalesce or a conditional.

I am not sure if we should make ExpressionsHelper.TryGetMappedType public as I think that in the future we should get rid of it and instead introduce custom expressions like NhPropertyExpression, NhCaseExpression... that would have the information of the mapped type and persister/component type. These expressions would replace expressions like MemberExpression and ConditionalExpression and be available to all rewriters including the one provided by the IQueryModelRewriterFactory interface.

@maca88
Copy link
Contributor Author

maca88 commented May 19, 2020

Rebased due to conflict with #2387.

@gliljas
Copy link
Member

gliljas commented May 19, 2020

I couldn't agree more. Something that carries mapping metadata within the expression tree (which doesn't have to be Linq based. It could cause confusion). Hibernate is working on the Semantic Query Model approach. I'm not sure how that will turn out, but the idea seems right. Preferably, the SQL would also be expressed as a visitable tree.

@fredericDelaporte fredericDelaporte mentioned this pull request Jun 21, 2020
@fredericDelaporte
Copy link
Member

Rebased for resolving a conflict.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants