Skip to content

Proper support for IN clause for composite values in Criteria #2158

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

Merged
merged 9 commits into from
Apr 21, 2020

Conversation

bahusoid
Copy link
Member

@bahusoid bahusoid commented May 15, 2019

Ported latest version of hibernate InExpression. As NHibernate version generates completely incorrect SQL for composite keys.

@bahusoid bahusoid force-pushed the InClause branch 2 times, most recently from 2abfeb9 to f5495f3 Compare May 16, 2019 12:27
@bahusoid bahusoid changed the title WIP Support IN clause for composite properties Proper support for IN clause for composite values in Criteria May 16, 2019
@hazzik
Copy link
Member

hazzik commented Sep 12, 2019

@bahusoid I think you do not gain much from substituting "bogus" parameters because you have more string manipulations. I think it would be clearer (and probably more efficient) to split this code into 3 branches:

  1. One column: super simple col in (@...) statement.
  2. Multiple columns:
    2a. When dialect supports multi-column IN statement.
    2b. When dialect does not support multi-column IN statement.

@bahusoid
Copy link
Member Author

I think you do not gain much from substituting "bogus" parameters

I'm not trying to gain anything. I need to split SQL template generation and parameters generation. This
is due to NHibernate specific parameter backtrack functionality so you have to provide parameters with typed value specified right away sqlString.Add(criteriaQuery.NewQueryParameter(typedValue) .

This bogus parameter allows me to separate template generation and parameters generation routines.

@bahusoid
Copy link
Member Author

bahusoid commented Sep 12, 2019

I think it would be clearer (and probably more efficient) to split this code into 3 branches:

I need to use functions like SqlStringHelper.Repeat and SqlStringHelper.Join to effectively generate SQL and "bogus" parameter allows it. Otherwise as I explained above I need to inject real parameters right in to generation process (so it won't be clearer for sure)

@hazzik So please clarify how suggested splitting allows me to effectively generate SQL without bogus parameter.

Current splitting (the same as in hibernate):

  1. When dialect supports multi-column IN statement or it's one column;
  2. When dialect does not support multi-column IN statement.

Suggested by you additional splitting really won't change much.

@hazzik
Copy link
Member

hazzik commented Sep 12, 2019

I don't understand what's wrong with putting actual parameters into the query.

I've got following snippet:

/// the beginning of the method is skipped
	var parametersList = GetParameterTypedValues(criteria, criteriaQuery)
	    .Select(tv => criteriaQuery.NewQueryParameter(tv).ToArray())
	    .ToList();

	return GetSqlString(criteriaQuery, columns, parametersList);
}

private static SqlString GetSqlString(
	ICriteriaQuery criteriaQuery,
	SqlString[] columns,
	List<Parameter[]> parametersList)
{
	if (columns.Length == 1)
	{
		//single column: col1 in (?, ?)
		return new SqlString(
			columns[0],
			" in (",
			SqlStringHelper.Join(", ", parametersList.Select(p => p.Single())),
			")"
		);
	}

	if (criteriaQuery.Factory.Dialect.SupportsRowValueConstructorSyntaxInInList)
	{
		//multi column:  (col1, col2) in ((?, ?), (?, ?))
		return new SqlString(
			"(",
			SqlStringHelper.Join(", ", columns),
			") in ((",
			SqlStringHelper.Join("), (", parametersList.Select(p => SqlStringHelper.Join(", ", p))),
			"))"
		);
	}
	
	//((col1 = ? and col2 = ?) or (col1 = ? and col2 = ?))

	var objects = parametersList.Select(
		parameters => new SqlString(
			"(",
			SqlStringHelper.Join(
				" and ", columns.Zip(parameters, (c, p) => new SqlString(c, " = ", p))),
			")"));

	return new SqlString(
		"(",
		SqlStringHelper.Join(" or ", objects),
		")"
	);
}

First two can be collapsed together, but I didn't like it.

@bahusoid
Copy link
Member Author

bahusoid commented Sep 13, 2019

I don't understand what's wrong with putting actual parameters into the query

  1. Main reason. I don't want to rewrite logic that's already present in hibernate. I practically copy-pasted it from hibernate converting values to SqlString ( and still would prefer to keep it that way);

  2. Your logic doesn't look cleaner to me. IMHO for external eyes both implementations need the same amount of time to understand it;

  3. Your current snippet doesn't work with ClassWithCompositeIdFixture.QueryOverInClause test. It generates wrong SQL in first case ((this_.string_, this_.short_, this_.date_) in ((@p0), (@p1)) and throw exception in second (that's SupportsRowValueConstructorSyntaxInInList == false).

@hazzik
Copy link
Member

hazzik commented Sep 13, 2019

Your current snippet doesn't work with

Yes, I did not run tests. It has come from wrong-ish assumption on how GetParameterTypedValues work.

@bahusoid bahusoid force-pushed the InClause branch 2 times, most recently from 53f74a8 to ff70a94 Compare September 13, 2019 07:03
bahusoid and others added 2 commits April 19, 2020 22:34
Co-Authored-By: Frédéric Delaporte <12201973+fredericDelaporte@users.noreply.github.com>
@hazzik
Copy link
Member

hazzik commented Apr 21, 2020

I was reluctant to approve it because there were code changes which I think could be improved. I tried to do that, but never got time to finish.

@fredericDelaporte

This comment has been minimized.

@bahusoid

This comment has been minimized.

@hazzik hazzik changed the title Proper support for IN clause for composite values in Criteria Proper support for IN clause for composite values in Criteria May 25, 2020
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.

3 participants