-
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
The data types varchar and nvarchar are incompatible in the '^' operator #35093
Comments
Confirmed regression from 8.0 to 9.0; the new boolean XOR logic likely needs to be applied only when the store type is bit (whereas here we have a value converter). For the following query with a value-converted enum, we now generate incorrect SQL with XOR logic (with a regular non-converted string the SQL is OK): _ = await context.Orders
.Select(order => new { Paid = order.State == OrderState.Paid })
// The following is OK (non-value-converted string)
// .Select(order => new { IsNameFoo = order.Name == "Foo" })
.ToListAsync(); 9.0 SQL: SELECT ~CAST([o].[State] ^ N'Paid' AS bit) AS [Paid]
FROM [Orders] AS [o] 8.0 SQL: SELECT CASE
WHEN [o].[State] = N'Paid' THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [Paid]
FROM [Orders] AS [o] Full reproawait using var context = new BlogContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
_ = await context.Orders
.Select(order => new { Paid = order.State == OrderState.Paid })
// The following is OK (non-value-converted string)
// .Select(order => new { IsNameFoo = order.Name == "Foo" })
.ToListAsync();
public class BlogContext : DbContext
{
public DbSet<Order> Orders { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer("Server=localhost;Database=test;User=SA;Password=Abcd5678;Connect Timeout=60;ConnectRetryCount=0;Encrypt=false")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>().Property(o => o.State).HasConversion<OrderStateConverter>();
}
private class OrderStateConverter() : ValueConverter<OrderState, string>(
os => os.ToString(),
s => Enum.Parse<OrderState>(s));
}
public class Order
{
public int Id { get; set; }
public OrderState State { get; set; }
public string Name { get; set; }
}
public enum OrderState { Unpaid, Paid } /cc @ranma42 - let me know if this is something you want to take a look at (and have time), as you worked on the original change. |
I will try and tackle this next weekend (aka it's unlikely I will have a PR ready before next week). (the same issue is likely also affecting the |
@roji @ranma42 integer data types are fine as well https://learn.microsoft.com/en-us/sql/t-sql/language-elements/bitwise-exclusive-or-transact-sql?view=sql-server-ver16 |
@ChrisJollyAU they are fine in that they support the operators (^ and ~), but they might not match the expected Boolean semantics. |
The transformation of equality/in-equality in a (negated) XOR is only possible when the expressions are BIT or integer types on the SQL side (i.e. taking value conversion into account). Similarly, the Boolean negation `NOT` can be implemented as `~` only if the underlying expression is a BIT. Fixes dotnet#35093.
The transformation of equality/in-equality in a (negated) XOR is only possible when the expressions are BIT or integer types on the SQL side (i.e. taking value conversion into account). Similarly, the Boolean negation `NOT` can be implemented as `~` only if the underlying expression is a BIT. Fixes dotnet#35093.
The transformation of equality/in-equality in a (negated) XOR is only possible when the expressions are BIT or integer types on the SQL side (i.e. taking value conversion into account). Similarly, the Boolean negation `NOT` can be implemented as `~` only if the underlying expression is a BIT. Fixes dotnet#35093.
Is there a workaround or a setting that will change this default behavior? All of the enums that we use are stored as strings in the DB for readability. Any query we run in the application that filters by/compares equality of an enum now fails with .Net 9. For example, the query below now fails (edited for brevity):
To bypass the error, I have to modify the query like so (adding .ToString() to each enum):
If there is no workaround, I'll be required to modify hundreds of queries that compare enums, and since the compiler provides no warning of this issue, if I miss a query among the hundreds, my users will get runtime errors. Any help would be appreciated! |
The transformation of equality/in-equality in a (negated) XOR is only possible when the expressions are BIT or integer types on the SQL side (i.e. taking value conversion into account). Similarly, the Boolean negation `NOT` can be implemented as `~` only if the underlying expression is a BIT. Fixes dotnet#35093.
The transformation of equality/in-equality in a (negated) XOR is only possible when the expressions are BIT or integer types on the SQL side (i.e. taking value conversion into account). Similarly, the Boolean negation `NOT` can be implemented as `~` only if the underlying expression is a BIT. Fixes dotnet#35093.
Projection to Boolean of Equals comparator of a Enum property (that has custom ValueConverter to string) with one of possibles values of Enum translates to SQL with the new XOR ('^') operator implementation, causing 'The data types varchar and nvarchar are incompatible in the '^' operator'.
Translate to SQL as
EF Core version: 9.0.0
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 8.0
Operating system: Windows 11 10.0.22631
IDE: Visual Studio 2022 17.11.6
The text was updated successfully, but these errors were encountered: