question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Query with Negative multiple AND's generating query with OR (SqlServer)

See original GitHub issue

If I have an query .Where(x => !(x.Name == "Adam" && x.Type == "Person")) I expect the query generated as NOT (Name = 'Adam' AND Type = 'Person') but during test this query is generated as Name <> 'Adam' OR Type <> 'Person' that make the query to exclude wrong result.

If I write the query as .Where(x => x.Name != "Adam" && x.Type != "Person") or .Where(x => !(x.Name == "Adam") && !(x.Type == "Person")) the query is translated correctly.

public class TestRunner
    {
        private readonly Db _db;

        public TestRunner(Db db)
        {
            _db = db;
        }

        public void Run()
        {
            _db.TableA.Where(x => !(x.Name == "Adam" && x.Type == "Person")).ToList();
        }
    }

    public class TableA
    {
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }
        public string Type { get; set; }
    }

    public class Db : DbContext
    {
        public Db()
        {
        }

        public Db(DbContextOptions options) : base(options)
        {
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            optionsBuilder.UseSqlServer("Data Source=(local); Integrated Security=True; Initial Catalog=BugTest;MultipleActiveResultSets=True");
        }

        public DbSet<TableA> TableA { get; set; }
    }

Full example of running application exists here https://github.com/Tasteful/bugs/tree/efcore-where-not-problem

Include verbose output

From console log where we can see that the select expression is build correctly and the generated SQL is with OR instead of AND.

dbug: Microsoft.EntityFrameworkCore.Query[10107]
      Generated query execution expression:
      'queryContext => new SingleQueryingEnumerable<TableA>(
          (RelationalQueryContext)queryContext,
          RelationalCommandCache.SelectExpression(
              Projection Mapping:
                  EmptyProjectionMember -> Dictionary<IProperty, int> { [Property: TableA.Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd, 0], [Property: TableA.Name (string), 1], [Property: TableA.Type (string), 2], }
              SELECT t.Id, t.Name, t.Type
              FROM TableA AS t
              WHERE Not((t.Name == N'Adam') && (t.Type == N'Person'))),
          Func<QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator, TableA>,
          BugTest.Db,
          False,
          False
      )'

info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT [t].[Id], [t].[Name], [t].[Type]
      FROM [TableA] AS [t]
      WHERE (([t].[Name] <> N'Adam') OR [t].[Name] IS NULL) OR (([t].[Type] <> N'Person') OR [t].[Type] IS NULL)

Include provider and version information

EF Core version: 5.0.5 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: .NET 5.0 Operating system: Windows 10 IDE: Visual Studio 2019 16.9.4

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:9 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
Tastefulcommented, Apr 15, 2021

This is fundamentally wrong assumption.

So where are the wrong results?

I have test now with Linq over a regular List<> and directly with TSQL and can see that my assumption was wrong about how && is working. Have never recognize that before and probably that is because I try to write queries that not using NOT. Then the result will be what I expect anyway.

Thanks for clarifying.

0reactions
maumarcommented, Apr 15, 2021

@Tasteful on top of what @roji and @smitpatel have already said, you can use Linq to Objects, completely circumventing EF query pipeline and see that it produces the same result:

_db.TableA.ToList().Where(x => !(x.Name == "Adam" && x.Type == "Person")).ToList();

Perhaps, your example can be demonstrated easier if you have 4 elements in your database:

1.) Name: Adam, Type: Person
2.) Name: Ben, Type: Person
3.) Name: Fabrikam, Type: Company
4.) Name: Adam, Type: Company // <-- added element

The query which is not negated:

Expression<Func<TableA, bool>> w = x => x.Name == "Adam" && x.Type == "Person";

will return true if entity is simultaneously named Adam and is a person (so returning the first element only). Negation of that MUST return everything else, so it should return elements 2, 3, 4.

This can be done by returning elements whos name is not adam OR who’s type is not person - which is what EF translates the negation to.

They way that you thought the negation should be translated (if I understood correctly), it should only return 3rd element (something that is not named Adam, and is also not a Person). This leads to contradiction, because all 4 elements should be returned if you combine the first query and its negated version, but you only get 2 of them.

If you want to go around de Morgan laws, you need to write the query without parentheses in the way that you want them to behave, rather than putting negation around and rely on EF to optimize it for you.

From EF perspective this issue is by design - we follow all the rules of 2-value logic correctly here.

Read more comments on GitHub >

github_iconTop Results From Across the Web

SQL query, negative and positive values matching and ...
I have a task at hand to identify negative values in a table and find a matching positive value in same table/column, then...
Read more >
Troubleshoot a query that shows different performance ...
This article provides troubleshooting steps for a performance issue where a query runs slower on one server than on another server. Symptoms.
Read more >
Query Optimization Techniques in SQL Server: Parameter ...
In this blog post we will walk you through one of the SQL Query Optimization Techniques in SQL Server - Parameter Sniffing.
Read more >
SELECT all negative values, that have a positive value
Hello, I need to identify in SQL server table all entries with a negative value, that have a positive value. How I can...
Read more >
SQL reference for query expressions used in ArcGIS
SQL expression syntax​​ A SQL expression contains a combination of one or more values, operators, and SQL functions that can be used to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found