-
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
6.0.11 to 7.0.0: [...] are both mapped to column [..] but are configured to use differing provider types ('double' and 'double?').' #29531
Comments
Note for triage: full repro: public static class Your
{
public static string ConnectionString = @"Data Source=(LocalDb)\MSSQLLocalDB;Database=AllTogetherNow";
}
public class AlarmSetting
{
public int Id { get; set; }
}
public class AlarmSetting1 : AlarmSetting
{
public double? Threshold { get; set; }
}
public class AlarmSetting2 : AlarmSetting
{
public double? Threshold { get; set; }
}
public class AlarmSetting3 : AlarmSetting
{
public double? Threshold { get; set; }
}
public class AlarmSetting4 : AlarmSetting
{
public DistanceUnit Threshold { get; set; }
}
public class DistanceUnit
{
public float? Metres { 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<AlarmSetting>();
modelBuilder.Entity<AlarmSetting1>().Property(e => e.Threshold).HasColumnName("LowVoltageThreshold");
modelBuilder.Entity<AlarmSetting2>().Property(e => e.Threshold).HasColumnName("LowVoltageThreshold");
modelBuilder.Entity<AlarmSetting3>().Property(e => e.Threshold).HasColumnName("LowVoltageThreshold");
modelBuilder.Entity<AlarmSetting4>().Property(e => e.Threshold)
.HasColumnName("LowVoltageThreshold")
.HasConversion(e => (double?)e.Metres, e => new DistanceUnit { Metres = (float?)e });
}
}
public class Program
{
public static void Main()
{
using (var context = new SomeDbContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
}
}
} |
Hi, I've noticed they changed the compatible validation: var typeMapping = property.GetRelationalTypeMapping();
var duplicateTypeMapping = duplicateProperty.GetRelationalTypeMapping();
var currentTypeString = property.GetColumnType(storeObject);
var previousTypeString = duplicateProperty.GetColumnType(storeObject);
if (!string.Equals(currentTypeString, previousTypeString, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(
RelationalStrings.DuplicateColumnNameDataTypeMismatch(
duplicateProperty.DeclaringEntityType.DisplayName(),
duplicateProperty.Name,
property.DeclaringEntityType.DisplayName(),
property.Name,
columnName,
storeObject.DisplayName(),
previousTypeString,
currentTypeString));
}
var currentProviderType = typeMapping.Converter?.ProviderClrType ?? typeMapping.ClrType;
var previousProviderType = duplicateTypeMapping.Converter?.ProviderClrType ?? duplicateTypeMapping.ClrType;
if (currentProviderType != previousProviderType)
{
throw new InvalidOperationException(
RelationalStrings.DuplicateColumnNameProviderTypeMismatch(
duplicateProperty.DeclaringEntityType.DisplayName(),
duplicateProperty.Name,
property.DeclaringEntityType.DisplayName(),
property.Name,
columnName,
storeObject.DisplayName(),
previousProviderType.ShortDisplayName(),
currentProviderType.ShortDisplayName()));
} and this is EF Core 6.0.11: var currentTypeString = property.GetColumnType(storeObject)
?? property.GetRelationalTypeMapping().StoreType;
var previousTypeString = duplicateProperty.GetColumnType(storeObject)
?? duplicateProperty.GetRelationalTypeMapping().StoreType;
if (!string.Equals(currentTypeString, previousTypeString, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(
RelationalStrings.DuplicateColumnNameDataTypeMismatch(
duplicateProperty.DeclaringEntityType.DisplayName(),
duplicateProperty.Name,
property.DeclaringEntityType.DisplayName(),
property.Name,
columnName,
storeObject.DisplayName(),
previousTypeString,
currentTypeString));
} The first part, the confrontation by GetColumnType, is the same, but the second part is different: one uses ProviderClrType and the other StoreType. |
Note for triage: specifying the store type explicitly doesn't work as a workaround. |
Make IColumn.ProviderClrType always non-nullable for value types Fixes #29531
Make IColumn.ProviderClrType always non-nullable for value types Fixes #29531
Make IColumn.ProviderClrType always non-nullable for value types Fixes #29531
Make IColumn.ProviderClrType always non-nullable for value types Fixes #29531
Make IColumn.ProviderClrType always non-nullable for value types Fixes #29531
Include your code
When updating Microsoft.EntityFrameworkCore.SqlServer from 6.0.11 to 7.0.0 I receive a new error. I checked the breaking changes and full release notes and I can't see anything that should impact this.
I have four entities types mapped to the same database column. Column is named "LowVoltageThreshold" and is float nullable in the database.
Three of these entities map directly to a double? property:
The other map to utility class containing a float? property, so I use a converter to convert from double? to float?:
When looking at the signature returned by HasConversion it indeed have the nullable "?" in the type:
So where does that "double" without the nullable comes from in the compatibility validation? And why did this behavior change in v7?
Include stack traces
Include the full exception message and stack trace for any exception you encounter.
Include provider and version information
EF Core version: 7.0.0
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 6.0
The text was updated successfully, but these errors were encountered: