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

Use right hand type mapping for more binary expressions when left is an object #34729

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/EFCore.Relational/Query/SqlExpressionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ private SqlExpression ApplyTypeMappingOnSqlBinary(
case ExpressionType.ExclusiveOr:
{
inferredTypeMapping = typeMapping ?? ExpressionExtensions.InferTypeMapping(left, right);
resultType = inferredTypeMapping?.ClrType ?? left.Type;
resultType = inferredTypeMapping?.ClrType ?? (left.Type != typeof(object) ? left.Type : right.Type);
resultTypeMapping = inferredTypeMapping;
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2283,4 +2283,181 @@ public class CompanyDto : ICompanyDto
}

#endregion

#region 34618

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Not_Null_Contains(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x != null ? x.Id + "" : null).FirstOrDefault(x => x!.Contains("1"));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Not_Null_Contains_Non_Numeric_First_Part(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x != null ? "" + x.Id + "" : null).FirstOrDefault(x => x!.Contains("1"));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Not_Null_EndsWith(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x != null ? x.Id + "" : null).FirstOrDefault(x => x!.EndsWith("1"));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Not_Null_EndsWith_Non_Numeric_First_Part(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x != null ? "" + x.Id + "" : null).FirstOrDefault(x => x!.EndsWith("1"));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Not_Null_Equals(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x != null ? x.Id + "" : null).FirstOrDefault(x => x == "1");
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Not_Null_Equals_Non_Numeric_First_Part(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x != null ? "" + x.Id + "" : null).FirstOrDefault(x => x == "1");
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Not_Null_StartsWith(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x != null ? x.Id + "" : null).FirstOrDefault(x => x!.StartsWith("1"));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Not_Null_StartsWith_Non_Numeric_First_Part(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x != null ? "" + x.Id + "" : null).FirstOrDefault(x => x!.StartsWith("1"));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Null_Contains(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x == null ? null : x.Id + "").FirstOrDefault(x => x!.Contains("1"));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Null_Contains_Non_Numeric_First_Part(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x == null ? null : "" + x.Id + "").FirstOrDefault(x => x!.Contains("1"));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Null_EndsWith(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x == null ? null : x.Id + "").FirstOrDefault(x => x!.EndsWith("1"));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Null_EndsWith_Non_Numeric_First_Part(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x == null ? null : "" + x.Id + "").FirstOrDefault(x => x!.EndsWith("1"));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Null_Equals(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x == null ? null : x.Id + "").FirstOrDefault(x => x == "1");
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Null_Equals_Non_Numeric_First_Part(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x == null ? null : "" + x.Id + "").FirstOrDefault(x => x == "1");
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Null_StartsWith(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x == null ? null : x.Id + "").FirstOrDefault(x => x!.StartsWith("1"));
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Ternary_Null_StartsWith_Non_Numeric_First_Part(bool async)
{
var contextFactory = await InitializeAsync<Context34618>(seed: x => x.SeedAsync());
using var context = contextFactory.CreateContext();
context.Set<Entity34618>().Select(x => x == null ? null : "" + x.Id + "").FirstOrDefault(x => x!.StartsWith("1"));
}

protected class Context34618(DbContextOptions options) : DbContext(options)
{
public DbSet<Entity34618> Entities { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Entity34618>().Property(x => x.Id).ValueGeneratedNever();

public async Task SeedAsync()
{
var e1 = new Entity34618
{
Id = 1,
};

var e2 = new Entity34618
{
Id = 2,
};

AddRange(e1, e2);
await SaveChangesAsync();
}
}

protected class Entity34618
{
public int Id { get; set; }
}

#endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -2405,4 +2405,186 @@ WHEN [c0].[Id] IS NOT NULL THEN [c1].[CountryName]
END = N'COUNTRY'
""");
}

#region 34618

public override async Task Ternary_Not_Null_Contains(bool async)
{
await base.Ternary_Not_Null_Contains(async);

AssertSql(
"""
SELECT TOP(1) CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE CAST([e].[Id] AS nvarchar(max)) + N'' LIKE N'%1%'
""");
}

public override async Task Ternary_Not_Null_Contains_Non_Numeric_First_Part(bool async)
{
await base.Ternary_Not_Null_Contains_Non_Numeric_First_Part(async);

AssertSql("""
SELECT TOP(1) N'' + CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE N'' + CAST([e].[Id] AS nvarchar(max)) + N'' LIKE N'%1%'
""");
}

public override async Task Ternary_Not_Null_EndsWith(bool async)
{
await base.Ternary_Not_Null_EndsWith(async);

AssertSql(
"""
SELECT TOP(1) CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE CAST([e].[Id] AS nvarchar(max)) + N'' LIKE N'%1'
""");
}

public override async Task Ternary_Not_Null_EndsWith_Non_Numeric_First_Part(bool async)
{
await base.Ternary_Not_Null_EndsWith_Non_Numeric_First_Part(async);

AssertSql("""
SELECT TOP(1) N'' + CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE N'' + CAST([e].[Id] AS nvarchar(max)) + N'' LIKE N'%1'
""");
}

public override async Task Ternary_Not_Null_Equals(bool async)
{
await base.Ternary_Not_Null_Equals(async);

AssertSql("""
SELECT TOP(1) CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE CAST([e].[Id] AS nvarchar(max)) + N'' = N'1'
""");
}

public override async Task Ternary_Not_Null_Equals_Non_Numeric_First_Part(bool async)
{
await base.Ternary_Not_Null_Equals_Non_Numeric_First_Part(async);

AssertSql("""
SELECT TOP(1) N'' + CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE N'' + CAST([e].[Id] AS nvarchar(max)) + N'' = N'1'
""");
}

public override async Task Ternary_Not_Null_StartsWith(bool async)
{
await base.Ternary_Not_Null_StartsWith(async);

AssertSql("""
SELECT TOP(1) CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE CAST([e].[Id] AS nvarchar(max)) + N'' LIKE N'1%'
""");
}

public override async Task Ternary_Not_Null_StartsWith_Non_Numeric_First_Part(bool async)
{
await base.Ternary_Not_Null_StartsWith_Non_Numeric_First_Part(async);

AssertSql("""
SELECT TOP(1) N'' + CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE N'' + CAST([e].[Id] AS nvarchar(max)) + N'' LIKE N'1%'
""");
}

public override async Task Ternary_Null_Contains(bool async)
{
await base.Ternary_Null_Contains(async);

AssertSql("""
SELECT TOP(1) CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE CAST([e].[Id] AS nvarchar(max)) + N'' LIKE N'%1%'
""");
}

public override async Task Ternary_Null_Contains_Non_Numeric_First_Part(bool async)
{
await base.Ternary_Null_Contains_Non_Numeric_First_Part(async);

AssertSql("""
SELECT TOP(1) N'' + CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE N'' + CAST([e].[Id] AS nvarchar(max)) + N'' LIKE N'%1%'
""");
}

public override async Task Ternary_Null_EndsWith(bool async)
{
await base.Ternary_Null_EndsWith(async);

AssertSql("""
SELECT TOP(1) CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE CAST([e].[Id] AS nvarchar(max)) + N'' LIKE N'%1'
""");
}

public override async Task Ternary_Null_EndsWith_Non_Numeric_First_Part(bool async)
{
await base.Ternary_Null_EndsWith_Non_Numeric_First_Part(async);

AssertSql("""
SELECT TOP(1) N'' + CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE N'' + CAST([e].[Id] AS nvarchar(max)) + N'' LIKE N'%1'
""");
}

public override async Task Ternary_Null_Equals(bool async)
{
await base.Ternary_Null_Equals(async);

AssertSql("""
SELECT TOP(1) CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE CAST([e].[Id] AS nvarchar(max)) + N'' = N'1'
""");
}

public override async Task Ternary_Null_Equals_Non_Numeric_First_Part(bool async)
{
await base.Ternary_Null_Equals_Non_Numeric_First_Part(async);

AssertSql("""
SELECT TOP(1) N'' + CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE N'' + CAST([e].[Id] AS nvarchar(max)) + N'' = N'1'
""");
}

public override async Task Ternary_Null_StartsWith(bool async)
{
await base.Ternary_Null_StartsWith(async);

AssertSql("""
SELECT TOP(1) CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE CAST([e].[Id] AS nvarchar(max)) + N'' LIKE N'1%'
""");
}

public override async Task Ternary_Null_StartsWith_Non_Numeric_First_Part(bool async)
{
await base.Ternary_Null_StartsWith_Non_Numeric_First_Part(async);

AssertSql("""
SELECT TOP(1) N'' + CAST([e].[Id] AS nvarchar(max)) + N''
FROM [Entities] AS [e]
WHERE N'' + CAST([e].[Id] AS nvarchar(max)) + N'' LIKE N'1%'
""");
}

#endregion
}