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

Query: Contains method on client list of nullable guid/int fails to translate to server #7922

Closed
winterlimelight opened this issue Mar 17, 2017 · 4 comments
Assignees
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@winterlimelight
Copy link

When a nullable Guid and a non-nullable Guid are compared using the Contains() method I get a log message: "could not be translated and will be evaluated locally". Unfortunately this is then downloading a big table to perform the comparison causing a performance problem. This occurs whether the nullable is an argument to or the caller of .Contains() as will be shown in the four cases below.

This may be related to #7616

Steps to reproduce

Here is a cut-down version of the entity:

public class Skill
{
	public Guid SkillId { get; set; }
	public Guid? PrimarySkillId { get; set; }

	// Navigation (self-join)
	public Skill PrimarySkill {get;set;}
}

Here are the four cases with resulting log messages and MySQL

//nullable Guid list, nullable field - works
List<Guid?> primarySkills = ...;
var outerQuery = dc.Skills.Where(s => primarySkills.Contains(s.PrimarySkillId));
var result = await outerQuery.ToListAsync();

SELECT s.SkillId, s.Name, s.PrimarySkillId, s.Source, s.SourceId
FROM Skills AS s
WHERE s.PrimarySkillId IN (...)

//nullable Guid list, non-nullable field - fails
List<Guid?> primarySkills = ...;
var outerQuery = dc.Skills.Where(s => primarySkills.Contains(s.SkillId) );
var result = await outerQuery.ToListAsync();

The LINQ expression '{__primarySkills_0 => Contains(Convert([s].SkillId))}' could not be translated and will be evaluated locally.
The LINQ expression 'Contains(Convert([s].SkillId))' could not be translated and will be evaluated locally.
SELECT s.SkillId, s.Name, s.PrimarySkillId, s.Source, s.SourceId
FROM Skills AS s

and the inverse is true:

//non-nullable Guid list, non-nullable field - works
List<Guid> primarySkills = ...; 
var outerQuery = dc.Skills.Where(s => primarySkills.Contains(s.SkillId));
var result = await outerQuery.ToListAsync();

SELECT s.SkillId, s.Name, s.PrimarySkillId, s.Source, s.SourceId
FROM Skills AS s
WHERE s.SkillId IN (...)

//non-nullable Guid, nullable field - fails
List<Guid> primarySkills = ...;
var outerQuery = dc.Skills.Where(s => /*primarySkills.Contains(s.SkillId) ||*/ s.PrimarySkillId != null && primarySkills.Contains(s.PrimarySkillId.Value));
var result = await outerQuery.ToListAsync();

The LINQ expression '{__primarySkills_0 => Contains(Convert([s].PrimarySkillId))}' could not be translated and will be evaluated locally.
The LINQ expression 'Contains(Convert([s].PrimarySkillId))' could not be translated and will be evaluated locally.
SELECT s.SkillId, s.Name, s.PrimarySkillId, s.Source, s.SourceId
FROM Skills AS s
WHERE s.PrimarySkillId IS NOT NULL

Unfortunately what I need to do is compare to both fields at once - so I can't get away from the nullable problem so easily. Ideally what I want is:

.Where(s => primarySkills.Contains(s.PrimarySkillId ?? s.SkillId));

Further technical details

These are my relevant project references:
PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.1"
PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.1"
PackageReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.1.0-preview4-final"
PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="1.1.0-"
PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Design" Version="1.1.0-
"

Workaround

Having written all this up I realised a stupidly simple workaround, and this works fine, but I'm thinking this is still something that'd be useful for you to know about.

List<Guid> primarySkills = ...;
List<Guid?> primarySkillsNullable = primarySkills.Cast<Guid?>().ToList();
var outerQuery = dc.Skills.Where(s => 
	primarySkills.Contains(s.SkillId) || primarySkillsNullable.Contains(s.PrimarySkillId));

SELECT s.SkillId, s.Name, s.PrimarySkillId, s.Source, s.SourceId
FROM Skills AS s
WHERE s.SkillId IN (...) OR s.PrimarySkillId IN (...)

@AnilCAE
Copy link

AnilCAE commented Mar 17, 2017

This seems this also same when we use contains with List<int?>?

@TPJ11
Copy link

TPJ11 commented Mar 17, 2017

@pmiddleton
Copy link
Contributor

pmiddleton commented Mar 21, 2017

I just took a look into this issue, and it can be closed.

I can confirm the issue is happening on 1.1.1, but it has already been resolved in the dev branch.

@ajcvickers @smitpatel - Let me know if you want me to add a unit test for this issue to test for regressions.

@ajcvickers
Copy link
Contributor

@pmiddleton PRs with additional tests are always welcome. 😸

@smitpatel smitpatel added type-bug closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. and removed type-investigation labels Mar 22, 2017
@smitpatel smitpatel changed the title Contains() method with nullable Guids translating locally. Contains method on client list of nullable guid/int fails to translate to server Mar 22, 2017
@ajcvickers ajcvickers changed the title Contains method on client list of nullable guid/int fails to translate to server Query: Contains method on client list of nullable guid/int fails to translate to server May 9, 2017
@divega divega added closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. and removed closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. labels May 10, 2017
@ajcvickers ajcvickers modified the milestones: 2.0.0-preview1, 2.0.0 Oct 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

7 participants