diff --git a/All.sln.DotSettings b/All.sln.DotSettings index 31aeddd6221..9d6e36aa676 100644 --- a/All.sln.DotSettings +++ b/All.sln.DotSettings @@ -32,6 +32,7 @@ WARNING WARNING WARNING + WARNING True <?xml version="1.0" encoding="utf-16"?><Profile name="EntityFramework"><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSUseVar><BehavourStyle>CAN_CHANGE_TO_IMPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_IMPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_IMPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><XMLReformatCode>True</XMLReformatCode><CSUpdateFileHeader>True</CSUpdateFileHeader><CSharpFormatDocComments>True</CSharpFormatDocComments><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><CSArrangeQualifiers>True</CSArrangeQualifiers><CSEnforceVarKeywordUsageSettings>True</CSEnforceVarKeywordUsageSettings><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CSCodeStyleAttributes ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" ArrangeAttributes="True" ArrangeVarStyle="True" ArrangeBraces="True" ArrangeCodeBodyStyle="True" ArrangeObjectCreation="True" ArrangeDefaultValue="True" ArrangeNamespaces="True" /><IDEA_SETTINGS>&lt;profile version="1.0"&gt; diff --git a/src/EFCore.Relational/Update/Internal/CompositeRowForeignKeyValueFactory.cs b/src/EFCore.Relational/Update/Internal/CompositeRowForeignKeyValueFactory.cs index c9ce89a9bc1..ab44d45936f 100644 --- a/src/EFCore.Relational/Update/Internal/CompositeRowForeignKeyValueFactory.cs +++ b/src/EFCore.Relational/Update/Internal/CompositeRowForeignKeyValueFactory.cs @@ -29,10 +29,11 @@ public CompositeRowForeignKeyValueFactory( : base(foreignKey.Columns) { _foreignKey = foreignKey; - _principalKeyValueFactory = (IRowKeyValueFactory)((UniqueConstraint)foreignKey.PrincipalUniqueConstraint).GetRowKeyValueFactory(); + _principalKeyValueFactory = + (IRowKeyValueFactory)((UniqueConstraint)foreignKey.PrincipalUniqueConstraint).GetRowKeyValueFactory(); var columns = foreignKey.Columns; - _valueConverters = new(columns.Count); + _valueConverters = new List(columns.Count); for (var i = 0; i < columns.Count; i++) { diff --git a/src/EFCore.Relational/Update/Internal/CompositeRowValueFactory.cs b/src/EFCore.Relational/Update/Internal/CompositeRowValueFactory.cs index 4f05ca0afd0..bbed3af3eee 100644 --- a/src/EFCore.Relational/Update/Internal/CompositeRowValueFactory.cs +++ b/src/EFCore.Relational/Update/Internal/CompositeRowValueFactory.cs @@ -23,7 +23,7 @@ protected CompositeRowValueFactory(IReadOnlyList columns) { Columns = columns; } - + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -38,7 +38,7 @@ protected CompositeRowValueFactory(IReadOnlyList columns) /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual IEqualityComparer EqualityComparer { get; set; } = null!; + public virtual IEqualityComparer EqualityComparer { get; protected set; } = null!; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -92,8 +92,8 @@ public virtual bool TryCreateDependentKeyValue(IDictionary keyV /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public virtual bool TryCreateDependentKeyValue( - IReadOnlyModificationCommand command, - bool fromOriginalValues, + IReadOnlyModificationCommand command, + bool fromOriginalValues, [NotNullWhen(true)] out object?[]? key) { var converters = ValueConverters; @@ -124,7 +124,7 @@ public virtual bool TryCreateDependentKeyValue( { value = converter.ConvertFromProvider(value); } - + if (!fromOriginalValues && (entry.EntityState == EntityState.Added || entry.EntityState == EntityState.Modified && entry.IsModified(property))) diff --git a/src/EFCore.Relational/Update/Internal/RowForeignKeyValueFactory.cs b/src/EFCore.Relational/Update/Internal/RowForeignKeyValueFactory.cs index b16d3e63e1e..b6bba63f5c6 100644 --- a/src/EFCore.Relational/Update/Internal/RowForeignKeyValueFactory.cs +++ b/src/EFCore.Relational/Update/Internal/RowForeignKeyValueFactory.cs @@ -48,8 +48,9 @@ protected RowForeignKeyValueFactory( RelationalStrings.StoredKeyTypesNotConvertable( column.Name, column.StoreType, pkColumn.StoreType, pkColumn.Name)); } + _valueConverter = converterInfos.First().Create(); - + ColumnAccessors = new ColumnAccessors( ConvertAccessor((Func)columnAccessors.CurrentValueGetter), ConvertAccessor((Func)columnAccessors.OriginalValueGetter)); @@ -64,8 +65,8 @@ protected RowForeignKeyValueFactory( => command => { var tuple = columnAccessor(command); - return (tuple.Item1 == null - ? (default, tuple.Item2) + return (tuple.Item1 == null + ? (default, tuple.Item2) : ((TKey)_valueConverter!.ConvertFromProvider(tuple.Item1)!, tuple.Item2))!; }; diff --git a/src/EFCore.Relational/Update/Internal/RowForeignKeyValueFactoryFactory.cs b/src/EFCore.Relational/Update/Internal/RowForeignKeyValueFactoryFactory.cs index 550949eb09d..bf16ff5289f 100644 --- a/src/EFCore.Relational/Update/Internal/RowForeignKeyValueFactoryFactory.cs +++ b/src/EFCore.Relational/Update/Internal/RowForeignKeyValueFactoryFactory.cs @@ -35,20 +35,13 @@ public RowForeignKeyValueFactoryFactory(IValueConverterSelector valueConverterSe /// public virtual IRowForeignKeyValueFactory Create(IForeignKeyConstraint foreignKey) { - try - { - return foreignKey.Columns.Count == 1 - ? (IRowForeignKeyValueFactory)CreateMethod - .MakeGenericMethod( - foreignKey.PrincipalColumns.First().ProviderClrType, - foreignKey.Columns.First().ProviderClrType) - .Invoke(null, new object[] { foreignKey, _valueConverterSelector })! - : new CompositeRowForeignKeyValueFactory(foreignKey, _valueConverterSelector); - } - catch (TargetInvocationException exception) - { - throw exception.InnerException ?? exception; - } + return foreignKey.Columns.Count == 1 + ? (IRowForeignKeyValueFactory)CreateMethod + .MakeGenericMethod( + foreignKey.PrincipalColumns.First().ProviderClrType, + foreignKey.Columns.First().ProviderClrType) + .Invoke(null, new object[] { foreignKey, _valueConverterSelector })! + : new CompositeRowForeignKeyValueFactory(foreignKey, _valueConverterSelector); } private static readonly MethodInfo CreateMethod = typeof(RowForeignKeyValueFactoryFactory).GetTypeInfo() diff --git a/src/EFCore.Relational/Update/Internal/SimpleNullablePrincipalRowForeignKeyValueFactory.cs b/src/EFCore.Relational/Update/Internal/SimpleNullablePrincipalRowForeignKeyValueFactory.cs index c921a81cda3..5ad7e24a1fe 100644 --- a/src/EFCore.Relational/Update/Internal/SimpleNullablePrincipalRowForeignKeyValueFactory.cs +++ b/src/EFCore.Relational/Update/Internal/SimpleNullablePrincipalRowForeignKeyValueFactory.cs @@ -11,7 +11,7 @@ namespace Microsoft.EntityFrameworkCore.Update.Internal; /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// -public class SimpleNullablePrincipalRowForeignKeyValueFactory +public class SimpleNullablePrincipalRowForeignKeyValueFactory : RowForeignKeyValueFactory where TNonNullableKey : struct { diff --git a/test/EFCore.SqlServer.FunctionalTests/MismatchedKeyTypesSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Update/MismatchedKeyTypesSqlServerTest.cs similarity index 93% rename from test/EFCore.SqlServer.FunctionalTests/MismatchedKeyTypesSqlServerTest.cs rename to test/EFCore.SqlServer.FunctionalTests/Update/MismatchedKeyTypesSqlServerTest.cs index bfe6b5b04c4..6f34150ae67 100644 --- a/test/EFCore.SqlServer.FunctionalTests/MismatchedKeyTypesSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Update/MismatchedKeyTypesSqlServerTest.cs @@ -5,7 +5,7 @@ using System.Transactions; -namespace Microsoft.EntityFrameworkCore; +namespace Microsoft.EntityFrameworkCore.Update; public class MismatchedKeyTypesSqlServerTest : IClassFixture { @@ -27,10 +27,10 @@ public virtual void Can_update_and_delete_with_bigint_FK_and_int_PK() Assert.Equal(8, context.ChangeTracker.Entries().Count()); - principalEmpty.OptionalSingle = new(); - principalEmpty.RequiredSingle = new(); - principalEmpty.OptionalMany.Add(new()); - principalEmpty.RequiredMany.Add(new()); + principalEmpty.OptionalSingle = new OptionalSingleIntLong(); + principalEmpty.RequiredSingle = new RequiredSingleIntLong(); + principalEmpty.OptionalMany.Add(new OptionalManyIntLong()); + principalEmpty.RequiredMany.Add(new RequiredManyIntLong()); principalPopulated.OptionalSingle = null; principalPopulated.RequiredSingle = null; @@ -100,10 +100,10 @@ public virtual void Can_update_and_delete_with_tinyint_FK_and_smallint_PK() Assert.Equal(8, context.ChangeTracker.Entries().Count()); - principalEmpty.OptionalSingle = new(); - principalEmpty.RequiredSingle = new(); - principalEmpty.OptionalMany.Add(new()); - principalEmpty.RequiredMany.Add(new()); + principalEmpty.OptionalSingle = new OptionalSingleShortByte(); + principalEmpty.RequiredSingle = new RequiredSingleShortByte(); + principalEmpty.OptionalMany.Add(new OptionalManyShortByte()); + principalEmpty.RequiredMany.Add(new RequiredManyShortByte()); principalPopulated.OptionalSingle = null; principalPopulated.RequiredSingle = null; @@ -173,10 +173,10 @@ public virtual void Can_update_and_delete_with_string_FK_and_GUID_PK() Assert.Equal(8, context.ChangeTracker.Entries().Count()); - principalEmpty.OptionalSingle = new(); - principalEmpty.RequiredSingle = new(); - principalEmpty.OptionalMany.Add(new()); - principalEmpty.RequiredMany.Add(new()); + principalEmpty.OptionalSingle = new OptionalSingleStringGuid(); + principalEmpty.RequiredSingle = new RequiredSingleStringGuid(); + principalEmpty.OptionalMany.Add(new OptionalManyStringGuid()); + principalEmpty.RequiredMany.Add(new RequiredManyStringGuid()); principalPopulated.OptionalSingle = null; principalPopulated.RequiredSingle = null; @@ -246,10 +246,10 @@ public virtual void Can_update_and_delete_composite_keys_mismatched_in_store() Assert.Equal(8, context.ChangeTracker.Entries().Count()); - principalEmpty.OptionalSingle = new(); - principalEmpty.RequiredSingle = new(); - principalEmpty.OptionalMany.Add(new()); - principalEmpty.RequiredMany.Add(new()); + principalEmpty.OptionalSingle = new OptionalSingleComposite(); + principalEmpty.RequiredSingle = new RequiredSingleComposite(); + principalEmpty.OptionalMany.Add(new OptionalManyComposite()); + principalEmpty.RequiredMany.Add(new RequiredManyComposite()); principalPopulated.OptionalSingle = null; principalPopulated.RequiredSingle = null; @@ -361,7 +361,7 @@ public virtual void Queries_work_but_SaveChanges_fails_when_keys_incompatible_in Assert.Equal( RelationalStrings.StoredKeyTypesNotConvertable( nameof(OptionalSingleBad.PrincipalId), "uniqueidentifier", "bigint", nameof(PrincipalBad.Id)), - Assert.Throws(() => context.SaveChanges()).Message); + Assert.Throws(() => context.SaveChanges()).InnerException!.Message); } protected class MismatchedKeyTypesContextNoFks : MismatchedKeyTypesContext @@ -481,13 +481,24 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .HasValueGenerator(); modelBuilder.Entity() - .HasKey(e => new { e.Id1, e.Id2, e.Id3 }); + .HasKey( + e => new + { + e.Id1, + e.Id2, + e.Id3 + }); modelBuilder.Entity() - .HasKey(e => new { e.Id1, e.Id2, e.Id3 }); + .HasKey( + e => new + { + e.Id1, + e.Id2, + e.Id3 + }); - modelBuilder.Entity(). - Property(e => e.Id).ValueGeneratedNever(); + modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever(); modelBuilder.Entity().Property(e => e.PrincipalId).HasColumnType("bigint"); modelBuilder.Entity().Property(e => e.PrincipalId).HasColumnType("bigint"); @@ -518,11 +529,11 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) }); modelBuilder.Entity( - b => - { - b.Property(e => e.Id).ValueGeneratedNever(); - b.Property(e => e.PrincipalId3).HasConversion(v => new Guid(), v => 1); - }); + b => + { + b.Property(e => e.Id).ValueGeneratedNever(); + b.Property(e => e.PrincipalId3).HasConversion(v => new Guid(), v => 1); + }); } }