-
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
HasConversion is not used in the provider value comparer #29406
Comments
@Searen1984 I am not able to reproduce this--see my code below. Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate. public static class Your
{
public static string ConnectionString = @"Data Source=(LocalDb)\MSSQLLocalDB;Database=AllTogetherNow";
}
public record MyRecord
{
public long MyKey { get; set; }
public long OtherData { get; set; }
}
public class SomeDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(Your.ConnectionString)
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyRecord>(
entity =>
{
var keyComparer = new MyValueComparer<long>(
(l, r) => l == r,
v => v.GetHashCode(),
v => v);
var keyConverter = new ValueConverter<long, decimal>(
v => new decimal(v),
v => decimal.ToInt64(v));
entity.HasKey(e => e.MyKey);
entity.Property(e => e.MyKey)
.ValueGeneratedOnAdd()
.HasPrecision(18, 0)
.HasColumnName("MyKey")
.HasConversion(keyConverter, keyComparer);
entity.Property(e => e.OtherData)
.IsRequired()
.HasPrecision(18, 0)
.HasColumnName("OtherData")
.HasConversion(v => new decimal(v), v => decimal.ToInt64(v));
});
}
private class MyValueComparer<T> : ValueComparer<T>
{
public MyValueComparer(
Expression<Func<T, T, bool>> equalsExpression,
Expression<Func<T, int>> hashCodeExpression,
Expression<Func<T, T>> snapshotExpression)
: base(equalsExpression, hashCodeExpression, snapshotExpression)
{
}
public override object Snapshot(object instance)
{
if (instance is decimal instance1)
{
return Snapshot(decimal.ToInt64(instance1));
}
else
{
return Snapshot((T)instance);
}
}
public override int GetHashCode(object instance)
{
if (instance is decimal instance1)
{
return GetHashCode(decimal.ToInt64(instance1));
}
else
{
return GetHashCode((T)instance);
}
}
public override bool Equals(object left, object right)
{
var v1Null = left == null;
var v2Null = right == null;
var t1 = left?.GetType();
var t2 = right?.GetType();
if (right is null)
{
return v1Null;
}
else if (right is decimal right1)
{
return !v1Null && Equals((T)left, decimal.ToInt64(right1));
}
else
{
return !v1Null && Equals((T)left, (T)right);
}
}
}
}
public class Program
{
public static void Main()
{
using (var context = new SomeDbContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
context.AddRange(new MyRecord { OtherData = 2 }, new MyRecord { OtherData = 4 });
context.SaveChanges();
}
}
} |
I think there is a misunderstanding. The problem only occurs for the key. So, to reproduce the issue you should 1. remove the class MyValueComparer AND 2. remove the keyComparer from the MyKey Property. Then you should run into the exception. |
Fixes #29406 The value generator selection was returning a generator for the converted type, when a value for the non-converted type should have been used.
Fixes #29406 The value generator selection was returning a generator for the converted type, when a value for the non-converted type should have been used.
EF Core version: 7.0.0-rc.2.22472.11
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 6.0
Operating system: Windows 2011
IDE: Visual Studio 2022 17.3.1
When upgrading from EFCore 6 to the release candidate I got the following exception:
I found already the origin but let me give you some code first. We have the following entity:
In the SQL database table both values (MyKey and OtherData) are of the type numeric(18,0) which is interpreted in EFCore as the datatype decimal. Because a direct cast between long and decimal is not possible a conversion has always to be done between those data types for comparison and so on. Thus, in the corresponding DbContext I defined the following:
However, I found that this conversion is not taken into account anymore for the provider value comparer in EFCore 7. So, I was overwriting the methods Snapshot, GetHashCode and Equals in a derived class and used that instead of the default one. The following code works:
So, I guess the bug is that the provider value comparer does not use the defined conversion in the corresponding methods or before those are called.
The text was updated successfully, but these errors were encountered: