diff --git a/src/EFCore.Cosmos/Query/Internal/ValueBufferFactoryFactory.cs b/src/EFCore.Cosmos/Query/Internal/ValueBufferFactoryFactory.cs
index 2301692f0c6..7aaf05edc7a 100644
--- a/src/EFCore.Cosmos/Query/Internal/ValueBufferFactoryFactory.cs
+++ b/src/EFCore.Cosmos/Query/Internal/ValueBufferFactoryFactory.cs
@@ -54,7 +54,7 @@ private static Expression CreateGetValueExpression(
var storeName = property.GetCosmosPropertyName();
if (storeName.Length == 0)
{
- var type = property.FindMapping()?.Converter?.ProviderClrType
+ var type = property.GetTypeMapping().Converter?.ProviderClrType
?? property.ClrType;
Expression calculatedExpression = Expression.Default(type);
@@ -80,7 +80,7 @@ public static Expression CreateGetStoreValueExpression(Expression jObjectExpress
Expression.Constant(storeName));
var modelClrType = property.ClrType;
- var converter = property.FindMapping().Converter;
+ var converter = property.GetTypeMapping().Converter;
if (converter != null)
{
var nullableExpression = valueExpression;
diff --git a/src/EFCore.Cosmos/Update/Internal/DocumentSource.cs b/src/EFCore.Cosmos/Update/Internal/DocumentSource.cs
index fa76f01ecb3..f1f9b41a6e8 100644
--- a/src/EFCore.Cosmos/Update/Internal/DocumentSource.cs
+++ b/src/EFCore.Cosmos/Update/Internal/DocumentSource.cs
@@ -170,7 +170,7 @@ private static JToken ConvertPropertyValue(IProperty property, object value)
return null;
}
- var converter = property.FindMapping().Converter;
+ var converter = property.GetTypeMapping().Converter;
if (converter != null)
{
value = converter.ConvertToProvider(value);
diff --git a/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs b/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
index af1807b2663..2b6bed481fa 100644
--- a/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
+++ b/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
@@ -521,8 +521,7 @@ protected virtual void GeneratePropertyAnnotations([NotNull] IProperty property,
}
private static ValueConverter FindValueConverter(IProperty property)
- => property.FindMapping()?.Converter
- ?? property.GetValueConverter();
+ => property.GetTypeMapping().Converter;
///
/// Generates code for objects.
diff --git a/src/EFCore.Design/Migrations/Design/MigrationsCodeGenerator.cs b/src/EFCore.Design/Migrations/Design/MigrationsCodeGenerator.cs
index 0efd9d59a47..db846d83969 100644
--- a/src/EFCore.Design/Migrations/Design/MigrationsCodeGenerator.cs
+++ b/src/EFCore.Design/Migrations/Design/MigrationsCodeGenerator.cs
@@ -181,7 +181,7 @@ private static IEnumerable GetAnnotatables(IEnumerable GetNamespaces([NotNull] IModel model)
=> model.GetEntityTypes().SelectMany(
e => e.GetDeclaredProperties()
- .SelectMany(p => (p.FindMapping()?.Converter?.ProviderClrType ?? p.ClrType).GetNamespaces()))
+ .SelectMany(p => (p.GetTypeMapping().Converter?.ProviderClrType ?? p.ClrType).GetNamespaces()))
.Concat(GetAnnotationNamespaces(GetAnnotatables(model)));
private static IEnumerable GetAnnotatables(IModel model)
@@ -264,7 +264,7 @@ private static IEnumerable GetAnnotationNamespaces(IEnumerable annotatable is IProperty property
&& valueType.UnwrapNullableType() == property.ClrType.UnwrapNullableType()
- ? property.FindMapping()?.Converter?.ProviderClrType ?? valueType
+ ? property.GetTypeMapping().Converter?.ProviderClrType ?? valueType
: valueType;
}
}
diff --git a/src/EFCore.InMemory/Storage/Internal/InMemoryTable.cs b/src/EFCore.InMemory/Storage/Internal/InMemoryTable.cs
index 9674535fb08..71208bf0416 100644
--- a/src/EFCore.InMemory/Storage/Internal/InMemoryTable.cs
+++ b/src/EFCore.InMemory/Storage/Internal/InMemoryTable.cs
@@ -89,7 +89,7 @@ private static List GetStructuralComparers(IEnumerable
=> properties.Select(GetStructuralComparer).ToList();
private static ValueComparer GetStructuralComparer(IProperty p)
- => p.GetStructuralValueComparer() ?? p.FindMapping()?.StructuralComparer;
+ => p.GetStructuralValueComparer() ?? p.GetTypeMapping().StructuralComparer;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
diff --git a/src/EFCore.InMemory/ValueGeneration/Internal/InMemoryValueGeneratorSelector.cs b/src/EFCore.InMemory/ValueGeneration/Internal/InMemoryValueGeneratorSelector.cs
index 6736b8950ee..307cdeb0d24 100644
--- a/src/EFCore.InMemory/ValueGeneration/Internal/InMemoryValueGeneratorSelector.cs
+++ b/src/EFCore.InMemory/ValueGeneration/Internal/InMemoryValueGeneratorSelector.cs
@@ -57,6 +57,7 @@ public override ValueGenerator Select(IProperty property, IEntityType entityType
return property.GetValueGeneratorFactory() == null
&& property.ClrType.IsInteger()
+ && property.ClrType.UnwrapNullableType() != typeof(char)
? GetOrCreate(property)
: base.Select(property, entityType);
}
diff --git a/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs b/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs
index dd8e6b7200c..ca0e2c240ed 100644
--- a/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs
+++ b/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs
@@ -397,13 +397,22 @@ public static void SetIsFixedLength([NotNull] this IConventionProperty property,
=> property.FindAnnotation(RelationalAnnotationNames.IsFixedLength)?.GetConfigurationSource();
///
- /// Returns the for the given property.
+ /// Returns the for the given property on a finalized model.
+ ///
+ /// The property.
+ /// The type mapping.
+ [DebuggerStepThrough]
+ public static RelationalTypeMapping GetRelationalTypeMapping([NotNull] this IProperty property)
+ => (RelationalTypeMapping)property.GetTypeMapping();
+
+ ///
+ /// Returns the for the given property on a finalized model.
///
/// The property.
/// The type mapping, or null if none was found.
[DebuggerStepThrough]
public static RelationalTypeMapping FindRelationalMapping([NotNull] this IProperty property)
- => property[CoreAnnotationNames.TypeMapping] as RelationalTypeMapping;
+ => (RelationalTypeMapping)property.FindMapping();
///
///
diff --git a/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs b/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
index 33b313d8add..1833536e541 100644
--- a/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
+++ b/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
@@ -359,9 +359,9 @@ protected virtual void ValidateSharedColumnsCompatibility(
}
var currentTypeString = property.GetColumnType()
- ?? property.FindRelationalMapping()?.StoreType;
+ ?? property.GetRelationalTypeMapping().StoreType;
var previousTypeString = duplicateProperty.GetColumnType()
- ?? duplicateProperty.FindRelationalMapping()?.StoreType;
+ ?? duplicateProperty.GetRelationalTypeMapping().StoreType;
if (!string.Equals(currentTypeString, previousTypeString, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(
diff --git a/src/EFCore.Relational/Metadata/Conventions/RelationalValueGenerationConvention.cs b/src/EFCore.Relational/Metadata/Conventions/RelationalValueGenerationConvention.cs
index 6ed0e626f5c..d26f9fdcada 100644
--- a/src/EFCore.Relational/Metadata/Conventions/RelationalValueGenerationConvention.cs
+++ b/src/EFCore.Relational/Metadata/Conventions/RelationalValueGenerationConvention.cs
@@ -58,7 +58,7 @@ public virtual void ProcessPropertyAnnotationChanged(
/// The property.
/// The store value generation strategy to set for the given property.
protected override ValueGenerated? GetValueGenerated(IConventionProperty property)
- => GetValueGenerated((IProperty)property);
+ => GetValueGenerated(property);
///
/// Returns the store value generation strategy to set for the given property.
diff --git a/src/EFCore.Relational/Migrations/HistoryRepository.cs b/src/EFCore.Relational/Migrations/HistoryRepository.cs
index 7e54688d990..bb70c124047 100644
--- a/src/EFCore.Relational/Migrations/HistoryRepository.cs
+++ b/src/EFCore.Relational/Migrations/HistoryRepository.cs
@@ -105,7 +105,7 @@ private IModel EnsureModel()
x.ToTable(TableName, TableSchema);
});
- _model = modelBuilder.Model;
+ _model = modelBuilder.FinalizeModel();
}
return _model;
diff --git a/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs b/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs
index 821295e3fc2..b52e6310225 100644
--- a/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs
+++ b/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs
@@ -1788,8 +1788,8 @@ protected virtual void DiffData(
var targetValue = entry.GetCurrentValue(targetProperty);
var comparer = targetProperty.GetValueComparer() ??
sourceProperty.GetValueComparer() ??
- targetProperty.FindMapping()?.Comparer ??
- sourceProperty.FindMapping()?.Comparer;
+ targetProperty.GetTypeMapping().Comparer ??
+ sourceProperty.GetTypeMapping().Comparer;
var modelValuesChanged
= sourceProperty.ClrType.UnwrapNullableType() == targetProperty.ClrType.UnwrapNullableType()
diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingRemovingExpressionVisitor.cs b/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingRemovingExpressionVisitor.cs
index 1081f946896..410a34d6140 100644
--- a/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingRemovingExpressionVisitor.cs
+++ b/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingRemovingExpressionVisitor.cs
@@ -78,7 +78,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
return CreateGetValueExpression(
projectionIndex,
IsNullableProjection(projection),
- property.FindRelationalMapping(),
+ property.GetRelationalTypeMapping(),
methodCallExpression.Type);
}
diff --git a/src/EFCore.Relational/Query/Pipeline/SqlExpressions/ColumnExpression.cs b/src/EFCore.Relational/Query/Pipeline/SqlExpressions/ColumnExpression.cs
index fb0aa90549c..ba52f8bd0b1 100644
--- a/src/EFCore.Relational/Query/Pipeline/SqlExpressions/ColumnExpression.cs
+++ b/src/EFCore.Relational/Query/Pipeline/SqlExpressions/ColumnExpression.cs
@@ -14,7 +14,7 @@ namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.SqlExpressions
public class ColumnExpression : SqlExpression
{
internal ColumnExpression(IProperty property, TableExpressionBase table, bool nullable)
- : this(property.GetColumnName(), table, property.ClrType, property.FindRelationalMapping(),
+ : this(property.GetColumnName(), table, property.ClrType, property.GetRelationalTypeMapping(),
nullable || property.IsNullable || property.DeclaringEntityType.BaseType != null)
{
}
diff --git a/src/EFCore.Relational/Storage/RelationalCommandBuilderExtensions.cs b/src/EFCore.Relational/Storage/RelationalCommandBuilderExtensions.cs
index cbe1e165636..edfb5352c21 100644
--- a/src/EFCore.Relational/Storage/RelationalCommandBuilderExtensions.cs
+++ b/src/EFCore.Relational/Storage/RelationalCommandBuilderExtensions.cs
@@ -186,7 +186,7 @@ public static IRelationalCommandBuilder AddParameter(
new TypeMappedRelationalParameter(
invariantName,
name,
- property.FindRelationalMapping(),
+ property.GetRelationalTypeMapping(),
property.IsNullable));
}
@@ -277,7 +277,7 @@ public static IRelationalCommandBuilder AddPropertyParameter(
new TypeMappedPropertyRelationalParameter(
invariantName,
name,
- property.FindRelationalMapping(),
+ property.GetRelationalTypeMapping(),
property));
}
diff --git a/src/EFCore.Relational/Storage/TypeMaterializationInfo.cs b/src/EFCore.Relational/Storage/TypeMaterializationInfo.cs
index e4db3a1aa55..f4170684376 100644
--- a/src/EFCore.Relational/Storage/TypeMaterializationInfo.cs
+++ b/src/EFCore.Relational/Storage/TypeMaterializationInfo.cs
@@ -78,7 +78,7 @@ public TypeMaterializationInfo(
if (mapping == null)
{
- mapping = property?.FindRelationalMapping()
+ mapping = property?.GetRelationalTypeMapping()
?? typeMappingSource?.GetMapping(modelClrType);
}
diff --git a/src/EFCore.Sqlite.Core/Migrations/Internal/SqliteMigrationsAnnotationProvider.cs b/src/EFCore.Sqlite.Core/Migrations/Internal/SqliteMigrationsAnnotationProvider.cs
index 171452f83ff..e16a833377c 100644
--- a/src/EFCore.Sqlite.Core/Migrations/Internal/SqliteMigrationsAnnotationProvider.cs
+++ b/src/EFCore.Sqlite.Core/Migrations/Internal/SqliteMigrationsAnnotationProvider.cs
@@ -84,7 +84,6 @@ public override IEnumerable For(IProperty property)
}
private static bool HasConverter(IProperty property)
- => (property.FindMapping()?.Converter
- ?? property.GetValueConverter()) != null;
+ => property.GetTypeMapping().Converter != null;
}
}
diff --git a/src/EFCore/ChangeTracking/Internal/ChangeDetector.cs b/src/EFCore/ChangeTracking/Internal/ChangeDetector.cs
index db5c5d14b74..720e348f1ec 100644
--- a/src/EFCore/ChangeTracking/Internal/ChangeDetector.cs
+++ b/src/EFCore/ChangeTracking/Internal/ChangeDetector.cs
@@ -198,7 +198,7 @@ private void LocalDetectChanges(InternalEntityEntry entry)
var current = entry[property];
var original = entry.GetOriginalValue(property);
- var comparer = property.GetValueComparer() ?? property.FindMapping()?.Comparer;
+ var comparer = property.GetValueComparer() ?? property.GetTypeMapping().Comparer;
if (comparer == null)
{
@@ -253,7 +253,7 @@ private void DetectKeyChange(InternalEntityEntry entry, IProperty property)
var currentValue = entry[property];
var comparer = property.GetKeyValueComparer()
- ?? property.FindMapping()?.KeyComparer;
+ ?? property.GetTypeMapping().KeyComparer;
// Note that mutation of a byte[] key is not supported or detected, but two different instances
// of byte[] with the same content must be detected as equal.
diff --git a/src/EFCore/ChangeTracking/Internal/CompositeValueFactory.cs b/src/EFCore/ChangeTracking/Internal/CompositeValueFactory.cs
index 9ed2a59d500..2f273b25b26 100644
--- a/src/EFCore/ChangeTracking/Internal/CompositeValueFactory.cs
+++ b/src/EFCore/ChangeTracking/Internal/CompositeValueFactory.cs
@@ -133,7 +133,7 @@ protected virtual bool TryCreateFromEntry(
///
protected static IEqualityComparer
protected override ValueComparer GetValueComparer(IProperty property)
- => property.GetValueComparer() ?? property.FindMapping()?.Comparer;
+ => property.GetValueComparer() ?? property.GetTypeMapping().Comparer;
}
}
diff --git a/src/EFCore/ChangeTracking/Internal/RelationshipSnapshotFactoryFactory.cs b/src/EFCore/ChangeTracking/Internal/RelationshipSnapshotFactoryFactory.cs
index 941f5dd7255..d3ba89dadee 100644
--- a/src/EFCore/ChangeTracking/Internal/RelationshipSnapshotFactoryFactory.cs
+++ b/src/EFCore/ChangeTracking/Internal/RelationshipSnapshotFactoryFactory.cs
@@ -39,6 +39,6 @@ protected override int GetPropertyCount(IEntityType entityType)
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
protected override ValueComparer GetValueComparer(IProperty property)
- => property.GetKeyValueComparer() ?? property.FindMapping()?.KeyComparer;
+ => property.GetKeyValueComparer() ?? property.GetTypeMapping().KeyComparer;
}
}
diff --git a/src/EFCore/ChangeTracking/Internal/RelationshipsSnapshot.cs b/src/EFCore/ChangeTracking/Internal/RelationshipsSnapshot.cs
index af482cd471b..73abf3d4cdf 100644
--- a/src/EFCore/ChangeTracking/Internal/RelationshipsSnapshot.cs
+++ b/src/EFCore/ChangeTracking/Internal/RelationshipsSnapshot.cs
@@ -49,7 +49,7 @@ private static object SnapshotValue(IPropertyBase propertyBase, object value)
{
if (propertyBase is IProperty property)
{
- var comparer = property.GetKeyValueComparer() ?? property.FindMapping()?.KeyComparer;
+ var comparer = property.GetKeyValueComparer() ?? property.GetTypeMapping().KeyComparer;
if (comparer != null)
{
diff --git a/src/EFCore/ChangeTracking/Internal/SidecarValues.cs b/src/EFCore/ChangeTracking/Internal/SidecarValues.cs
index 5fca5c63e55..6084d2d1cec 100644
--- a/src/EFCore/ChangeTracking/Internal/SidecarValues.cs
+++ b/src/EFCore/ChangeTracking/Internal/SidecarValues.cs
@@ -53,7 +53,7 @@ public void SetValue(IProperty property, object value, int index)
private static object SnapshotValue(IProperty property, object value)
{
- var comparer = property.GetValueComparer() ?? property.FindMapping()?.Comparer;
+ var comparer = property.GetValueComparer() ?? property.GetTypeMapping().Comparer;
return comparer == null ? value : comparer.Snapshot(value);
}
diff --git a/src/EFCore/ChangeTracking/Internal/SidecarValuesFactoryFactory.cs b/src/EFCore/ChangeTracking/Internal/SidecarValuesFactoryFactory.cs
index 54415874865..e069f626475 100644
--- a/src/EFCore/ChangeTracking/Internal/SidecarValuesFactoryFactory.cs
+++ b/src/EFCore/ChangeTracking/Internal/SidecarValuesFactoryFactory.cs
@@ -39,6 +39,6 @@ protected override int GetPropertyCount(IEntityType entityType)
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
protected override ValueComparer GetValueComparer(IProperty property)
- => property.GetValueComparer() ?? property.FindMapping()?.Comparer;
+ => property.GetValueComparer() ?? property.GetTypeMapping().Comparer;
}
}
diff --git a/src/EFCore/ChangeTracking/Internal/SimplePrincipalKeyValueFactory.cs b/src/EFCore/ChangeTracking/Internal/SimplePrincipalKeyValueFactory.cs
index e5cb378a4fe..c0142b0ad95 100644
--- a/src/EFCore/ChangeTracking/Internal/SimplePrincipalKeyValueFactory.cs
+++ b/src/EFCore/ChangeTracking/Internal/SimplePrincipalKeyValueFactory.cs
@@ -35,7 +35,7 @@ public SimplePrincipalKeyValueFactory([NotNull] IProperty property)
_propertyAccessors = _property.GetPropertyAccessors();
var comparer = property.GetKeyValueComparer()
- ?? property.FindMapping()?.KeyComparer;
+ ?? property.GetTypeMapping().KeyComparer;
EqualityComparer
= comparer != null
diff --git a/src/EFCore/ChangeTracking/Internal/StateManager.cs b/src/EFCore/ChangeTracking/Internal/StateManager.cs
index 913a4cfd554..861d8496303 100644
--- a/src/EFCore/ChangeTracking/Internal/StateManager.cs
+++ b/src/EFCore/ChangeTracking/Internal/StateManager.cs
@@ -1078,7 +1078,7 @@ private static bool KeysEqual(InternalEntityEntry entry, IForeignKey fk, Interna
private static bool KeyValuesEqual(IProperty property, object value, object currentValue)
=> (property.GetKeyValueComparer()
- ?? property.FindMapping()?.KeyComparer)
+ ?? property.GetTypeMapping().KeyComparer)
?.Equals(currentValue, value)
?? Equals(currentValue, value);
diff --git a/src/EFCore/Extensions/PropertyExtensions.cs b/src/EFCore/Extensions/PropertyExtensions.cs
index 4ed31a14e0d..fb6e727ae94 100644
--- a/src/EFCore/Extensions/PropertyExtensions.cs
+++ b/src/EFCore/Extensions/PropertyExtensions.cs
@@ -3,9 +3,11 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.ChangeTracking;
+using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
@@ -22,6 +24,25 @@ namespace Microsoft.EntityFrameworkCore
///
public static class PropertyExtensions
{
+ ///
+ /// Returns the for the given property from a finalized model.
+ ///
+ /// The property.
+ /// The type mapping.
+ public static CoreTypeMapping GetTypeMapping(
+ [NotNull] this IProperty property)
+ {
+ var mapping = (CoreTypeMapping)property[CoreAnnotationNames.TypeMapping];
+
+ if (mapping == null)
+ {
+ throw new InvalidOperationException(
+ CoreStrings.ModelNotFinalized(nameof(GetTypeMapping)));
+ }
+
+ return mapping;
+ }
+
///
/// Returns the for the given property.
///
diff --git a/src/EFCore/Metadata/Internal/ClrPropertyGetterFactory.cs b/src/EFCore/Metadata/Internal/ClrPropertyGetterFactory.cs
index 3b08d38dea2..75eda218d65 100644
--- a/src/EFCore/Metadata/Internal/ClrPropertyGetterFactory.cs
+++ b/src/EFCore/Metadata/Internal/ClrPropertyGetterFactory.cs
@@ -93,7 +93,7 @@ protected override IClrPropertyGetter CreateGeneric).MakeGenericType(typeof(TValue)),
new object[]
diff --git a/src/EFCore/Metadata/Internal/EntityType.cs b/src/EFCore/Metadata/Internal/EntityType.cs
index c7597b86a0f..6d15480a7bd 100644
--- a/src/EFCore/Metadata/Internal/EntityType.cs
+++ b/src/EFCore/Metadata/Internal/EntityType.cs
@@ -2355,7 +2355,7 @@ public virtual IEnumerable> GetSeedData(bool provide
{
if (propertyBase is IProperty property)
{
- valueConverter = property.FindMapping()?.Converter
+ valueConverter = property.GetTypeMapping().Converter
?? property.GetValueConverter();
}
diff --git a/src/EFCore/Metadata/Internal/IndexedPropertyGetterFactory.cs b/src/EFCore/Metadata/Internal/IndexedPropertyGetterFactory.cs
index 12339a34f1d..043b5c29287 100644
--- a/src/EFCore/Metadata/Internal/IndexedPropertyGetterFactory.cs
+++ b/src/EFCore/Metadata/Internal/IndexedPropertyGetterFactory.cs
@@ -54,7 +54,7 @@ protected override IClrPropertyGetter CreateGeneric).MakeGenericType(typeof(TValue)),
new object[]
diff --git a/src/EFCore/Properties/CoreStrings.Designer.cs b/src/EFCore/Properties/CoreStrings.Designer.cs
index 32222b9d1a1..d22fe12f36b 100644
--- a/src/EFCore/Properties/CoreStrings.Designer.cs
+++ b/src/EFCore/Properties/CoreStrings.Designer.cs
@@ -1,4 +1,4 @@
-//
+//
using System;
using System.Reflection;
@@ -32,6 +32,14 @@ public static string CircularDependency([CanBeNull] object cycle)
GetString("CircularDependency", nameof(cycle)),
cycle);
+ ///
+ /// The model must be finalized before '{method}' can be used. Ensure that either 'OnModelCreating' has completed or, if using a stand-alone 'ModelBuilder', that 'FinalizeModel' has been called.
+ ///
+ public static string ModelNotFinalized([CanBeNull] object method)
+ => string.Format(
+ GetString("ModelNotFinalized", nameof(method)),
+ method);
+
///
/// The value provided for argument '{argumentName}' must be a valid value of enum type '{enumType}'.
///
diff --git a/src/EFCore/Properties/CoreStrings.resx b/src/EFCore/Properties/CoreStrings.resx
index e9a6efb62e9..73a6de11d78 100644
--- a/src/EFCore/Properties/CoreStrings.resx
+++ b/src/EFCore/Properties/CoreStrings.resx
@@ -1,17 +1,17 @@
-
@@ -120,6 +120,9 @@
Unable to save changes because a circular dependency was detected in the data to be saved: '{cycle}'.
+
+ The model must be finalized before '{method}' can be used. Ensure that either 'OnModelCreating' has completed or, if using a stand-alone 'ModelBuilder', that 'FinalizeModel' has been called.
+
The value provided for argument '{argumentName}' must be a valid value of enum type '{enumType}'.
diff --git a/src/EFCore/ValueGeneration/ValueGeneratorSelector.cs b/src/EFCore/ValueGeneration/ValueGeneratorSelector.cs
index 262e25c0cd1..21fb0bd96f3 100644
--- a/src/EFCore/ValueGeneration/ValueGeneratorSelector.cs
+++ b/src/EFCore/ValueGeneration/ValueGeneratorSelector.cs
@@ -73,7 +73,7 @@ private static ValueGenerator CreateFromFactory(IProperty property, IEntityType
if (factory == null)
{
- var mapping = property.FindMapping();
+ var mapping = property.GetTypeMapping();
factory = mapping?.ValueGeneratorFactory;
if (factory == null)
diff --git a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs
index c27c79ae99c..4f5566af3cf 100644
--- a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs
+++ b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs
@@ -39,9 +39,6 @@ public class CSharpMigrationsGeneratorTest
[ConditionalFact]
public void Test_new_annotations_handled_for_entity_types()
{
- var model = RelationalTestHelpers.Instance.CreateConventionBuilder();
- var entityType = model.Entity().Metadata;
-
// Only add the annotation here if it will never be present on IEntityType
var notForEntityType = new HashSet
{
@@ -110,7 +107,8 @@ public void Test_new_annotations_handled_for_entity_types()
};
MissingAnnotationCheck(
- entityType, notForEntityType, forEntityType,
+ b => b.Entity().Metadata,
+ notForEntityType, forEntityType,
_toTable,
(g, m, b) => g.TestGenerateEntityTypeAnnotations("modelBuilder", (IEntityType)m, b));
}
@@ -118,9 +116,6 @@ public void Test_new_annotations_handled_for_entity_types()
[ConditionalFact]
public void Test_new_annotations_handled_for_properties()
{
- var model = RelationalTestHelpers.Instance.CreateConventionBuilder();
- var property = model.Entity().Property(e => e.Id).Metadata;
-
// Only add the annotation here if it will never be present on IProperty
var notForProperty = new HashSet
{
@@ -203,13 +198,14 @@ public void Test_new_annotations_handled_for_properties()
};
MissingAnnotationCheck(
- property, notForProperty, forProperty,
+ b => b.Entity().Property(e => e.Id).Metadata,
+ notForProperty, forProperty,
"",
(g, m, b) => g.TestGeneratePropertyAnnotations((IProperty)m, b));
}
private static void MissingAnnotationCheck(
- IMutableAnnotatable metadataItem,
+ Func createMetadataItem,
HashSet invalidAnnotations,
Dictionary validAnnotations,
string generationDefault,
@@ -240,9 +236,13 @@ private static void MissingAnnotationCheck(
if (!invalidAnnotations.Contains(annotationName))
{
+ var modelBuilder = RelationalTestHelpers.Instance.CreateConventionBuilder();
+ var metadataItem = createMetadataItem(modelBuilder);
metadataItem[annotationName] = validAnnotations.ContainsKey(annotationName)
? validAnnotations[annotationName].Value
- : new Random(); // Something that cannot be scaffolded by default
+ : null;
+
+ modelBuilder.FinalizeModel();
var sb = new IndentedStringBuilder();
@@ -261,8 +261,6 @@ private static void MissingAnnotationCheck(
? validAnnotations[annotationName].Expected
: generationDefault,
sb.ToString());
-
- metadataItem[annotationName] = null;
}
}
}
@@ -703,6 +701,8 @@ public void Snapshot_with_default_values_are_round_tripped()
eb.HasKey(e => e.Boolean);
});
+ modelBuilder.FinalizeModel();
+
var modelSnapshotCode = generator.GenerateSnapshot(
"MyNamespace",
typeof(MyContext),
@@ -715,8 +715,26 @@ public void Snapshot_with_default_values_are_round_tripped()
foreach (var property in modelBuilder.Model.GetEntityTypes().Single().GetProperties())
{
- var snapshotProperty = entityType.FindProperty(property.Name);
- Assert.Equal(property.GetDefaultValue(), snapshotProperty.GetDefaultValue());
+ var expected = property.GetDefaultValue();
+ var actual = entityType.FindProperty(property.Name).GetDefaultValue();
+
+ if (actual != null
+ && expected != null)
+ {
+ if (expected.GetType().IsEnum)
+ {
+ actual = actual is string actualString
+ ? Enum.Parse(expected.GetType(), actualString)
+ : Enum.ToObject(expected.GetType(), actual);
+ }
+
+ if (actual.GetType() != expected.GetType())
+ {
+ actual = Convert.ChangeType(actual, expected.GetType());
+ }
+ }
+
+ Assert.Equal(expected, actual);
}
}
diff --git a/test/EFCore.InMemory.FunctionalTests/ShadowStateUpdateTest.cs b/test/EFCore.InMemory.FunctionalTests/ShadowStateUpdateTest.cs
index b0235b25eba..00b5a0e9317 100644
--- a/test/EFCore.InMemory.FunctionalTests/ShadowStateUpdateTest.cs
+++ b/test/EFCore.InMemory.FunctionalTests/ShadowStateUpdateTest.cs
@@ -4,7 +4,9 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.InMemory.Metadata.Conventions;
using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Metadata.Conventions;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Xunit;
@@ -15,11 +17,9 @@ public class ShadowStateUpdateTest : IClassFixture
[ConditionalFact]
public async Task Can_add_update_delete_end_to_end_using_partial_shadow_state()
{
- IMutableModel model = new Model();
+ IMutableModel model = new Model(InMemoryConventionSetBuilder.Build());
var customerType = model.AddEntityType(typeof(Customer));
- var property1 = customerType.AddProperty("Id", typeof(int));
- customerType.SetPrimaryKey(property1);
customerType.AddProperty("Name", typeof(string));
var optionsBuilder = new DbContextOptionsBuilder()
diff --git a/test/EFCore.InMemory.Tests/InMemoryDatabaseTest.cs b/test/EFCore.InMemory.Tests/InMemoryDatabaseTest.cs
index 6a826343564..ae80cd13ccc 100644
--- a/test/EFCore.InMemory.Tests/InMemoryDatabaseTest.cs
+++ b/test/EFCore.InMemory.Tests/InMemoryDatabaseTest.cs
@@ -8,6 +8,7 @@
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.InMemory.Diagnostics.Internal;
using Microsoft.EntityFrameworkCore.InMemory.Internal;
+using Microsoft.EntityFrameworkCore.InMemory.Metadata.Conventions;
using Microsoft.EntityFrameworkCore.InMemory.Storage.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
@@ -177,7 +178,7 @@ public async Task Should_log_writes()
private static IModel CreateModel()
{
- var modelBuilder = new ModelBuilder(new ConventionSet());
+ var modelBuilder = new ModelBuilder(InMemoryConventionSetBuilder.Build());
modelBuilder.Entity(
b =>
diff --git a/test/EFCore.Relational.Tests/Storage/RelationalTypeMappingTest.cs b/test/EFCore.Relational.Tests/Storage/RelationalTypeMappingTest.cs
index 9e734168c5f..d997b2c5f20 100644
--- a/test/EFCore.Relational.Tests/Storage/RelationalTypeMappingTest.cs
+++ b/test/EFCore.Relational.Tests/Storage/RelationalTypeMappingTest.cs
@@ -532,8 +532,8 @@ public virtual void Primary_key_type_mapping_is_picked_up_by_FK_without_going_th
using (var context = new FruityContext(ContextOptions))
{
Assert.Same(
- context.Model.FindEntityType(typeof(Banana)).FindProperty("Id").FindMapping(),
- context.Model.FindEntityType(typeof(Kiwi)).FindProperty("BananaId").FindMapping());
+ context.Model.FindEntityType(typeof(Banana)).FindProperty("Id").GetTypeMapping(),
+ context.Model.FindEntityType(typeof(Kiwi)).FindProperty("BananaId").GetTypeMapping());
}
}
@@ -555,8 +555,8 @@ public virtual void Primary_key_type_mapping_can_differ_from_FK()
{
Assert.Equal(
typeof(short),
- context.Model.FindEntityType(typeof(Banana)).FindProperty("Id").FindMapping().Converter.ProviderClrType);
- Assert.Null(context.Model.FindEntityType(typeof(Kiwi)).FindProperty("Id").FindMapping().Converter);
+ context.Model.FindEntityType(typeof(Banana)).FindProperty("Id").GetTypeMapping().Converter.ProviderClrType);
+ Assert.Null(context.Model.FindEntityType(typeof(Kiwi)).FindProperty("Id").GetTypeMapping().Converter);
}
}
diff --git a/test/EFCore.Relational.Tests/TestUtilities/TestRelationalConventionSetBuilder.cs b/test/EFCore.Relational.Tests/TestUtilities/TestRelationalConventionSetBuilder.cs
index 1465cf753bb..255f8d9768d 100644
--- a/test/EFCore.Relational.Tests/TestUtilities/TestRelationalConventionSetBuilder.cs
+++ b/test/EFCore.Relational.Tests/TestUtilities/TestRelationalConventionSetBuilder.cs
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using Microsoft.EntityFrameworkCore.Metadata.Conventions;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
namespace Microsoft.EntityFrameworkCore.TestUtilities
@@ -13,5 +14,8 @@ public TestRelationalConventionSetBuilder(
: base(dependencies, relationalDependencies)
{
}
+
+ public static ConventionSet Build()
+ => ConventionSet.CreateConventionSet(RelationalTestHelpers.Instance.CreateContext());
}
}
diff --git a/test/EFCore.Relational.Tests/TestUtilities/TestRelationalTypeMappingSource.cs b/test/EFCore.Relational.Tests/TestUtilities/TestRelationalTypeMappingSource.cs
index 4dcd9539298..b0cdd01527e 100644
--- a/test/EFCore.Relational.Tests/TestUtilities/TestRelationalTypeMappingSource.cs
+++ b/test/EFCore.Relational.Tests/TestUtilities/TestRelationalTypeMappingSource.cs
@@ -24,6 +24,9 @@ private static readonly RelationalTypeMapping _rowversion
private static readonly RelationalTypeMapping _defaultIntMapping
= new IntTypeMapping("default_int_mapping", dbType: DbType.Int32);
+ private static readonly RelationalTypeMapping _defaultCharMapping
+ = new CharTypeMapping("default_char_mapping", dbType: DbType.Int32);
+
private static readonly RelationalTypeMapping _defaultLongMapping
= new LongTypeMapping("default_long_mapping", dbType: DbType.Int64);
@@ -99,7 +102,7 @@ private readonly IReadOnlyDictionary _simpleMapping
{ typeof(byte), _defaultByteMapping },
{ typeof(double), _defaultDoubleMapping },
{ typeof(DateTimeOffset), _defaultDateTimeOffsetMapping },
- { typeof(char), _defaultIntMapping },
+ { typeof(char), _defaultCharMapping },
{ typeof(short), _defaultShortMapping },
{ typeof(float), _defaultFloatMapping },
{ typeof(decimal), _defaultDecimalMapping },
diff --git a/test/EFCore.Relational.Tests/Update/ModificationCommandComparerTest.cs b/test/EFCore.Relational.Tests/Update/ModificationCommandComparerTest.cs
index 21201994587..778ab148378 100644
--- a/test/EFCore.Relational.Tests/Update/ModificationCommandComparerTest.cs
+++ b/test/EFCore.Relational.Tests/Update/ModificationCommandComparerTest.cs
@@ -7,6 +7,7 @@
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Storage;
+using Microsoft.EntityFrameworkCore.TestUtilities;
using Microsoft.EntityFrameworkCore.Update.Internal;
using Xunit;
@@ -18,7 +19,7 @@ public class ModificationCommandComparerTest
[ConditionalFact]
public void Compare_returns_0_only_for_commands_that_are_equal()
{
- IMutableModel model = new Model();
+ IMutableModel model = new Model(TestRelationalConventionSetBuilder.Build());
var entityType = model.AddEntityType(typeof(object));
var key = entityType.AddProperty("Id", typeof(int));
entityType.SetPrimaryKey(key);
@@ -152,7 +153,7 @@ public void Compare_returns_0_only_for_entries_that_have_same_key_values()
private void Compare_returns_0_only_for_entries_that_have_same_key_values_generic(T value1, T value2)
{
- IMutableModel model = new Model();
+ IMutableModel model = new Model(TestRelationalConventionSetBuilder.Build());
var entityType = model.AddEntityType(typeof(object));
var keyProperty = entityType.AddProperty("Id", typeof(T));
diff --git a/test/EFCore.Relational.Tests/Update/ModificationCommandTest.cs b/test/EFCore.Relational.Tests/Update/ModificationCommandTest.cs
index 130b160fa64..3115beb6351 100644
--- a/test/EFCore.Relational.Tests/Update/ModificationCommandTest.cs
+++ b/test/EFCore.Relational.Tests/Update/ModificationCommandTest.cs
@@ -440,21 +440,21 @@ private class T1
private static IModel BuildModel(bool generateKeyValues, bool computeNonKeyValue)
{
- IMutableModel model = new Model();
+ IMutableModel model = new Model(TestRelationalConventionSetBuilder.Build());
var entityType = model.AddEntityType(typeof(T1));
- var key = entityType.AddProperty("Id", typeof(int));
+ var key = entityType.FindProperty("Id");
key.ValueGenerated = generateKeyValues ? ValueGenerated.OnAdd : ValueGenerated.Never;
key.SetColumnName("Col1");
entityType.SetPrimaryKey(key);
- var nonKey1 = entityType.AddProperty("Name1", typeof(string));
+ var nonKey1 = entityType.FindProperty("Name1");
nonKey1.IsConcurrencyToken = computeNonKeyValue;
nonKey1.SetColumnName("Col2");
nonKey1.ValueGenerated = computeNonKeyValue ? ValueGenerated.OnAddOrUpdate : ValueGenerated.Never;
- var nonKey2 = entityType.AddProperty("Name2", typeof(string));
+ var nonKey2 = entityType.FindProperty("Name2");
nonKey2.IsConcurrencyToken = computeNonKeyValue;
nonKey2.SetColumnName("Col3");
diff --git a/test/EFCore.Relational.Tests/Update/UpdateSqlGeneratorTestBase.cs b/test/EFCore.Relational.Tests/Update/UpdateSqlGeneratorTestBase.cs
index bb9065b59a6..4d23624e936 100644
--- a/test/EFCore.Relational.Tests/Update/UpdateSqlGeneratorTestBase.cs
+++ b/test/EFCore.Relational.Tests/Update/UpdateSqlGeneratorTestBase.cs
@@ -3,11 +3,9 @@
using System;
using System.Linq;
-using System.Reflection;
using System.Text;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
-using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.TestUtilities;
using Microsoft.Extensions.DependencyInjection;
@@ -411,14 +409,9 @@ protected ModificationCommand CreateDeleteCommand(bool concurrencyToken = true)
private IMutableEntityType GetDuckType()
{
- var entityType = ((IMutableModel)new Model()).AddEntityType(typeof(Duck));
- var id = entityType.AddProperty(typeof(Duck).GetTypeInfo().GetDeclaredProperty(nameof(Duck.Id)));
- entityType.AddProperty(typeof(Duck).GetTypeInfo().GetDeclaredProperty(nameof(Duck.Name)));
- entityType.AddProperty(typeof(Duck).GetTypeInfo().GetDeclaredProperty(nameof(Duck.Quacks)));
- entityType.AddProperty(typeof(Duck).GetTypeInfo().GetDeclaredProperty(nameof(Duck.Computed)));
- entityType.AddProperty(typeof(Duck).GetTypeInfo().GetDeclaredProperty(nameof(Duck.ConcurrencyToken)));
- entityType.SetPrimaryKey(id);
- return entityType;
+ var modelBuilder = TestHelpers.CreateConventionBuilder();
+ modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever();
+ return modelBuilder.Model.FindEntityType(typeof(Duck));
}
protected class Duck
diff --git a/test/EFCore.SqlServer.FunctionalTests/DataAnnotationSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/DataAnnotationSqlServerTest.cs
index d246f61e22f..1b0840a0328 100644
--- a/test/EFCore.SqlServer.FunctionalTests/DataAnnotationSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/DataAnnotationSqlServerTest.cs
@@ -85,7 +85,7 @@ public override ModelBuilder Key_and_MaxLength_64_produce_nvarchar_64()
var property = GetProperty(modelBuilder, "PersonFirstName");
- var storeType = property.FindRelationalMapping().StoreType;
+ var storeType = property.GetRelationalTypeMapping().StoreType;
Assert.Equal("nvarchar(64)", storeType);
@@ -98,7 +98,7 @@ public override ModelBuilder Timestamp_takes_precedence_over_MaxLength()
var property = GetProperty(modelBuilder, "MaxTimestamp");
- var storeType = property.FindRelationalMapping().StoreType;
+ var storeType = property.GetRelationalTypeMapping().StoreType;
Assert.Equal("rowversion", storeType);
diff --git a/test/EFCore.SqlServer.Tests/SqlServerValueGeneratorCacheTest.cs b/test/EFCore.SqlServer.Tests/SqlServerValueGeneratorCacheTest.cs
index 6ab17b6de53..cc35000ab87 100644
--- a/test/EFCore.SqlServer.Tests/SqlServerValueGeneratorCacheTest.cs
+++ b/test/EFCore.SqlServer.Tests/SqlServerValueGeneratorCacheTest.cs
@@ -115,12 +115,16 @@ private static FakeRelationalConnection CreateConnection(
[ConditionalFact]
public void Block_size_is_obtained_from_default_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.Entity()
.Property(e => e.Id)
.ForSqlServerUseSequenceHiLo()
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal(10, cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.IncrementBy);
@@ -129,12 +133,16 @@ public void Block_size_is_obtained_from_default_sequence()
[ConditionalFact]
public void Block_size_is_obtained_from_named_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.Entity()
.Property(e => e.Id)
.ForSqlServerUseSequenceHiLo("DaneelOlivaw")
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal(10, cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.IncrementBy);
@@ -143,12 +151,16 @@ public void Block_size_is_obtained_from_named_sequence()
[ConditionalFact]
public void Block_size_is_obtained_from_model_default_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.ForSqlServerUseSequenceHiLo()
.Entity()
.Property(e => e.Id)
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal(10, cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.IncrementBy);
@@ -157,12 +169,16 @@ public void Block_size_is_obtained_from_model_default_sequence()
[ConditionalFact]
public void Block_size_is_obtained_from_named_model_default_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.ForSqlServerUseSequenceHiLo("DaneelOlivaw")
.Entity()
.Property(e => e.Id)
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal(10, cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.IncrementBy);
@@ -171,13 +187,17 @@ public void Block_size_is_obtained_from_named_model_default_sequence()
[ConditionalFact]
public void Block_size_is_obtained_from_specified_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.HasSequence("DaneelOlivaw", b => b.IncrementsBy(11))
.Entity()
.Property(e => e.Id)
.ForSqlServerUseSequenceHiLo("DaneelOlivaw")
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal(11, cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.IncrementBy);
@@ -186,7 +206,9 @@ public void Block_size_is_obtained_from_specified_sequence()
[ConditionalFact]
public void Non_positive_block_sizes_are_not_allowed()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.HasSequence("DaneelOlivaw", b => b.IncrementsBy(-1))
.Entity()
.Property(e => e.Id)
@@ -195,6 +217,8 @@ public void Non_positive_block_sizes_are_not_allowed()
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
+ modelBuilder.FinalizeModel();
+
Assert.StartsWith(
CoreStrings.HiLoBadBlockSize,
Assert.Throws(
@@ -204,13 +228,17 @@ public void Non_positive_block_sizes_are_not_allowed()
[ConditionalFact]
public void Block_size_is_obtained_from_specified_model_default_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.ForSqlServerUseSequenceHiLo("DaneelOlivaw")
.HasSequence("DaneelOlivaw", b => b.IncrementsBy(11))
.Entity()
.Property(e => e.Id)
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal(11, cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.IncrementBy);
@@ -219,12 +247,16 @@ public void Block_size_is_obtained_from_specified_model_default_sequence()
[ConditionalFact]
public void Sequence_name_is_obtained_from_default_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.Entity()
.Property(e => e.Id)
.ForSqlServerUseSequenceHiLo()
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal("EntityFrameworkHiLoSequence", cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.Name);
@@ -233,12 +265,16 @@ public void Sequence_name_is_obtained_from_default_sequence()
[ConditionalFact]
public void Sequence_name_is_obtained_from_named_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.Entity()
.Property(e => e.Id)
.ForSqlServerUseSequenceHiLo("DaneelOlivaw")
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal("DaneelOlivaw", cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.Name);
@@ -247,12 +283,16 @@ public void Sequence_name_is_obtained_from_named_sequence()
[ConditionalFact]
public void Sequence_name_is_obtained_from_model_default_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.ForSqlServerUseSequenceHiLo()
.Entity()
.Property(e => e.Id)
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal("EntityFrameworkHiLoSequence", cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.Name);
@@ -261,12 +301,16 @@ public void Sequence_name_is_obtained_from_model_default_sequence()
[ConditionalFact]
public void Sequence_name_is_obtained_from_named_model_default_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.ForSqlServerUseSequenceHiLo("DaneelOlivaw")
.Entity()
.Property(e => e.Id)
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal("DaneelOlivaw", cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.Name);
@@ -275,13 +319,17 @@ public void Sequence_name_is_obtained_from_named_model_default_sequence()
[ConditionalFact]
public void Sequence_name_is_obtained_from_specified_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.HasSequence("DaneelOlivaw", b => b.IncrementsBy(11))
.Entity()
.Property(e => e.Id)
.ForSqlServerUseSequenceHiLo("DaneelOlivaw")
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal("DaneelOlivaw", cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.Name);
@@ -290,13 +338,17 @@ public void Sequence_name_is_obtained_from_specified_sequence()
[ConditionalFact]
public void Sequence_name_is_obtained_from_specified_model_default_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.ForSqlServerUseSequenceHiLo("DaneelOlivaw")
.HasSequence("DaneelOlivaw", b => b.IncrementsBy(11))
.Entity()
.Property(e => e.Id)
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal("DaneelOlivaw", cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.Name);
@@ -305,12 +357,16 @@ public void Sequence_name_is_obtained_from_specified_model_default_sequence()
[ConditionalFact]
public void Schema_qualified_sequence_name_is_obtained_from_named_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.Entity()
.Property(e => e.Id)
.ForSqlServerUseSequenceHiLo("DaneelOlivaw", "R")
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal("DaneelOlivaw", cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.Name);
@@ -320,12 +376,16 @@ public void Schema_qualified_sequence_name_is_obtained_from_named_sequence()
[ConditionalFact]
public void Schema_qualified_sequence_name_is_obtained_from_named_model_default_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.ForSqlServerUseSequenceHiLo("DaneelOlivaw", "R")
.Entity()
.Property(e => e.Id)
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal("DaneelOlivaw", cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.Name);
@@ -335,13 +395,17 @@ public void Schema_qualified_sequence_name_is_obtained_from_named_model_default_
[ConditionalFact]
public void Schema_qualified_sequence_name_is_obtained_from_specified_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.HasSequence("DaneelOlivaw", "R", b => b.IncrementsBy(11))
.Entity()
.Property(e => e.Id)
.ForSqlServerUseSequenceHiLo("DaneelOlivaw", "R")
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal("DaneelOlivaw", cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.Name);
@@ -351,13 +415,17 @@ public void Schema_qualified_sequence_name_is_obtained_from_specified_sequence()
[ConditionalFact]
public void Schema_qualified_sequence_name_is_obtained_from_specified_model_default_sequence()
{
- var property = CreateConventionModelBuilder()
+ var modelBuilder = CreateConventionModelBuilder();
+
+ var property = modelBuilder
.ForSqlServerUseSequenceHiLo("DaneelOlivaw", "R")
.HasSequence("DaneelOlivaw", "R", b => b.IncrementsBy(11))
.Entity()
.Property(e => e.Id)
.Metadata;
+ modelBuilder.FinalizeModel();
+
var cache = new SqlServerValueGeneratorCache(new ValueGeneratorCacheDependencies());
Assert.Equal("DaneelOlivaw", cache.GetOrAddSequenceState(property, CreateConnection()).Sequence.Name);
diff --git a/test/EFCore.SqlServer.Tests/SqlServerValueGeneratorSelectorTest.cs b/test/EFCore.SqlServer.Tests/SqlServerValueGeneratorSelectorTest.cs
index 98cf7ca99da..b12a2c899e2 100644
--- a/test/EFCore.SqlServer.Tests/SqlServerValueGeneratorSelectorTest.cs
+++ b/test/EFCore.SqlServer.Tests/SqlServerValueGeneratorSelectorTest.cs
@@ -2,9 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Diagnostics;
-using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.SqlServer.ValueGeneration.Internal;
using Microsoft.EntityFrameworkCore.TestUtilities;
using Microsoft.EntityFrameworkCore.ValueGeneration;
@@ -20,36 +20,59 @@ public class SqlServerValueGeneratorSelectorTest
[ConditionalFact]
public void Returns_built_in_generators_for_types_setup_for_value_generation()
{
- var model = BuildModel();
+ AssertGenerator("Id");
+ AssertGenerator("Custom");
+ AssertGenerator("Long");
+ AssertGenerator("Short");
+ AssertGenerator("Byte");
+ AssertGenerator("NullableInt");
+ AssertGenerator("NullableLong");
+ AssertGenerator("NullableShort");
+ AssertGenerator("NullableByte");
+ AssertGenerator("Decimal");
+ AssertGenerator("String");
+ AssertGenerator("Guid");
+ AssertGenerator("Binary");
+ }
+
+ private void AssertGenerator(string propertyName, bool setSequences = false)
+ {
+ var builder = SqlServerTestHelpers.Instance.CreateConventionBuilder();
+ builder.Entity(
+ b =>
+ {
+ b.Property(e => e.Custom).HasValueGenerator();
+ b.Property(propertyName).ValueGeneratedOnAdd();
+ b.HasKey(propertyName);
+ });
+
+ if (setSequences)
+ {
+ builder.ForSqlServerUseSequenceHiLo();
+ Assert.NotNull(builder.Model.FindSequence(SqlServerModelExtensions.DefaultHiLoSequenceName));
+ }
+
+ var model = builder.FinalizeModel();
var entityType = model.FindEntityType(typeof(AnEntity));
var selector = SqlServerTestHelpers.Instance.CreateContextServices(model).GetRequiredService();
- Assert.IsType(selector.Select(entityType.FindProperty("Id"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("Custom"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("Long"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("Short"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("Byte"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("NullableInt"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("NullableLong"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("NullableShort"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("NullableByte"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("Decimal"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("String"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("Guid"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("Binary"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("AlwaysIdentity"), entityType));
- Assert.IsType>(selector.Select(entityType.FindProperty("AlwaysSequence"), entityType));
+ Assert.IsType(selector.Select(entityType.FindProperty(propertyName), entityType));
}
[ConditionalFact]
public void Returns_temp_guid_generator_when_default_sql_set()
{
- var model = BuildModel();
+ var builder = SqlServerTestHelpers.Instance.CreateConventionBuilder();
+ builder.Entity(
+ b =>
+ {
+ b.Property(e => e.Guid).HasDefaultValueSql("newid()");
+ b.HasKey(e => e.Guid);
+ });
+ var model = builder.FinalizeModel();
var entityType = model.FindEntityType(typeof(AnEntity));
- entityType.FindProperty("Guid").SetDefaultValueSql("newid()");
-
var selector = SqlServerTestHelpers.Instance.CreateContextServices(model).GetRequiredService();
Assert.IsType(selector.Select(entityType.FindProperty("Guid"), entityType));
@@ -58,11 +81,16 @@ public void Returns_temp_guid_generator_when_default_sql_set()
[ConditionalFact]
public void Returns_temp_string_generator_when_default_sql_set()
{
- var model = BuildModel();
+ var builder = SqlServerTestHelpers.Instance.CreateConventionBuilder();
+ builder.Entity(
+ b =>
+ {
+ b.Property(e => e.String).ValueGeneratedOnAdd().HasDefaultValueSql("Foo");
+ b.HasKey(e => e.String);
+ });
+ var model = builder.FinalizeModel();
var entityType = model.FindEntityType(typeof(AnEntity));
- entityType.FindProperty("String").SetDefaultValueSql("Foo");
-
var selector = SqlServerTestHelpers.Instance.CreateContextServices(model).GetRequiredService();
var generator = selector.Select(entityType.FindProperty("String"), entityType);
@@ -73,11 +101,16 @@ public void Returns_temp_string_generator_when_default_sql_set()
[ConditionalFact]
public void Returns_temp_binary_generator_when_default_sql_set()
{
- var model = BuildModel();
+ var builder = SqlServerTestHelpers.Instance.CreateConventionBuilder();
+ builder.Entity(
+ b =>
+ {
+ b.HasKey(e => e.Binary);
+ b.Property(e => e.Binary).HasDefaultValueSql("Foo").ValueGeneratedOnAdd();
+ });
+ var model = builder.FinalizeModel();
var entityType = model.FindEntityType(typeof(AnEntity));
- entityType.FindProperty("Binary").SetDefaultValueSql("Foo");
-
var selector = SqlServerTestHelpers.Instance.CreateContextServices(model).GetRequiredService();
var generator = selector.Select(entityType.FindProperty("Binary"), entityType);
@@ -88,82 +121,58 @@ public void Returns_temp_binary_generator_when_default_sql_set()
[ConditionalFact]
public void Returns_sequence_value_generators_when_configured_for_model()
{
- var model = BuildModel();
- model.SetSqlServerValueGenerationStrategy(SqlServerValueGenerationStrategy.SequenceHiLo);
- model.FindSequence(SqlServerModelExtensions.DefaultHiLoSequenceName);
- var entityType = model.FindEntityType(typeof(AnEntity));
-
- var selector = SqlServerTestHelpers.Instance.CreateContextServices(model).GetRequiredService();
-
- Assert.IsType>(selector.Select(entityType.FindProperty("Id"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("Custom"), entityType));
- Assert.IsType>(selector.Select(entityType.FindProperty("Long"), entityType));
- Assert.IsType>(selector.Select(entityType.FindProperty("Short"), entityType));
- Assert.IsType>(selector.Select(entityType.FindProperty("Byte"), entityType));
- Assert.IsType>(selector.Select(entityType.FindProperty("NullableInt"), entityType));
- Assert.IsType>(selector.Select(entityType.FindProperty("NullableLong"), entityType));
- Assert.IsType>(
- selector.Select(entityType.FindProperty("NullableShort"), entityType));
- Assert.IsType>(selector.Select(entityType.FindProperty("NullableByte"), entityType));
- Assert.IsType>(selector.Select(entityType.FindProperty("Decimal"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("String"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("Guid"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("Binary"), entityType));
- Assert.IsType(selector.Select(entityType.FindProperty("AlwaysIdentity"), entityType));
- Assert.IsType>(selector.Select(entityType.FindProperty("AlwaysSequence"), entityType));
+ AssertGenerator>("Id", setSequences: true);
+ AssertGenerator("Custom", setSequences: true);
+ AssertGenerator>("Long", setSequences: true);
+ AssertGenerator>("Short", setSequences: true);
+ AssertGenerator>("Byte", setSequences: true);
+ AssertGenerator>("NullableInt", setSequences: true);
+ AssertGenerator>("NullableLong", setSequences: true);
+ AssertGenerator>("NullableShort", setSequences: true);
+ AssertGenerator>("NullableByte", setSequences: true);
+ AssertGenerator>("Decimal", setSequences: true);
+ AssertGenerator("String", setSequences: true);
+ AssertGenerator("Guid", setSequences: true);
+ AssertGenerator("Binary", setSequences: true);
}
[ConditionalFact]
public void Throws_for_unsupported_combinations()
{
- var model = BuildModel();
+ var builder = InMemoryTestHelpers.Instance.CreateConventionBuilder();
+ builder.Entity(
+ b =>
+ {
+ b.Property(e => e.Random).ValueGeneratedOnAdd();
+ b.HasKey(e => e.Random);
+ });
+ var model = builder.FinalizeModel();
var entityType = model.FindEntityType(typeof(AnEntity));
- var selector = SqlServerTestHelpers.Instance.CreateContextServices(model).GetRequiredService();
+ var selector = InMemoryTestHelpers.Instance.CreateContextServices(model).GetRequiredService();
Assert.Equal(
- CoreStrings.NoValueGenerator("Random", "AnEntity", typeof(Random).Name),
+ CoreStrings.NoValueGenerator("Random", "AnEntity", "Something"),
Assert.Throws(() => selector.Select(entityType.FindProperty("Random"), entityType)).Message);
}
[ConditionalFact]
public void Returns_generator_configured_on_model_when_property_is_identity()
- {
- var model = SqlServerTestHelpers.Instance.BuildModelFor();
- model.SetSqlServerValueGenerationStrategy(SqlServerValueGenerationStrategy.SequenceHiLo);
- model.AddSequence(SqlServerModelExtensions.DefaultHiLoSequenceName);
- var entityType = model.FindEntityType(typeof(AnEntity));
-
- var selector = SqlServerTestHelpers.Instance.CreateContextServices(model).GetRequiredService();
-
- Assert.IsType>(selector.Select(entityType.FindProperty("Id"), entityType));
- }
-
- private static IMutableModel BuildModel(bool generateValues = true)
{
var builder = SqlServerTestHelpers.Instance.CreateConventionBuilder();
- builder.Ignore();
- builder.Entity().Property(e => e.Custom).HasValueGenerator();
+ builder.Entity();
- var model = builder.Model;
- model.AddSequence(SqlServerModelExtensions.DefaultHiLoSequenceName);
+ builder
+ .ForSqlServerUseSequenceHiLo()
+ .HasSequence(SqlServerModelExtensions.DefaultHiLoSequenceName);
+ var model = builder.ForSqlServerUseSequenceHiLo().FinalizeModel();
var entityType = model.FindEntityType(typeof(AnEntity));
- entityType.AddProperty("Random", typeof(Random));
-
- foreach (var property in entityType.GetProperties())
- {
- property.ValueGenerated = generateValues ? ValueGenerated.OnAdd : ValueGenerated.Never;
- }
-
- entityType.FindProperty("AlwaysIdentity").ValueGenerated = ValueGenerated.OnAdd;
- entityType.FindProperty("AlwaysIdentity").SetSqlServerValueGenerationStrategy(SqlServerValueGenerationStrategy.IdentityColumn);
- entityType.FindProperty("AlwaysSequence").ValueGenerated = ValueGenerated.OnAdd;
- entityType.FindProperty("AlwaysSequence").SetSqlServerValueGenerationStrategy(SqlServerValueGenerationStrategy.SequenceHiLo);
+ var selector = SqlServerTestHelpers.Instance.CreateContextServices(model).GetRequiredService();
- return model;
+ Assert.IsType>(selector.Select(entityType.FindProperty("Id"), entityType));
}
private class AnEntity
@@ -182,18 +191,19 @@ private class AnEntity
public byte[] Binary { get; set; }
public float Float { get; set; }
public decimal Decimal { get; set; }
- public int AlwaysIdentity { get; set; }
- public int AlwaysSequence { get; set; }
- public Random Random { get; set; }
+
+ [NotMapped]
+ public Something Random { get; set; }
}
- private class CustomValueGenerator : ValueGenerator
+ private struct Something
{
- public override int Next(EntityEntry entry)
- {
- throw new NotImplementedException();
- }
+ public int Id { get; set; }
+ }
+ private class CustomValueGenerator : ValueGenerator
+ {
+ public override int Next(EntityEntry entry) => throw new NotImplementedException();
public override bool GeneratesTemporaryValues => false;
}
}
diff --git a/test/EFCore.Sqlite.FunctionalTests/DataAnnotationSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/DataAnnotationSqliteTest.cs
index 310a8b25db7..3bf8a2428a2 100644
--- a/test/EFCore.Sqlite.FunctionalTests/DataAnnotationSqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/DataAnnotationSqliteTest.cs
@@ -62,7 +62,7 @@ public override ModelBuilder Key_and_MaxLength_64_produce_nvarchar_64()
var property = GetProperty(modelBuilder, "PersonFirstName");
- var storeType = property.FindRelationalMapping().StoreType;
+ var storeType = property.GetRelationalTypeMapping().StoreType;
Assert.Equal("TEXT", storeType);
@@ -75,7 +75,7 @@ public override ModelBuilder Timestamp_takes_precedence_over_MaxLength()
var property = GetProperty(modelBuilder, "MaxTimestamp");
- var storeType = property.FindRelationalMapping().StoreType;
+ var storeType = property.GetRelationalTypeMapping().StoreType;
Assert.Equal("BLOB", storeType);
diff --git a/test/EFCore.Sqlite.Tests/Migrations/SqliteMigrationAnnotationProviderTest.cs b/test/EFCore.Sqlite.Tests/Migrations/SqliteMigrationAnnotationProviderTest.cs
index 987a9489e86..25774450efb 100644
--- a/test/EFCore.Sqlite.Tests/Migrations/SqliteMigrationAnnotationProviderTest.cs
+++ b/test/EFCore.Sqlite.Tests/Migrations/SqliteMigrationAnnotationProviderTest.cs
@@ -27,6 +27,7 @@ public SqliteMigrationAnnotationProviderTest()
public void Adds_Autoincrement_for_OnAdd_integer_property()
{
var property = _modelBuilder.Entity().Property(e => e.IntProp).ValueGeneratedOnAdd().Metadata;
+ _modelBuilder.FinalizeModel();
Assert.Contains(_provider.For(property), a => a.Name == _autoincrement.Name && (bool)a.Value);
}
@@ -35,6 +36,7 @@ public void Adds_Autoincrement_for_OnAdd_integer_property()
public void Does_not_add_Autoincrement_for_OnAddOrUpdate_integer_property()
{
var property = _modelBuilder.Entity().Property(e => e.IntProp).ValueGeneratedOnAddOrUpdate().Metadata;
+ _modelBuilder.FinalizeModel();
Assert.DoesNotContain(_provider.For(property), a => a.Name == _autoincrement.Name);
}
@@ -43,6 +45,7 @@ public void Does_not_add_Autoincrement_for_OnAddOrUpdate_integer_property()
public void Does_not_add_Autoincrement_for_OnUpdate_integer_property()
{
var property = _modelBuilder.Entity().Property(e => e.IntProp).ValueGeneratedOnUpdate().Metadata;
+ _modelBuilder.FinalizeModel();
Assert.DoesNotContain(_provider.For(property), a => a.Name == _autoincrement.Name);
}
@@ -51,6 +54,7 @@ public void Does_not_add_Autoincrement_for_OnUpdate_integer_property()
public void Does_not_add_Autoincrement_for_Never_value_generated_integer_property()
{
var property = _modelBuilder.Entity().Property(e => e.IntProp).ValueGeneratedNever().Metadata;
+ _modelBuilder.FinalizeModel();
Assert.DoesNotContain(_provider.For(property), a => a.Name == _autoincrement.Name);
}
@@ -59,6 +63,7 @@ public void Does_not_add_Autoincrement_for_Never_value_generated_integer_propert
public void Does_not_add_Autoincrement_for_default_integer_property()
{
var property = _modelBuilder.Entity().Property(e => e.IntProp).Metadata;
+ _modelBuilder.FinalizeModel();
Assert.DoesNotContain(_provider.For(property), a => a.Name == _autoincrement.Name);
}
@@ -67,6 +72,7 @@ public void Does_not_add_Autoincrement_for_default_integer_property()
public void Does_not_add_Autoincrement_for_non_integer_OnAdd_property()
{
var property = _modelBuilder.Entity().Property(e => e.StringProp).ValueGeneratedOnAdd().Metadata;
+ _modelBuilder.FinalizeModel();
Assert.DoesNotContain(_provider.For(property), a => a.Name == _autoincrement.Name);
}
diff --git a/test/EFCore.Tests/ChangeTracking/Internal/InternalClrEntityEntryTest.cs b/test/EFCore.Tests/ChangeTracking/Internal/InternalClrEntityEntryTest.cs
index 20f34dbd465..3f935ad5eda 100644
--- a/test/EFCore.Tests/ChangeTracking/Internal/InternalClrEntityEntryTest.cs
+++ b/test/EFCore.Tests/ChangeTracking/Internal/InternalClrEntityEntryTest.cs
@@ -1,103 +1,190 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using Microsoft.EntityFrameworkCore.Storage;
-using Microsoft.EntityFrameworkCore.TestUtilities;
-using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using Microsoft.EntityFrameworkCore.Infrastructure;
using Xunit;
// ReSharper disable InconsistentNaming
namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal
{
- public class InternalClrEntityEntryTest : InternalEntityEntryTestBase
+ public class InternalClrEntityEntryTest : InternalEntityEntryTestBase<
+ InternalClrEntityEntryTest.SomeEntity,
+ InternalClrEntityEntryTest.SomeSimpleEntityBase,
+ InternalClrEntityEntryTest.SomeDependentEntity,
+ InternalClrEntityEntryTest.SomeMoreDependentEntity,
+ InternalClrEntityEntryTest.Root,
+ InternalClrEntityEntryTest.FirstDependent,
+ InternalClrEntityEntryTest.SecondDependent,
+ InternalClrEntityEntryTest.CompositeRoot,
+ InternalClrEntityEntryTest.CompositeFirstDependent,
+ InternalClrEntityEntryTest.SomeCompositeEntityBase,
+ InternalClrEntityEntryTest.CompositeSecondDependent,
+ InternalClrEntityEntryTest.KClrContext,
+ InternalClrEntityEntryTest.KClrSnapContext>
{
[ConditionalFact]
- public void Can_get_entity()
- {
- var model = BuildModel();
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
+ public virtual void All_original_values_can_be_accessed_for_entity_that_does_full_change_tracking_if_eager_values_on()
+ => AllOriginalValuesTest(new FullNotificationEntity());
- var entity = new SomeEntity();
- var entry = CreateInternalEntry(configuration, model.FindEntityType(typeof(SomeEntity).FullName), entity);
+ [ConditionalFact]
+ public virtual void Required_original_values_can_be_accessed_for_entity_that_does_full_change_tracking()
+ => OriginalValuesTest(new FullNotificationEntity());
- Assert.Same(entity, entry.Entity);
- }
+ [ConditionalFact]
+ public virtual void Required_original_values_can_be_accessed_for_entity_that_does_changed_only_notification()
+ => OriginalValuesTest(new ChangedOnlyEntity());
[ConditionalFact]
- public void Can_set_and_get_property_value_from_CLR_object()
- {
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var nonKeyProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
+ public virtual void Required_original_values_can_be_accessed_generically_for_entity_that_does_full_change_tracking()
+ => GenericOriginalValuesTest(new FullNotificationEntity());
- var entity = new SomeEntity
- {
- Id = 77,
- Name = "Magic Tree House"
- };
- var entry = CreateInternalEntry(configuration, entityType, entity);
+ [ConditionalFact]
+ public virtual void Required_original_values_can_be_accessed_generically_for_entity_that_does_changed_only_notification()
+ => GenericOriginalValuesTest(new ChangedOnlyEntity());
+
+ [ConditionalFact]
+ public virtual void Null_original_values_are_handled_for_entity_that_does_full_change_tracking()
+ => NullOriginalValuesTest(new FullNotificationEntity());
- Assert.Equal(77, entry[keyProperty]);
- Assert.Equal("Magic Tree House", entry[nonKeyProperty]);
+ [ConditionalFact]
+ public virtual void Null_original_values_are_handled_for_entity_that_does_changed_only_notification()
+ => NullOriginalValuesTest(new ChangedOnlyEntity());
- entry[keyProperty] = 78;
- entry[nonKeyProperty] = "Normal Tree House";
+ [ConditionalFact]
+ public virtual void Null_original_values_are_handled_generically_for_entity_that_does_full_change_tracking()
+ => GenericNullOriginalValuesTest(new FullNotificationEntity());
- Assert.Equal(78, entity.Id);
- Assert.Equal("Normal Tree House", entity.Name);
- }
+ [ConditionalFact]
+ public virtual void Null_original_values_are_handled_generically_for_entity_that_does_changed_only_notification()
+ => GenericNullOriginalValuesTest(new ChangedOnlyEntity());
+
+ [ConditionalFact]
+ public virtual void Setting_property_using_state_entry_always_marks_as_modified_full_notifications()
+ => SetPropertyInternalEntityEntryTest(new FullNotificationEntity());
+
+ [ConditionalFact]
+ public virtual void Setting_property_using_state_entry_always_marks_as_modified_changed_notifications()
+ => SetPropertyInternalEntityEntryTest(new ChangedOnlyEntity());
+
+ [ConditionalFact]
+ public void All_original_values_can_be_accessed_for_entity_that_does_changed_only_notifications()
+ => AllOriginalValuesTest(new ChangedOnlyEntity());
[ConditionalFact]
- public void Asking_for_entity_instance_causes_it_to_be_materialized()
+ public virtual void Temporary_values_are_not_reset_when_entity_is_detached()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
+ using (var context = new KClrContext())
+ {
+ var entity = new SomeEntity();
+ var entry = context.Add(entity).GetInfrastructure();
+ var keyProperty = entry.EntityType.FindProperty("Id");
- var entry = CreateInternalEntry(
- configuration,
- entityType,
- new SomeEntity
- {
- Id = 1,
- Name = "Kool"
- },
- new ValueBuffer(new object[] { 1, "Kool" }));
+ entry.SetEntityState(EntityState.Added);
+ entry.SetTemporaryValue(keyProperty, -1);
+
+ Assert.NotNull(entry[keyProperty]);
+ Assert.Equal(0, entity.Id);
+ Assert.Equal(-1, entry[keyProperty]);
+
+ entry.SetEntityState(EntityState.Detached);
- var entity = (SomeEntity)entry.Entity;
+ Assert.Equal(0, entity.Id);
+ Assert.Equal(-1, entry[keyProperty]);
- Assert.Equal(1, entity.Id);
- Assert.Equal("Kool", entity.Name);
+ entry.SetEntityState(EntityState.Added);
+
+ Assert.Equal(0, entity.Id);
+ Assert.Equal(-1, entry[keyProperty]);
+ }
}
- [ConditionalFact]
- public void All_original_values_can_be_accessed_for_entity_that_does_no_notification()
+ [ConditionalTheory]
+ [InlineData(EntityState.Unchanged)]
+ [InlineData(EntityState.Detached)]
+ [InlineData(EntityState.Modified)]
+ [InlineData(EntityState.Added)]
+ [InlineData(EntityState.Deleted)]
+ public void AcceptChanges_handles_different_entity_states_for_owned_types(EntityState entityState)
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
+ using (var context = new KClrContext())
+ {
+ var ownerEntry = context.Entry(
+ new OwnerClass
+ {
+ Id = 1,
+ Owned = new OwnedClass
+ {
+ Value = "Kool"
+ }
+ }).GetInfrastructure();
+
+ var entry = context.Entry(((OwnerClass)ownerEntry.Entity).Owned).GetInfrastructure();
+ var valueProperty = entry.EntityType.FindProperty(nameof(OwnedClass.Value));
+
+ entry.SetEntityState(entityState);
+
+ if (entityState != EntityState.Unchanged)
+ {
+ entry[valueProperty] = "Pickle";
+ }
+
+ entry.SetOriginalValue(valueProperty, "Cheese");
- AllOriginalValuesTest(
- model, entityType, new SomeEntity
+ entry.AcceptChanges();
+
+ Assert.Equal(
+ entityState == EntityState.Deleted || entityState == EntityState.Detached
+ ? EntityState.Detached
+ : EntityState.Unchanged,
+ entry.EntityState);
+ if (entityState == EntityState.Unchanged)
{
- Id = 1,
- Name = "Kool"
- });
+ Assert.Equal("Kool", entry[valueProperty]);
+ Assert.Equal("Kool", entry.GetOriginalValue(valueProperty));
+ }
+ else
+ {
+ Assert.Equal("Pickle", entry[valueProperty]);
+ Assert.Equal(
+ entityState == EntityState.Detached || entityState == EntityState.Deleted ? "Cheese" : "Pickle",
+ entry.GetOriginalValue(valueProperty));
+ }
+ }
}
[ConditionalFact]
- public void All_original_values_can_be_accessed_for_entity_that_does_changed_only_notifications()
+ public void Setting_an_explicit_value_on_the_entity_marks_property_as_not_temporary()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(ChangedOnlyEntity).FullName);
+ using (var context = new KClrContext())
+ {
+ var entry = context.Entry(new SomeEntity()).GetInfrastructure();
+ var keyProperty = entry.EntityType.FindProperty("Id");
- AllOriginalValuesTest(
- model, entityType, new ChangedOnlyEntity
- {
- Id = 1,
- Name = "Kool"
- });
+ var entity = (SomeEntity)entry.Entity;
+
+ entry.SetEntityState(EntityState.Added);
+ entry.SetTemporaryValue(keyProperty, -1);
+
+ Assert.True(entry.HasTemporaryValue(keyProperty));
+
+ entity.Id = 77;
+
+ context.GetService().DetectChanges(entry);
+
+ Assert.False(entry.HasTemporaryValue(keyProperty));
+
+ entry.SetEntityState(EntityState.Unchanged); // Does not throw
+
+ var nameProperty = entry.EntityType.FindProperty(nameof(SomeEntity.Name));
+ Assert.True(entry.HasDefaultValue(nameProperty));
+
+ entity.Name = "Name";
+
+ Assert.False(entry.HasDefaultValue(nameProperty));
+ }
}
[ConditionalFact]
@@ -127,37 +214,311 @@ public void Setting_CLR_property_with_full_notifications_does_not_require_Detect
Name = "Kool"
}, needsDetectChanges: false);
- [ConditionalFact]
- public void Setting_an_explicit_value_on_the_entity_marks_property_as_not_temporary()
+ private void SetPropertyClrTest(TEntity entity, bool needsDetectChanges)
+ where TEntity : class, ISomeEntity
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
+ using (var context = new KClrContext())
+ {
+ var entry = context.Attach(entity).GetInfrastructure();
+ var nameProperty = entry.EntityType.FindProperty("Name");
- var entry = CreateInternalEntry(configuration, entityType, new SomeEntity());
+ Assert.False(entry.IsModified(nameProperty));
+ Assert.Equal(EntityState.Unchanged, entry.EntityState);
- var entity = (SomeEntity)entry.Entity;
+ entity.Name = "Kool";
- entry.SetEntityState(EntityState.Added);
- entry.SetTemporaryValue(keyProperty, -1);
+ Assert.False(entry.IsModified(nameProperty));
+ Assert.Equal(EntityState.Unchanged, entry.EntityState);
- Assert.True(entry.HasTemporaryValue(keyProperty));
+ entity.Name = "Beans";
- entity.Id = 77;
+ if (needsDetectChanges)
+ {
+ Assert.False(entry.IsModified(nameProperty));
+ Assert.Equal(EntityState.Unchanged, entry.EntityState);
- configuration.GetRequiredService().DetectChanges(entry);
+ context.GetService().DetectChanges(entry);
+ }
- Assert.False(entry.HasTemporaryValue(keyProperty));
+ Assert.True(entry.IsModified(nameProperty));
+ Assert.Equal(EntityState.Modified, entry.EntityState);
+ }
+ }
- entry.SetEntityState(EntityState.Unchanged); // Does not throw
+ public class SomeCompositeEntityBase
+ {
+ public int Id1 { get; set; }
+ public string Id2 { get; set; }
+ }
- var nameProperty = entityType.FindProperty(nameof(SomeEntity.Name));
- Assert.True(entry.HasDefaultValue(nameProperty));
+ public class SomeDependentEntity : SomeCompositeEntityBase
+ {
+ public int SomeEntityId { get; set; }
+ public int JustAProperty { get; set; }
+ }
- entity.Name = "Name";
+ public class SomeMoreDependentEntity : SomeSimpleEntityBase
+ {
+ public int Fk1 { get; set; }
+ public string Fk2 { get; set; }
+ }
- Assert.False(entry.HasDefaultValue(nameProperty));
+ public class FullNotificationEntity : INotifyPropertyChanging, INotifyPropertyChanged, ISomeEntity
+ {
+ private int _id;
+ private string _name;
+
+ public int Id
+ {
+ get => _id;
+ set
+ {
+ if (_id != value)
+ {
+ NotifyChanging();
+ _id = value;
+ NotifyChanged();
+ }
+ }
+ }
+
+ public string Name
+ {
+ get => _name;
+ set
+ {
+ if (_name != value)
+ {
+ NotifyChanging();
+ _name = value;
+ NotifyChanged();
+ }
+ }
+ }
+
+ public event PropertyChangingEventHandler PropertyChanging;
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ private void NotifyChanged([CallerMemberName] string propertyName = "")
+ => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+
+ private void NotifyChanging([CallerMemberName] string propertyName = "")
+ => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
+ }
+
+ public class ChangedOnlyEntity : INotifyPropertyChanged, ISomeEntity
+ {
+ private int _id;
+ private string _name;
+
+ public int Id
+ {
+ get => _id;
+ set
+ {
+ if (_id != value)
+ {
+ _id = value;
+ NotifyChanged();
+ }
+ }
+ }
+
+ public string Name
+ {
+ get => _name;
+ set
+ {
+ if (_name != value)
+ {
+ _name = value;
+ NotifyChanged();
+ }
+ }
+ }
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ private void NotifyChanged([CallerMemberName] string propertyName = "")
+ => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+
+ public class Root : IRoot
+ {
+ public int Id { get; set; }
+
+ public FirstDependent First { get; set; }
+
+ IFirstDependent IRoot.First
+ {
+ get => First;
+ set => First = (FirstDependent)value;
+ }
+ }
+
+ public class FirstDependent : IFirstDependent
+ {
+ public int Id { get; set; }
+
+ public Root Root { get; set; }
+
+ IRoot IFirstDependent.Root
+ {
+ get => Root;
+ set => Root = (Root)value;
+ }
+
+ public SecondDependent Second { get; set; }
+
+ ISecondDependent IFirstDependent.Second
+ {
+ get => Second;
+ set => Second = (SecondDependent)value;
+ }
+ }
+
+ public class SecondDependent : ISecondDependent
+ {
+ public int Id { get; set; }
+
+ public FirstDependent First { get; set; }
+
+ IFirstDependent ISecondDependent.First
+ {
+ get => First;
+ set => First = (FirstDependent)value;
+ }
+ }
+
+ public class CompositeRoot : ICompositeRoot
+ {
+ public int Id1 { get; set; }
+ public string Id2 { get; set; }
+
+ public ICompositeFirstDependent First { get; set; }
+ }
+
+ public class CompositeFirstDependent : ICompositeFirstDependent
+ {
+ public int Id1 { get; set; }
+ public string Id2 { get; set; }
+
+ public int RootId1 { get; set; }
+ public string RootId2 { get; set; }
+
+ public CompositeRoot Root { get; set; }
+
+ ICompositeRoot ICompositeFirstDependent.Root
+ {
+ get => Root;
+ set => Root = (CompositeRoot)value;
+ }
+
+ public CompositeSecondDependent Second { get; set; }
+
+ ICompositeSecondDependent ICompositeFirstDependent.Second
+ {
+ get => Second;
+ set => Second = (CompositeSecondDependent)value;
+ }
+ }
+
+ public class CompositeSecondDependent : ICompositeSecondDependent
+ {
+ public int Id1 { get; set; }
+ public string Id2 { get; set; }
+
+ public int FirstId1 { get; set; }
+ public string FirstId2 { get; set; }
+
+ public CompositeFirstDependent First { get; set; }
+
+ ICompositeFirstDependent ICompositeSecondDependent.First
+ {
+ get => First;
+ set => First = (CompositeFirstDependent)value;
+ }
+ }
+
+ public class OwnerClass
+ {
+ public int Id { get; set; }
+ public virtual OwnedClass Owned { get; set; }
+ }
+
+ public class OwnedClass
+ {
+ public string Value { get; set; }
+ }
+
+ public interface ISomeEntity
+ {
+ int Id { get; set; }
+ string Name { get; set; }
+ }
+
+ public class SomeSimpleEntityBase
+ {
+ public int Id { get; set; }
+ }
+
+ public class SomeEntity : SomeSimpleEntityBase, ISomeEntity
+ {
+ public string Name { get; set; }
+ }
+
+ public class KClrContext : KContext
+ {
+ protected internal override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ base.OnModelCreating(modelBuilder);
+
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property(e => e.Name).IsConcurrencyToken();
+ b.HasChangeTrackingStrategy(ChangeTrackingStrategy.ChangingAndChangedNotifications);
+ });
+
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property(e => e.Name).IsConcurrencyToken();
+ b.HasChangeTrackingStrategy(ChangeTrackingStrategy.ChangedNotifications);
+ });
+
+ modelBuilder.Entity(
+ eb =>
+ {
+ eb.HasKey(e => e.Id);
+ var owned = eb.OwnsOne(e => e.Owned);
+ owned.WithOwner().HasForeignKey("Id");
+ owned.HasKey("Id");
+ owned.Property(e => e.Value);
+ });
+ }
+ }
+
+ public class KClrSnapContext : KContext
+ {
+ protected internal override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ base.OnModelCreating(modelBuilder);
+
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property(e => e.Name).IsConcurrencyToken();
+ b.HasChangeTrackingStrategy(ChangeTrackingStrategy.ChangingAndChangedNotificationsWithOriginalValues);
+ });
+
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property(e => e.Name).IsConcurrencyToken();
+ b.HasChangeTrackingStrategy(ChangeTrackingStrategy.ChangedNotifications);
+ });
+ }
}
}
}
diff --git a/test/EFCore.Tests/ChangeTracking/Internal/InternalEntityEntryTestBase.cs b/test/EFCore.Tests/ChangeTracking/Internal/InternalEntityEntryTestBase.cs
index 10156877a11..d2d08463a97 100644
--- a/test/EFCore.Tests/ChangeTracking/Internal/InternalEntityEntryTestBase.cs
+++ b/test/EFCore.Tests/ChangeTracking/Internal/InternalEntityEntryTestBase.cs
@@ -3,18 +3,12 @@
using System;
using System.Collections.Generic;
-using System.ComponentModel;
using System.Linq;
-using System.Runtime.CompilerServices;
using Microsoft.EntityFrameworkCore.Diagnostics;
-using Microsoft.EntityFrameworkCore.Internal;
-using Microsoft.EntityFrameworkCore.Metadata;
-using Microsoft.EntityFrameworkCore.Metadata.Conventions;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.InMemory.ValueGeneration.Internal;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
-using Microsoft.EntityFrameworkCore.Storage;
-using Microsoft.EntityFrameworkCore.TestUtilities;
using Microsoft.EntityFrameworkCore.Update;
-using Microsoft.Extensions.DependencyInjection;
using Xunit;
// ReSharper disable UnusedMember.Global
@@ -23,213 +17,229 @@
// ReSharper disable InconsistentNaming
namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal
{
- public abstract class InternalEntityEntryTestBase
+ public abstract class InternalEntityEntryTestBase<
+ TSomeEntity,
+ TSomeSimpleEntityBase,
+ TSomeDependentEntity,
+ TSomeMoreDependentEntity,
+ TRoot,
+ TFirstDependent,
+ TSecondDependent,
+ TCompositeRoot,
+ TCompositeFirstDependent,
+ TSomeCompositeEntityBase,
+ TCompositeSecondDependent,
+ TKContext,
+ TKSnapContext>
+ where TSomeEntity : class, new()
+ where TSomeSimpleEntityBase : class, new()
+ where TSomeDependentEntity : class, new()
+ where TSomeMoreDependentEntity : class, new()
+ where TRoot : class, IRoot, new()
+ where TFirstDependent: class, IFirstDependent, new()
+ where TCompositeRoot : class, ICompositeRoot, new()
+ where TCompositeFirstDependent: class, ICompositeFirstDependent, new()
+ where TSecondDependent : class, ISecondDependent, new()
+ where TSomeCompositeEntityBase : class, new()
+ where TCompositeSecondDependent : class, ICompositeSecondDependent, new()
+ where TKContext : DbContext, new()
+ where TKSnapContext : DbContext, new()
{
[ConditionalFact]
public virtual void Store_setting_null_for_non_nullable_store_generated_property_throws()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- keyProperty.ValueGenerated = ValueGenerated.OnAdd;
-
- var contextServices = InMemoryTestHelpers.Instance.CreateContextServices(model);
+ using (var context = new TKContext())
+ {
+ var entry = context.Add(new TSomeEntity()).GetInfrastructure();
+ var keyProperty = entry.EntityType.FindProperty("Id");
- var entry = CreateInternalEntry(contextServices, entityType, new SomeEntity());
- entry.SetEntityState(EntityState.Added);
- entry.PrepareToSave();
+ entry.PrepareToSave();
- Assert.Equal(
- CoreStrings.ValueCannotBeNull("Id", keyProperty.DeclaringEntityType.DisplayName(), typeof(int).DisplayName()),
- Assert.Throws(() => entry.SetStoreGeneratedValue(keyProperty, null)).Message);
+ Assert.Equal(
+ CoreStrings.ValueCannotBeNull("Id", "SomeSimpleEntityBase", "int"),
+ Assert.Throws(
+ () => entry.SetStoreGeneratedValue(keyProperty, null)).Message);
+ }
}
[ConditionalFact]
public virtual void Changing_state_from_Unknown_causes_entity_to_start_tracking()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
-
- var contextServices = InMemoryTestHelpers.Instance.CreateContextServices(model);
+ using (var context = new TKContext())
+ {
+ var entry = context.Entry(new TSomeEntity()).GetInfrastructure();
+ var keyProperty = entry.EntityType.FindProperty("Id");
- var entry = CreateInternalEntry(contextServices, entityType, new SomeEntity());
- entry[keyProperty] = 1;
+ entry[keyProperty] = 1;
- entry.SetEntityState(EntityState.Added);
+ entry.SetEntityState(EntityState.Added);
- Assert.Equal(EntityState.Added, entry.EntityState);
- Assert.Contains(entry, contextServices.GetRequiredService().Entries);
+ Assert.Equal(EntityState.Added, entry.EntityState);
+ Assert.Contains(entry, context.GetService().Entries);
+ }
}
[ConditionalFact]
public virtual void Changing_state_to_Unknown_causes_entity_to_stop_tracking()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
-
- var contextServices = InMemoryTestHelpers.Instance.CreateContextServices(model);
+ using (var context = new TKContext())
+ {
+ var entry = context.Entry(new TSomeEntity()).GetInfrastructure();
+ var keyProperty = entry.EntityType.FindProperty("Id");
- var entry = CreateInternalEntry(contextServices, entityType, new SomeEntity());
- entry[keyProperty] = 1;
+ entry[keyProperty] = 1;
- entry.SetEntityState(EntityState.Added);
- entry.SetEntityState(EntityState.Detached);
+ entry.SetEntityState(EntityState.Added);
+ entry.SetEntityState(EntityState.Detached);
- Assert.Equal(EntityState.Detached, entry.EntityState);
- Assert.DoesNotContain(entry, contextServices.GetRequiredService().Entries);
+ Assert.Equal(EntityState.Detached, entry.EntityState);
+ Assert.DoesNotContain(entry, context.GetService().Entries);
+ }
}
[ConditionalFact] // GitHub #251, #1247
public virtual void Changing_state_from_Added_to_Deleted_does_what_you_ask()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
-
- var contextServices = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(contextServices, entityType, new SomeEntity());
- entry[keyProperty] = 1;
+ using (var context = new TKContext())
+ {
+ var entry = context.Add(new TSomeEntity()).GetInfrastructure();
- entry.SetEntityState(EntityState.Added);
- entry.SetEntityState(EntityState.Deleted);
+ entry.SetEntityState(EntityState.Added);
+ entry.SetEntityState(EntityState.Deleted);
- Assert.Equal(EntityState.Deleted, entry.EntityState);
- Assert.Contains(entry, contextServices.GetRequiredService().Entries);
+ Assert.Equal(EntityState.Deleted, entry.EntityState);
+ Assert.Contains(entry, context.GetService().Entries);
+ }
}
[ConditionalFact]
public virtual void Changing_state_to_Modified_or_Unchanged_causes_all_properties_to_be_marked_accordingly()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var nonKeyProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
+ using (var context = new TKContext())
+ {
+ var entry = context.Add(new TSomeEntity()).GetInfrastructure();
- var entry = CreateInternalEntry(configuration, entityType, new SomeEntity());
- entry[keyProperty] = 1;
+ var keyProperty = entry.EntityType.FindProperty("Id");
+ var nonKeyProperty = entry.EntityType.FindProperty("Name");
- Assert.False(entry.IsModified(keyProperty));
- Assert.False(entry.IsModified(nonKeyProperty));
+ Assert.False(entry.IsModified(keyProperty));
+ Assert.False(entry.IsModified(nonKeyProperty));
- entry.SetEntityState(EntityState.Modified);
+ entry.SetEntityState(EntityState.Modified);
- Assert.False(entry.IsModified(keyProperty));
- Assert.NotEqual(nonKeyProperty.IsShadowProperty(), entry.IsModified(nonKeyProperty));
+ Assert.False(entry.IsModified(keyProperty));
+ Assert.NotEqual(nonKeyProperty.IsShadowProperty(), entry.IsModified(nonKeyProperty));
- entry.SetEntityState(EntityState.Unchanged, true);
+ entry.SetEntityState(EntityState.Unchanged, true);
- Assert.False(entry.IsModified(keyProperty));
- Assert.False(entry.IsModified(nonKeyProperty));
+ Assert.False(entry.IsModified(keyProperty));
+ Assert.False(entry.IsModified(nonKeyProperty));
- entry.SetPropertyModified(nonKeyProperty);
+ entry.SetPropertyModified(nonKeyProperty);
- Assert.Equal(EntityState.Modified, entry.EntityState);
- Assert.False(entry.IsModified(keyProperty));
- Assert.True(entry.IsModified(nonKeyProperty));
+ Assert.Equal(EntityState.Modified, entry.EntityState);
+ Assert.False(entry.IsModified(keyProperty));
+ Assert.True(entry.IsModified(nonKeyProperty));
+ }
}
[ConditionalFact]
public virtual void Key_properties_throw_immediately_if_modified()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, new SomeEntity());
-
- entry[keyProperty] = 1;
+ using (var context = new TKContext())
+ {
+ var entry = context.Add(new TSomeEntity()).GetInfrastructure();
+ var keyProperty = entry.EntityType.FindProperty("Id");
- entry.SetEntityState(EntityState.Modified);
+ entry.SetEntityState(EntityState.Modified);
- Assert.False(entry.IsModified(keyProperty));
+ Assert.False(entry.IsModified(keyProperty));
- entry.SetEntityState(EntityState.Unchanged, true);
+ entry.SetEntityState(EntityState.Unchanged, true);
- Assert.False(entry.IsModified(keyProperty));
+ Assert.False(entry.IsModified(keyProperty));
- Assert.Equal(
- CoreStrings.KeyReadOnly("Id", entityType.DisplayName()),
- Assert.Throws(() => entry.SetPropertyModified(keyProperty)).Message);
+ Assert.Equal(
+ CoreStrings.KeyReadOnly("Id", "SomeEntity"),
+ Assert.Throws(
+ () => entry.SetPropertyModified(keyProperty)).Message);
- Assert.Equal(EntityState.Unchanged, entry.EntityState);
- Assert.False(entry.IsModified(keyProperty));
+ Assert.Equal(EntityState.Unchanged, entry.EntityState);
+ Assert.False(entry.IsModified(keyProperty));
- Assert.Equal(
- CoreStrings.KeyReadOnly("Id", entityType.DisplayName()),
- Assert.Throws(() => entry[keyProperty] = 2).Message);
+ Assert.Equal(
+ CoreStrings.KeyReadOnly("Id", "SomeEntity"),
+ Assert.Throws(
+ () => entry[keyProperty] = 2).Message);
- Assert.Equal(EntityState.Unchanged, entry.EntityState);
- Assert.False(entry.IsModified(keyProperty));
+ Assert.Equal(EntityState.Unchanged, entry.EntityState);
+ Assert.False(entry.IsModified(keyProperty));
+ }
}
[ConditionalFact]
public virtual void Added_entities_can_have_temporary_values()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var nonKeyProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
+ using (var context = new TKContext())
+ {
+ var entry = context.Add(new TSomeEntity()).GetInfrastructure();
+ var keyProperty = entry.EntityType.FindProperty("Id");
+ var nonKeyProperty = entry.EntityType.FindProperty("Name");
- var entry = CreateInternalEntry(configuration, entityType, new SomeEntity());
- entry[keyProperty] = 1;
+ entry[keyProperty] = 1;
- Assert.False(entry.HasTemporaryValue(keyProperty));
- Assert.False(entry.HasTemporaryValue(nonKeyProperty));
- Assert.False(entry.IsModified(keyProperty));
- Assert.False(entry.IsModified(nonKeyProperty));
+ Assert.False(entry.HasTemporaryValue(keyProperty));
+ Assert.False(entry.HasTemporaryValue(nonKeyProperty));
+ Assert.False(entry.IsModified(keyProperty));
+ Assert.False(entry.IsModified(nonKeyProperty));
- entry.SetEntityState(EntityState.Added);
+ entry.SetEntityState(EntityState.Added);
- Assert.False(entry.HasTemporaryValue(keyProperty));
- Assert.False(entry.HasTemporaryValue(nonKeyProperty));
- Assert.False(entry.IsModified(keyProperty));
- Assert.False(entry.IsModified(nonKeyProperty));
+ Assert.False(entry.HasTemporaryValue(keyProperty));
+ Assert.False(entry.HasTemporaryValue(nonKeyProperty));
+ Assert.False(entry.IsModified(keyProperty));
+ Assert.False(entry.IsModified(nonKeyProperty));
- entry.SetTemporaryValue(keyProperty, 1);
+ entry.SetTemporaryValue(keyProperty, 1);
- Assert.True(entry.HasTemporaryValue(keyProperty));
- Assert.False(entry.HasTemporaryValue(nonKeyProperty));
- Assert.False(entry.IsModified(keyProperty));
- Assert.False(entry.IsModified(nonKeyProperty));
+ Assert.True(entry.HasTemporaryValue(keyProperty));
+ Assert.False(entry.HasTemporaryValue(nonKeyProperty));
+ Assert.False(entry.IsModified(keyProperty));
+ Assert.False(entry.IsModified(nonKeyProperty));
- entry.SetTemporaryValue(nonKeyProperty, "Temp");
- entry[keyProperty] = 1;
+ entry.SetTemporaryValue(nonKeyProperty, "Temp");
+ entry[keyProperty] = 1;
- Assert.False(entry.HasTemporaryValue(keyProperty));
- Assert.True(entry.HasTemporaryValue(nonKeyProperty));
- Assert.False(entry.IsModified(keyProperty));
- Assert.False(entry.IsModified(nonKeyProperty));
+ Assert.False(entry.HasTemporaryValue(keyProperty));
+ Assert.True(entry.HasTemporaryValue(nonKeyProperty));
+ Assert.False(entry.IsModified(keyProperty));
+ Assert.False(entry.IsModified(nonKeyProperty));
- entry[nonKeyProperty] = "I Am A Real Person!";
+ entry[nonKeyProperty] = "I Am A Real Person!";
- entry.SetEntityState(EntityState.Unchanged);
+ entry.SetEntityState(EntityState.Unchanged);
- Assert.False(entry.HasTemporaryValue(keyProperty));
- Assert.False(entry.HasTemporaryValue(nonKeyProperty));
- Assert.False(entry.IsModified(keyProperty));
- Assert.False(entry.IsModified(nonKeyProperty));
+ Assert.False(entry.HasTemporaryValue(keyProperty));
+ Assert.False(entry.HasTemporaryValue(nonKeyProperty));
+ Assert.False(entry.IsModified(keyProperty));
+ Assert.False(entry.IsModified(nonKeyProperty));
- // Can't change the key...
- Assert.Throws(() => entry.SetTemporaryValue(keyProperty, -1));
- entry.SetTemporaryValue(nonKeyProperty, "Temp");
+ // Can't change the key...
+ Assert.Throws(() => entry.SetTemporaryValue(keyProperty, -1));
+ entry.SetTemporaryValue(nonKeyProperty, "Temp");
- Assert.True(entry.HasTemporaryValue(keyProperty));
- Assert.True(entry.HasTemporaryValue(nonKeyProperty));
- Assert.False(entry.IsModified(keyProperty));
- Assert.True(entry.IsModified(nonKeyProperty));
+ Assert.True(entry.HasTemporaryValue(keyProperty));
+ Assert.True(entry.HasTemporaryValue(nonKeyProperty));
+ Assert.False(entry.IsModified(keyProperty));
+ Assert.True(entry.IsModified(nonKeyProperty));
- entry.SetEntityState(EntityState.Added);
+ entry.SetEntityState(EntityState.Added);
- Assert.True(entry.HasTemporaryValue(keyProperty));
- Assert.True(entry.HasTemporaryValue(nonKeyProperty));
- Assert.False(entry.IsModified(keyProperty));
- Assert.False(entry.IsModified(nonKeyProperty));
+ Assert.True(entry.HasTemporaryValue(keyProperty));
+ Assert.True(entry.HasTemporaryValue(nonKeyProperty));
+ Assert.False(entry.IsModified(keyProperty));
+ Assert.False(entry.IsModified(nonKeyProperty));
+ }
}
[ConditionalTheory]
@@ -238,1354 +248,883 @@ public virtual void Added_entities_can_have_temporary_values()
[InlineData(EntityState.Deleted)]
public virtual void Changing_state_with_temp_value_throws(EntityState targetState)
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, new SomeEntity());
+ using (var context = new TKContext())
+ {
+ var entry = context.Add(new TSomeEntity()).GetInfrastructure();
+ var keyProperty = entry.EntityType.FindProperty("Id");
- entry.SetEntityState(EntityState.Added);
- entry.SetTemporaryValue(keyProperty, -1);
+ entry.SetEntityState(EntityState.Added);
+ entry.SetTemporaryValue(keyProperty, -1);
- Assert.Equal(
- CoreStrings.TempValuePersists("Id", entityType.DisplayName(), targetState.ToString()),
- Assert.Throws(() => entry.SetEntityState(targetState)).Message);
+ Assert.Equal(
+ CoreStrings.TempValuePersists("Id", "SomeEntity", targetState.ToString()),
+ Assert.Throws(() => entry.SetEntityState(targetState)).Message);
+ }
}
[ConditionalFact]
public virtual void Detaching_with_temp_values_does_not_throw()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, new SomeEntity());
- entry[keyProperty] = 1;
+ using (var context = new TKContext())
+ {
+ var entry = context.Add(new TSomeEntity()).GetInfrastructure();
+ var keyProperty = entry.EntityType.FindProperty("Id");
- entry.SetEntityState(EntityState.Added);
- entry.SetTemporaryValue(keyProperty, -1);
+ entry[keyProperty] = 1;
+ entry.SetEntityState(EntityState.Added);
+ entry.SetTemporaryValue(keyProperty, -1);
- Assert.True(entry.HasTemporaryValue(keyProperty));
+ Assert.True(entry.HasTemporaryValue(keyProperty));
- entry.SetEntityState(EntityState.Detached);
+ entry.SetEntityState(EntityState.Detached);
- Assert.True(entry.HasTemporaryValue(keyProperty));
+ Assert.True(entry.HasTemporaryValue(keyProperty));
- entry[keyProperty] = 1;
- entry.SetEntityState(EntityState.Unchanged);
+ entry[keyProperty] = 1;
+ entry.SetEntityState(EntityState.Unchanged);
- Assert.False(entry.HasTemporaryValue(keyProperty));
+ Assert.False(entry.HasTemporaryValue(keyProperty));
+ }
}
[ConditionalFact]
public virtual void Setting_an_explicit_value_marks_property_as_not_temporary()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, new SomeEntity());
+ using (var context = new TKContext())
+ {
+ var entry = context.Add(new TSomeEntity()).GetInfrastructure();
+ var keyProperty = entry.EntityType.FindProperty("Id");
- entry.SetEntityState(EntityState.Added);
- entry.SetTemporaryValue(keyProperty, -1);
+ entry.SetEntityState(EntityState.Added);
+ entry.SetTemporaryValue(keyProperty, -1);
- Assert.True(entry.HasTemporaryValue(keyProperty));
+ Assert.True(entry.HasTemporaryValue(keyProperty));
- entry[keyProperty] = 77;
+ entry[keyProperty] = 77;
- Assert.False(entry.HasTemporaryValue(keyProperty));
+ Assert.False(entry.HasTemporaryValue(keyProperty));
- entry.SetEntityState(EntityState.Unchanged); // Does not throw
+ entry.SetEntityState(EntityState.Unchanged); // Does not throw
+ }
}
[ConditionalFact]
public virtual void Key_properties_share_value_generation_space_with_base()
{
- var model = BuildModel(finalize: false);
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var baseEntityType = model.FindEntityType(typeof(SomeSimpleEntityBase).FullName);
- var altKeyProperty = baseEntityType.AddProperty("NonId", typeof(int));
- altKeyProperty.ValueGenerated = ValueGenerated.OnAdd;
- baseEntityType.AddKey(altKeyProperty);
- model.FinalizeModel();
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, new SomeEntity());
-
- Assert.Equal(0, entry[keyProperty]);
-
- Assert.Equal(0, entry[altKeyProperty]);
-
- entry.SetEntityState(EntityState.Added);
-
- Assert.NotNull(entry[keyProperty]);
- Assert.NotEqual(0, entry[keyProperty]);
- Assert.Equal(entry[keyProperty], entry[altKeyProperty]);
+ using (var context = new TKContext())
+ {
+ var entry = context.Add(new TSomeEntity()).GetInfrastructure();
+ var keyProperty = entry.EntityType.FindProperty("Id");
+ var altKeyProperty = entry.EntityType.FindProperty("NonId");
- var baseEntry = CreateInternalEntry(configuration, baseEntityType, new SomeSimpleEntityBase());
+ Assert.NotEqual(0, entry[keyProperty]);
+ Assert.Equal(entry[keyProperty], entry[altKeyProperty]);
- baseEntry.SetEntityState(EntityState.Added);
+ var baseEntry = context.Add(new TSomeSimpleEntityBase()).GetInfrastructure();
- Assert.NotNull(baseEntry[keyProperty]);
- Assert.NotEqual(0, baseEntry[keyProperty]);
- Assert.Equal(baseEntry[keyProperty], baseEntry[altKeyProperty]);
- Assert.NotEqual(entry[keyProperty], baseEntry[keyProperty]);
- Assert.NotEqual(entry[altKeyProperty], baseEntry[altKeyProperty]);
+ Assert.NotNull(baseEntry[keyProperty]);
+ Assert.NotEqual(0, baseEntry[keyProperty]);
+ Assert.Equal(baseEntry[keyProperty], baseEntry[altKeyProperty]);
+ Assert.NotEqual(entry[keyProperty], baseEntry[keyProperty]);
+ Assert.NotEqual(entry[altKeyProperty], baseEntry[altKeyProperty]);
+ }
}
[ConditionalFact]
public virtual void Value_generation_does_not_happen_if_property_has_non_default_value()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, new SomeEntity());
+ using (var context = new TKContext())
+ {
+ var entry = context.Add(new TSomeEntity()).GetInfrastructure();
+ var keyProperty = entry.EntityType.FindProperty("Id");
- entry[keyProperty] = 31143;
+ entry[keyProperty] = 31143;
- entry.SetEntityState(EntityState.Added);
+ entry.SetEntityState(EntityState.Added);
- Assert.Equal(31143, entry[keyProperty]);
+ Assert.Equal(31143, entry[keyProperty]);
+ }
}
[ConditionalFact]
- public virtual void Temporary_values_are_npt_reset_when_entity_is_detached()
+ public virtual void Modified_values_are_reset_when_entity_is_changed_to_Added()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entity = new SomeEntity();
- var entry = CreateInternalEntry(configuration, entityType, entity);
-
- entry.SetEntityState(EntityState.Added);
- entry.SetTemporaryValue(keyProperty, -1);
-
- Assert.NotNull(entry[keyProperty]);
- Assert.Equal(0, entity.Id);
- Assert.Equal(-1, entry[keyProperty]);
+ using (var context = new TKContext())
+ {
+ var entry = context.Update(new TSomeEntity()).GetInfrastructure();
+ var property = entry.EntityType.FindProperty("Name");
- entry.SetEntityState(EntityState.Detached);
+ entry[entry.EntityType.FindProperty("Id")] = 1;
- Assert.Equal(0, entity.Id);
- Assert.Equal(-1, entry[keyProperty]);
+ entry.SetEntityState(EntityState.Modified);
+ entry.SetPropertyModified(property);
- entry.SetEntityState(EntityState.Added);
+ entry.SetEntityState(EntityState.Added);
- Assert.Equal(0, entity.Id);
- Assert.Equal(-1, entry[keyProperty]);
+ Assert.False(entry.HasTemporaryValue(property));
+ }
}
[ConditionalFact]
- public virtual void Modified_values_are_reset_when_entity_is_changed_to_Added()
+ public virtual void Changing_state_to_Added_triggers_value_generation_for_any_property()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var property = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, new SomeEntity());
- entry[entityType.FindProperty("Id")] = 1;
+ using (var context = new TKContext())
+ {
+ var entry = context.Entry(new TSomeDependentEntity()).GetInfrastructure();
- entry.SetEntityState(EntityState.Modified);
- entry.SetPropertyModified(property);
+ var entityType = entry.EntityType;
+ entry[entityType.FindProperty("Id1")] = 77;
+ entry[entityType.FindProperty("Id2")] = "Ready Salted";
+ entry.SetEntityState(EntityState.Added);
- entry.SetEntityState(EntityState.Added);
+ var property = entityType.FindProperty("JustAProperty");
- Assert.False(entry.HasTemporaryValue(property));
+ Assert.NotEqual(0, entry[property]);
+ }
}
[ConditionalFact]
- public virtual void Changing_state_to_Added_triggers_value_generation_for_any_property()
+ public virtual void Notification_that_an_FK_property_has_changed_updates_the_snapshot()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeDependentEntity).FullName);
- var keyProperties = new[] { entityType.FindProperty("Id1"), entityType.FindProperty("Id2") };
- var fkProperty = entityType.FindProperty("SomeEntityId");
- var property = entityType.FindProperty("JustAProperty");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
+ using (var context = new TKContext())
+ {
+ var entry = context.Entry(new TSomeDependentEntity()).GetInfrastructure();
- var entry = CreateInternalEntry(configuration, entityType, new SomeDependentEntity());
- entry[keyProperties[0]] = 77;
- entry[keyProperties[1]] = "ReadySalted";
- entry[fkProperty] = 0;
+ var entityType = entry.EntityType;
+ entry[entityType.FindProperty("Id1")] = 77;
+ entry[entityType.FindProperty("Id2")] = "Ready Salted";
+ entry.SetEntityState(EntityState.Added);
- Assert.Equal(0, entry[property]);
+ var fkProperty = entityType.FindProperty("SomeEntityId");
- entry.SetEntityState(EntityState.Added);
+ entry[fkProperty] = 77;
+ entry.SetRelationshipSnapshotValue(fkProperty, 78);
- Assert.NotNull(entry[property]);
- Assert.NotEqual(0, entry[property]);
- }
+ entry[fkProperty] = 79;
- [ConditionalFact]
- public virtual void Notification_that_an_FK_property_has_changed_updates_the_snapshot()
- {
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeDependentEntity).FullName);
- var fkProperty = entityType.FindProperty("SomeEntityId");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, new SomeDependentEntity());
- entry[entityType.FindProperty("Id1")] = 66;
- entry[entityType.FindProperty("Id2")] = "Bar";
- entry.SetEntityState(EntityState.Added);
- entry[fkProperty] = 77;
- entry.SetRelationshipSnapshotValue(fkProperty, 78);
-
- entry[fkProperty] = 79;
-
- var keyValue = entry.GetRelationshipSnapshotValue(entityType.GetForeignKeys().Single().Properties.Single());
- Assert.Equal(79, keyValue);
+ var keyValue = entry.GetRelationshipSnapshotValue(entityType.GetForeignKeys().Single().Properties.Single());
+ Assert.Equal(79, keyValue);
+ }
}
[ConditionalFact]
public virtual void Setting_property_to_the_same_value_does_not_update_the_snapshot()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeDependentEntity).FullName);
- var fkProperty = entityType.FindProperty("SomeEntityId");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
+ using (var context = new TKContext())
+ {
+ var entry = context.Entry(new TSomeDependentEntity()).GetInfrastructure();
- var entry = CreateInternalEntry(configuration, entityType, new SomeDependentEntity());
- entry[fkProperty] = 77;
- entry.SetRelationshipSnapshotValue(fkProperty, 78);
+ var entityType = entry.EntityType;
+ entry[entityType.FindProperty("Id1")] = 77;
+ entry[entityType.FindProperty("Id2")] = "Ready Salted";
+ entry.SetEntityState(EntityState.Unchanged);
- entry[fkProperty] = 77;
+ var fkProperty = entityType.FindProperty("SomeEntityId");
- var keyValue = entry.GetRelationshipSnapshotValue(entityType.GetForeignKeys().Single().Properties.Single());
- Assert.Equal(78, keyValue);
- }
+ entry[fkProperty] = 77;
+ entry.SetRelationshipSnapshotValue(fkProperty, 78);
- [ConditionalFact]
- public virtual void Can_get_property_value_after_creation_from_value_buffer()
- {
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(
- configuration,
- entityType,
- new SomeEntity
- {
- Id = 1,
- Name = "Kool"
- },
- new ValueBuffer(new object[] { 1, "Kool" }));
-
- Assert.Equal(1, entry[keyProperty]);
- }
+ entry[fkProperty] = 77;
- [ConditionalFact]
- public virtual void Can_set_property_value_after_creation_from_value_buffer()
- {
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var nameProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(
- configuration,
- entityType,
- new SomeEntity
- {
- Id = 1,
- Name = "Kool"
- },
- new ValueBuffer(new object[] { 1, "Kool" }));
-
- entry[nameProperty] = "Mule";
-
- Assert.Equal("Mule", entry[nameProperty]);
+ var keyValue = entry.GetRelationshipSnapshotValue(entityType.GetForeignKeys().Single().Properties.Single());
+ Assert.Equal(78, keyValue);
+ }
}
[ConditionalFact]
- public virtual void Can_set_and_get_property_values()
+ public virtual void Can_get_property_value_after_creation_from_value_buffer()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var nonKeyProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, new SomeEntity());
-
- entry[keyProperty] = 77;
- entry[nonKeyProperty] = "Magic Tree House";
+ using (var context = new TKContext())
+ {
+ var stateManager = context.GetService();
+ var entityType = context.Model.FindEntityType(typeof(TSomeEntity));
- Assert.Equal(77, entry[keyProperty]);
- Assert.Equal("Magic Tree House", entry[nonKeyProperty]);
+ var entry = stateManager.CreateEntry(
+ new Dictionary
+ {
+ {
+ "Id", 1
+ },
+ {
+ "Name", "Kool"
+ }
+ },
+ entityType
+ );
+
+ var keyProperty = entityType.FindProperty("Id");
+ var property = entityType.FindProperty("Name");
+
+ Assert.Equal(1, entry[keyProperty]);
+ Assert.Equal("Kool", entry[property]);
+ }
}
[ConditionalFact]
- public virtual void Can_set_and_get_property_values_genericly()
+ public virtual void Can_set_property_value_after_creation_from_value_buffer()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var nonKeyProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, new SomeEntity());
-
- entry[keyProperty] = 77;
- entry[nonKeyProperty] = "Magic Tree House";
+ using (var context = new TKContext())
+ {
+ var stateManager = context.GetService();
+ var entityType = context.Model.FindEntityType(typeof(TSomeEntity));
- Assert.Equal(77, entry.GetCurrentValue(keyProperty));
- Assert.Equal("Magic Tree House", entry.GetCurrentValue(nonKeyProperty));
+ var entry = stateManager.CreateEntry(
+ new Dictionary
+ {
+ {
+ "Id", 1
+ },
+ {
+ "Name", "Kool"
+ }
+ },
+ entityType
+ );
+
+ var nameProperty = entityType.FindProperty("Name");
+ entry[nameProperty] = "Mule";
+
+ Assert.Equal("Mule", entry[nameProperty]);
+ }
}
[ConditionalFact]
public virtual void Can_get_value_buffer_from_properties()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var keyProperty = entityType.FindProperty("Id");
- var nonKeyProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, new SomeEntity());
+ using (var context = new TKContext())
+ {
+ var entry = context.Add(new TSomeEntity()).GetInfrastructure();
+ var keyProperty = entry.EntityType.FindProperty("Id");
+ var nonKeyProperty = entry.EntityType.FindProperty("Name");
- entry[keyProperty] = 77;
- entry[nonKeyProperty] = "Magic Tree House";
+ entry[keyProperty] = 77;
+ entry[nonKeyProperty] = "Magic Tree House";
- Assert.Equal(new object[] { 77, "Magic Tree House" }, CreateValueBuffer(entry));
+ Assert.Equal(
+ new object[]
+ {
+ 77, "SomeEntity", 1, "Magic Tree House"
+ },
+ CreateValueBuffer(entry));
+ }
}
private static object[] CreateValueBuffer(IUpdateEntry entry)
=> entry.EntityType.GetProperties().Select(entry.GetCurrentValue).ToArray();
- [ConditionalFact]
- public virtual void All_original_values_can_be_accessed_for_entity_that_does_full_change_tracking_if_eager_values_on()
- {
- var model = BuildModel(finalize: false);
- var entityType = model.FindEntityType(typeof(FullNotificationEntity).FullName);
- entityType.SetChangeTrackingStrategy(ChangeTrackingStrategy.Snapshot);
- model.FinalizeModel();
-
- AllOriginalValuesTest(
- model, entityType, new FullNotificationEntity
- {
- Id = 1,
- Name = "Kool"
- });
- }
-
- protected void AllOriginalValuesTest(IModel model, IEntityType entityType, object entity)
+ protected void AllOriginalValuesTest(object entity)
{
- var idProperty = entityType.FindProperty("Id");
- var nameProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(
- configuration,
- entityType,
- entity,
- new ValueBuffer(new object[] { 1, "Kool" }));
-
- entry.SetEntityState(EntityState.Unchanged);
+ using (var context = new TKSnapContext())
+ {
+ var entry = context.Entry(entity).GetInfrastructure();
+ var idProperty = entry.EntityType.FindProperty("Id");
+ var nameProperty = entry.EntityType.FindProperty("Name");
- Assert.Equal(1, entry.GetOriginalValue(idProperty));
- Assert.Equal("Kool", entry.GetOriginalValue(nameProperty));
- Assert.Equal(1, entry[idProperty]);
- Assert.Equal("Kool", entry[nameProperty]);
+ entry[idProperty] = 1;
+ entry[nameProperty] = "Kool";
+ entry.SetEntityState(EntityState.Unchanged);
- entry[nameProperty] = "Beans";
+ Assert.Equal(1, entry.GetOriginalValue(idProperty));
+ Assert.Equal("Kool", entry.GetOriginalValue(nameProperty));
+ Assert.Equal(1, entry[idProperty]);
+ Assert.Equal("Kool", entry[nameProperty]);
- Assert.Equal(1, entry.GetOriginalValue(idProperty));
- Assert.Equal("Kool", entry.GetOriginalValue(nameProperty));
- Assert.Equal(1, entry[idProperty]);
- Assert.Equal("Beans", entry[nameProperty]);
+ entry[nameProperty] = "Beans";
- entry.SetOriginalValue(nameProperty, "Franks");
+ Assert.Equal(1, entry.GetOriginalValue(idProperty));
+ Assert.Equal("Kool", entry.GetOriginalValue(nameProperty));
+ Assert.Equal(1, entry[idProperty]);
+ Assert.Equal("Beans", entry[nameProperty]);
- Assert.Equal(1, entry.GetOriginalValue(idProperty));
- Assert.Equal("Franks", entry.GetOriginalValue(nameProperty));
- Assert.Equal(1, entry[idProperty]);
- Assert.Equal("Beans", entry[nameProperty]);
- }
+ entry.SetOriginalValue(nameProperty, "Franks");
- [ConditionalFact]
- public virtual void Required_original_values_can_be_accessed_for_entity_that_does_full_change_tracking()
- {
- var model = BuildModel();
- OriginalValuesTest(
- model, model.FindEntityType(typeof(FullNotificationEntity).FullName), new FullNotificationEntity
- {
- Id = 1,
- Name = "Kool"
- });
- }
-
- [ConditionalFact]
- public virtual void Required_original_values_can_be_accessed_for_entity_that_does_changed_only_notification()
- {
- var model = BuildModel();
- OriginalValuesTest(
- model, model.FindEntityType(typeof(ChangedOnlyEntity).FullName), new ChangedOnlyEntity
- {
- Id = 1,
- Name = "Kool"
- });
+ Assert.Equal(1, entry.GetOriginalValue(idProperty));
+ Assert.Equal("Franks", entry.GetOriginalValue(nameProperty));
+ Assert.Equal(1, entry[idProperty]);
+ Assert.Equal("Beans", entry[nameProperty]);
+ }
}
[ConditionalFact]
public virtual void Required_original_values_can_be_accessed_for_entity_that_does_no_notification()
- {
- var model = BuildModel();
- OriginalValuesTest(
- model, model.FindEntityType(typeof(SomeEntity).FullName), new SomeEntity
- {
- Id = 1,
- Name = "Kool"
- });
- }
+ => OriginalValuesTest(new TSomeEntity());
- protected void OriginalValuesTest(IModel model, IEntityType entityType, object entity)
+ protected void OriginalValuesTest(object entity)
{
- var nameProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, entity, new ValueBuffer(new object[] { 1, "Kool" }));
- entry.SetEntityState(EntityState.Unchanged);
-
- Assert.Equal("Kool", entry.GetOriginalValue(nameProperty));
- Assert.Equal("Kool", entry[nameProperty]);
+ using (var context = new TKContext())
+ {
+ var entry = context.Entry(entity).GetInfrastructure();
+ entry[entry.EntityType.FindProperty("Id")] = 1;
+ var nameProperty = entry.EntityType.FindProperty("Name");
+ entry[nameProperty] = "Kool";
+ entry.SetEntityState(EntityState.Unchanged);
- entry[nameProperty] = "Beans";
+ Assert.Equal("Kool", entry.GetOriginalValue(nameProperty));
+ Assert.Equal("Kool", entry[nameProperty]);
- Assert.Equal("Kool", entry.GetOriginalValue(nameProperty));
- Assert.Equal("Beans", entry[nameProperty]);
+ entry[nameProperty] = "Beans";
- entry.SetOriginalValue(nameProperty, "Franks");
+ Assert.Equal("Kool", entry.GetOriginalValue(nameProperty));
+ Assert.Equal("Beans", entry[nameProperty]);
- Assert.Equal("Franks", entry.GetOriginalValue(nameProperty));
- Assert.Equal("Beans", entry[nameProperty]);
- }
+ entry.SetOriginalValue(nameProperty, "Franks");
- [ConditionalFact]
- public virtual void Required_original_values_can_be_accessed_generically_for_entity_that_does_full_change_tracking()
- {
- var model = BuildModel();
- GenericOriginalValuesTest(
- model, model.FindEntityType(typeof(FullNotificationEntity).FullName), new FullNotificationEntity
- {
- Id = 1,
- Name = "Kool"
- });
- }
-
- [ConditionalFact]
- public virtual void Required_original_values_can_be_accessed_generically_for_entity_that_does_changed_only_notification()
- {
- var model = BuildModel();
- GenericOriginalValuesTest(
- model, model.FindEntityType(typeof(ChangedOnlyEntity).FullName), new ChangedOnlyEntity
- {
- Id = 1,
- Name = "Kool"
- });
+ Assert.Equal("Franks", entry.GetOriginalValue(nameProperty));
+ Assert.Equal("Beans", entry[nameProperty]);
+ }
}
[ConditionalFact]
public virtual void Required_original_values_can_be_accessed_generically_for_entity_that_does_no_notification()
- {
- var model = BuildModel();
- GenericOriginalValuesTest(
- model, model.FindEntityType(typeof(SomeEntity).FullName), new SomeEntity
- {
- Id = 1,
- Name = "Kool"
- });
- }
+ => GenericOriginalValuesTest(new TSomeEntity());
- protected void GenericOriginalValuesTest(IModel model, IEntityType entityType, object entity)
+ protected void GenericOriginalValuesTest(object entity)
{
- var nameProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, entity, new ValueBuffer(new object[] { 1, "Kool" }));
- entry.SetEntityState(EntityState.Unchanged);
-
- Assert.Equal("Kool", entry.GetOriginalValue(nameProperty));
- Assert.Equal("Kool", entry.GetCurrentValue(nameProperty));
+ using (var context = new TKContext())
+ {
+ var entry = context.Entry(entity).GetInfrastructure();
+ var idProperty = entry.EntityType.FindProperty("Id");
+ var nameProperty = entry.EntityType.FindProperty("Name");
- entry[nameProperty] = "Beans";
+ entry[idProperty] = 77;
+ entry[nameProperty] = "Kool";
+ entry.SetEntityState(EntityState.Unchanged);
- Assert.Equal("Kool", entry.GetOriginalValue(nameProperty));
- Assert.Equal("Beans", entry.GetCurrentValue(nameProperty));
+ Assert.Equal("Kool", entry.GetOriginalValue(nameProperty));
+ Assert.Equal("Kool", entry.GetCurrentValue(nameProperty));
- entry.SetOriginalValue(nameProperty, "Franks");
+ entry[nameProperty] = "Beans";
- Assert.Equal("Franks", entry.GetOriginalValue(nameProperty));
- Assert.Equal("Beans", entry.GetCurrentValue(nameProperty));
- }
+ Assert.Equal("Kool", entry.GetOriginalValue(nameProperty));
+ Assert.Equal("Beans", entry.GetCurrentValue(nameProperty));
- [ConditionalFact]
- public virtual void Null_original_values_are_handled_for_entity_that_does_full_change_tracking()
- {
- var model = BuildModel();
- NullOriginalValuesTest(
- model, model.FindEntityType(typeof(FullNotificationEntity).FullName), new FullNotificationEntity
- {
- Id = 1
- });
- }
+ entry.SetOriginalValue(nameProperty, "Franks");
- [ConditionalFact]
- public virtual void Null_original_values_are_handled_for_entity_that_does_changed_only_notification()
- {
- var model = BuildModel();
- NullOriginalValuesTest(
- model, model.FindEntityType(typeof(ChangedOnlyEntity).FullName), new ChangedOnlyEntity
- {
- Id = 1
- });
+ Assert.Equal("Franks", entry.GetOriginalValue(nameProperty));
+ Assert.Equal("Beans", entry.GetCurrentValue(nameProperty));
+ }
}
[ConditionalFact]
public virtual void Null_original_values_are_handled_for_entity_that_does_no_notification()
- {
- var model = BuildModel();
- NullOriginalValuesTest(
- model, model.FindEntityType(typeof(SomeEntity).FullName), new SomeEntity
- {
- Id = 1
- });
- }
+ => NullOriginalValuesTest(new TSomeEntity());
- protected void NullOriginalValuesTest(IModel model, IEntityType entityType, object entity)
+ protected void NullOriginalValuesTest(object entity)
{
- var nameProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, entity, new ValueBuffer(new object[] { 1, null }));
- entry.SetEntityState(EntityState.Unchanged);
-
- Assert.Null(entry.GetOriginalValue(nameProperty));
- Assert.Null(entry[nameProperty]);
+ using (var context = new TKContext())
+ {
+ var entry = context.Entry(entity).GetInfrastructure();
+ var idProperty = entry.EntityType.FindProperty("Id");
+ var nameProperty = entry.EntityType.FindProperty("Name");
- entry[nameProperty] = "Beans";
+ entry[idProperty] = 77;
+ entry.SetEntityState(EntityState.Unchanged);
- Assert.Null(entry.GetOriginalValue(nameProperty));
- Assert.Equal("Beans", entry[nameProperty]);
+ Assert.Null(entry.GetOriginalValue(nameProperty));
+ Assert.Null(entry[nameProperty]);
- entry.SetOriginalValue(nameProperty, "Franks");
+ entry[nameProperty] = "Beans";
- Assert.Equal("Franks", entry.GetOriginalValue(nameProperty));
- Assert.Equal("Beans", entry[nameProperty]);
+ Assert.Null(entry.GetOriginalValue(nameProperty));
+ Assert.Equal("Beans", entry[nameProperty]);
- entry.SetOriginalValue(nameProperty, null);
+ entry.SetOriginalValue(nameProperty, "Franks");
- Assert.Null(entry.GetOriginalValue(nameProperty));
- Assert.Equal("Beans", entry[nameProperty]);
- }
+ Assert.Equal("Franks", entry.GetOriginalValue(nameProperty));
+ Assert.Equal("Beans", entry[nameProperty]);
- [ConditionalFact]
- public virtual void Null_original_values_are_handled_generically_for_entity_that_does_full_change_tracking()
- {
- var model = BuildModel();
- GenericNullOriginalValuesTest(
- model, model.FindEntityType(typeof(FullNotificationEntity).FullName), new FullNotificationEntity
- {
- Id = 1
- });
- }
+ entry.SetOriginalValue(nameProperty, null);
- [ConditionalFact]
- public virtual void Null_original_values_are_handled_generically_for_entity_that_does_changed_only_notification()
- {
- var model = BuildModel();
- GenericNullOriginalValuesTest(
- model, model.FindEntityType(typeof(ChangedOnlyEntity).FullName), new ChangedOnlyEntity
- {
- Id = 1
- });
+ Assert.Null(entry.GetOriginalValue(nameProperty));
+ Assert.Equal("Beans", entry[nameProperty]);
+ }
}
[ConditionalFact]
public virtual void Null_original_values_are_handled_generically_for_entity_that_does_no_notification()
- {
- var model = BuildModel();
- GenericNullOriginalValuesTest(
- model, model.FindEntityType(typeof(SomeEntity).FullName), new SomeEntity
- {
- Id = 1
- });
- }
+ => GenericNullOriginalValuesTest(new TSomeEntity());
- protected void GenericNullOriginalValuesTest(IModel model, IEntityType entityType, object entity)
+ protected void GenericNullOriginalValuesTest(object entity)
{
- var nameProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
+ using (var context = new TKContext())
+ {
+ var entry = context.Entry(entity).GetInfrastructure();
+ var idProperty = entry.EntityType.FindProperty("Id");
+ var nameProperty = entry.EntityType.FindProperty("Name");
- var entry = CreateInternalEntry(configuration, entityType, entity, new ValueBuffer(new object[] { 1, null }));
- entry.SetEntityState(EntityState.Unchanged);
+ entry[idProperty] = 77;
+ entry.SetEntityState(EntityState.Unchanged);
- Assert.Null(entry.GetOriginalValue(nameProperty));
- Assert.Null(entry.GetCurrentValue(nameProperty));
+ Assert.Null(entry.GetOriginalValue(nameProperty));
+ Assert.Null(entry.GetCurrentValue(nameProperty));
- entry[nameProperty] = "Beans";
+ entry[nameProperty] = "Beans";
- Assert.Null(entry.GetOriginalValue(nameProperty));
- Assert.Equal("Beans", entry.GetCurrentValue(nameProperty));
+ Assert.Null(entry.GetOriginalValue(nameProperty));
+ Assert.Equal("Beans", entry.GetCurrentValue(nameProperty));
- entry.SetOriginalValue(nameProperty, "Franks");
+ entry.SetOriginalValue(nameProperty, "Franks");
- Assert.Equal("Franks", entry.GetOriginalValue(nameProperty));
- Assert.Equal("Beans", entry.GetCurrentValue(nameProperty));
+ Assert.Equal("Franks", entry.GetOriginalValue(nameProperty));
+ Assert.Equal("Beans", entry.GetCurrentValue(nameProperty));
- entry.SetOriginalValue(nameProperty, null);
+ entry.SetOriginalValue(nameProperty, null);
- Assert.Null(entry.GetOriginalValue(nameProperty));
- Assert.Equal("Beans", entry.GetCurrentValue(nameProperty));
+ Assert.Null(entry.GetOriginalValue(nameProperty));
+ Assert.Equal("Beans", entry.GetCurrentValue(nameProperty));
+ }
}
[ConditionalFact]
- public virtual void Setting_property_using_state_entry_always_marks_as_modified()
- {
- var model = BuildModel();
-
- SetPropertyInternalEntityEntryTest(
- model, model.FindEntityType(typeof(FullNotificationEntity).FullName), new FullNotificationEntity
- {
- Id = 1,
- Name = "Kool"
- });
- SetPropertyInternalEntityEntryTest(
- model, model.FindEntityType(typeof(ChangedOnlyEntity).FullName), new ChangedOnlyEntity
- {
- Id = 1,
- Name = "Kool"
- });
- SetPropertyInternalEntityEntryTest(
- model, model.FindEntityType(typeof(SomeEntity).FullName), new SomeEntity
- {
- Id = 1,
- Name = "Kool"
- });
- }
+ public virtual void Setting_property_using_state_entry_always_marks_as_modified_no_notifications()
+ => SetPropertyInternalEntityEntryTest(new TSomeEntity());
- protected void SetPropertyInternalEntityEntryTest(IModel model, IEntityType entityType, object entity)
+ protected void SetPropertyInternalEntityEntryTest(object entity)
{
- var idProperty = entityType.FindProperty("Id");
- var nameProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, entity, new ValueBuffer(new object[] { 1, "Kool" }));
- entry.SetEntityState(EntityState.Unchanged);
-
- Assert.False(entry.IsModified(idProperty));
- Assert.False(entry.IsModified(nameProperty));
- Assert.Equal(EntityState.Unchanged, entry.EntityState);
-
- entry[idProperty] = 1;
- entry[nameProperty] = "Kool";
-
- Assert.False(entry.IsModified(idProperty));
- Assert.False(entry.IsModified(nameProperty));
- Assert.Equal(EntityState.Unchanged, entry.EntityState);
-
- entry[nameProperty] = "Beans";
-
- Assert.False(entry.IsModified(idProperty));
- Assert.True(entry.IsModified(nameProperty));
- Assert.Equal(EntityState.Modified, entry.EntityState);
- }
-
- protected void SetPropertyClrTest(TEntity entity, bool needsDetectChanges)
- where TEntity : ISomeEntity
- {
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(TEntity));
- var nameProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(configuration, entityType, entity, new ValueBuffer(new object[] { 1, "Kool" }));
- entry.SetEntityState(EntityState.Unchanged);
-
- Assert.False(entry.IsModified(nameProperty));
- Assert.Equal(EntityState.Unchanged, entry.EntityState);
-
- entity.Name = "Kool";
-
- Assert.False(entry.IsModified(nameProperty));
- Assert.Equal(EntityState.Unchanged, entry.EntityState);
+ using (var context = new TKContext())
+ {
+ var entry = context.Entry(entity).GetInfrastructure();
+ var idProperty = entry.EntityType.FindProperty("Id");
+ var nameProperty = entry.EntityType.FindProperty("Name");
- entity.Name = "Beans";
+ entry[idProperty] = 77;
+ entry[nameProperty] = "Kool";
+ entry.SetEntityState(EntityState.Unchanged);
- if (needsDetectChanges)
- {
+ Assert.False(entry.IsModified(idProperty));
Assert.False(entry.IsModified(nameProperty));
Assert.Equal(EntityState.Unchanged, entry.EntityState);
- configuration.GetRequiredService().DetectChanges(entry);
- }
-
- Assert.True(entry.IsModified(nameProperty));
- Assert.Equal(EntityState.Modified, entry.EntityState);
- }
-
- [ConditionalFact]
- public virtual void AcceptChanges_does_nothing_for_unchanged_entities()
- => AcceptChangesNoop(EntityState.Unchanged);
-
- [ConditionalFact]
- public virtual void AcceptChanges_does_nothing_for_unknown_entities()
- => AcceptChangesNoop(EntityState.Detached);
-
- private void AcceptChangesNoop(EntityState entityState)
- {
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(
- configuration,
- entityType,
- new SomeEntity
- {
- Id = 1,
- Name = "Kool"
- },
- new ValueBuffer(new object[] { 1, "Kool" }));
+ entry[nameProperty] = "Kool";
- entry.SetEntityState(entityState);
-
- entry.AcceptChanges();
+ Assert.False(entry.IsModified(nameProperty));
+ Assert.Equal(EntityState.Unchanged, entry.EntityState);
- Assert.Equal(entityState, entry.EntityState);
- }
+ entry[nameProperty] = "Beans";
- [ConditionalFact]
- public virtual void AcceptChanges_makes_Modified_entities_Unchanged_and_resets_used_original_values()
- {
- AcceptChangesKeep(EntityState.Modified);
+ Assert.True(entry.IsModified(nameProperty));
+ Assert.Equal(EntityState.Modified, entry.EntityState);
+ }
}
[ConditionalFact]
- public virtual void AcceptChanges_makes_Added_entities_Unchanged()
- {
- AcceptChangesKeep(EntityState.Added);
- }
-
- private void AcceptChangesKeep(EntityState entityState)
+ public void Can_get_entity()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var nameProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(
- configuration,
- entityType,
- new SomeEntity
- {
- Id = 1,
- Name = "Kool"
- },
- new ValueBuffer(new object[] { 1, "Kool" }));
-
- entry.SetEntityState(entityState);
-
- entry[nameProperty] = "Pickle";
- entry.SetOriginalValue(nameProperty, "Cheese");
-
- entry.AcceptChanges();
-
- Assert.Equal(EntityState.Unchanged, entry.EntityState);
- Assert.Equal("Pickle", entry[nameProperty]);
- Assert.Equal("Pickle", entry.GetOriginalValue(nameProperty));
- }
+ using (var context = new TKContext())
+ {
+ var entity = new TSomeEntity();
+ var entry = context.Attach(entity).GetInfrastructure();
- [ConditionalFact]
- public virtual void AcceptChanges_makes_Modified_entities_Unchanged_and_effectively_resets_unused_original_values()
- {
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var nameProperty = entityType.FindProperty("Name");
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(
- configuration,
- entityType,
- new SomeEntity
- {
- Id = 1,
- Name = "Kool"
- },
- new ValueBuffer(new object[] { 1, "Kool" }));
-
- entry.SetEntityState(EntityState.Modified);
-
- entry[nameProperty] = "Pickle";
-
- entry.AcceptChanges();
-
- Assert.Equal(EntityState.Unchanged, entry.EntityState);
- Assert.Equal("Pickle", entry[nameProperty]);
- Assert.Equal("Pickle", entry.GetOriginalValue(nameProperty));
+ Assert.Same(entity, entry.Entity);
+ }
}
[ConditionalFact]
- public virtual void AcceptChanges_detaches_Deleted_entities()
+ public void Can_set_and_get_property_value_from_CLR_object()
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var configuration = InMemoryTestHelpers.Instance.CreateContextServices(model);
+ using (var context = new TKContext())
+ {
+ var entity = new TSomeEntity();
+ var entry = context.Entry(entity).GetInfrastructure();
+ var entityType = entry.EntityType;
+ var keyProperty = entityType.FindProperty("Id");
+ var nonKeyProperty = entityType.FindProperty("Name");
- var entry = CreateInternalEntry(
- configuration,
- entityType,
- new SomeEntity
- {
- Id = 1,
- Name = "Kool"
- },
- new ValueBuffer(new object[] { 1, "Kool" }));
+ entry[keyProperty] = 77;
+ entry[nonKeyProperty] = "Magic Tree House";
+ entry.SetEntityState(EntityState.Added);
- entry.SetEntityState(EntityState.Deleted);
+ Assert.Equal(77, entry[keyProperty]);
+ Assert.Equal("Magic Tree House", entry[nonKeyProperty]);
- entry.AcceptChanges();
+ entry[keyProperty] = 78;
+ entry[nonKeyProperty] = "Normal Tree House";
- Assert.Equal(EntityState.Detached, entry.EntityState);
+ Assert.Equal(78, entry[keyProperty]);
+ Assert.Equal("Normal Tree House", entry[nonKeyProperty]);
+ }
}
[ConditionalFact]
- public virtual void AcceptChanges_does_nothing_for_unchanged_owned_entities()
- => AcceptChangesOwned(EntityState.Unchanged);
-
- [ConditionalFact]
- public virtual void AcceptChanges_does_nothing_for_unknown_owned_entities()
- => AcceptChangesOwned(EntityState.Detached);
-
- [ConditionalFact]
- public virtual void AcceptChanges_makes_Modified_owned_entities_Unchanged_and_resets_used_original_values()
- => AcceptChangesOwned(EntityState.Modified);
+ public void All_original_values_can_be_accessed_for_entity_that_does_no_notification()
+ => AllOriginalValuesTest(new TSomeEntity());
[ConditionalFact]
- public virtual void AcceptChanges_makes_Added_owned_entities_Unchanged()
- => AcceptChangesOwned(EntityState.Added);
+ public virtual void AcceptChanges_does_nothing_for_unchanged_entities()
+ => AcceptChangesNoop(EntityState.Unchanged);
[ConditionalFact]
- public virtual void AcceptChanges_detaches_Deleted_owned_entities()
- => AcceptChangesOwned(EntityState.Deleted);
+ public virtual void AcceptChanges_does_nothing_for_unknown_entities()
+ => AcceptChangesNoop(EntityState.Detached);
- private void AcceptChangesOwned(EntityState entityState)
+ private void AcceptChangesNoop(EntityState entityState)
{
- var model = BuildModel();
- var ownerType = model.FindEntityType(typeof(OwnerClass).FullName);
- var ownedType = ownerType.FindNavigation(nameof(OwnerClass.Owned)).GetTargetType();
- var valueProperty = ownedType.FindProperty(nameof(OwnedClass.Value));
- var contextServices = InMemoryTestHelpers.Instance.CreateContextServices(model);
-
- var entry = CreateInternalEntry(
- contextServices,
- ownedType,
- new OwnedClass
- {
- Value = "Kool"
- },
- new ValueBuffer(new object[] { 1, "Kool" }));
-
- entry.SetEntityState(entityState);
-
- if (entityState != EntityState.Unchanged)
+ using (var context = new TKContext())
{
- entry[valueProperty] = "Pickle";
- }
+ var entry = context.Entry(new TSomeEntity()).GetInfrastructure();
+ var entityType = entry.EntityType;
+ var keyProperty = entityType.FindProperty("Id");
+ var nonKeyProperty = entityType.FindProperty("Name");
+ entry[keyProperty] = 1;
+ entry[nonKeyProperty] = "Kool";
- entry.SetOriginalValue(valueProperty, "Cheese");
+ entry.SetEntityState(entityState);
- entry.AcceptChanges();
+ entry.AcceptChanges();
- Assert.Equal(
- entityState == EntityState.Deleted || entityState == EntityState.Detached ? EntityState.Detached : EntityState.Unchanged,
- entry.EntityState);
- if (entityState == EntityState.Unchanged)
- {
- Assert.Equal("Kool", entry[valueProperty]);
- Assert.Equal("Kool", entry.GetOriginalValue(valueProperty));
- }
- else
- {
- Assert.Equal("Pickle", entry[valueProperty]);
- Assert.Equal(
- entityState == EntityState.Detached || entityState == EntityState.Deleted ? "Cheese" : "Pickle",
- entry.GetOriginalValue(valueProperty));
+ Assert.Equal(entityState, entry.EntityState);
}
}
- [ConditionalFact]
- public virtual void Non_transparent_sidecar_does_not_intercept_normal_property_read_and_write()
+ [ConditionalTheory]
+ [InlineData(EntityState.Modified)]
+ [InlineData(EntityState.Added)]
+ public void AcceptChanges_makes_entities_Unchanged(EntityState entityState)
{
- var model = BuildModel();
- var entityType = model.FindEntityType(typeof(SomeEntity).FullName);
- var idProperty = entityType.FindProperty("Id");
- var nameProperty = entityType.FindProperty("Name");
-
- var entry = CreateInternalEntry(
- InMemoryTestHelpers.Instance.CreateContextServices(model),
- entityType,
- new SomeEntity
- {
- Id = 1,
- Name = "Kool"
- },
- new ValueBuffer(new object[] { 1, "Kool" }));
-
- entry.SetEntityState(EntityState.Added);
+ using (var context = new TKContext())
+ {
+ var entry = context.Entry(new TSomeEntity()).GetInfrastructure();
+ var entityType = entry.EntityType;
+ var keyProperty = entityType.FindProperty("Id");
+ var nameProperty = entityType.FindProperty("Name");
- Assert.Equal(1, entry[idProperty]);
- Assert.Equal("Kool", entry[nameProperty]);
+ entry[keyProperty] = 1;
+ entry[nameProperty] = "Kool";
- entry.SetOriginalValue(idProperty, 7);
+ entry.SetEntityState(entityState);
- Assert.Equal(1, entry[idProperty]);
- Assert.Equal("Kool", entry[nameProperty]);
+ entry[nameProperty] = "Pickle";
+ entry.SetOriginalValue(nameProperty, "Cheese");
- entry[idProperty] = 77;
+ entry.AcceptChanges();
- Assert.Equal(77, entry[idProperty]);
- Assert.Equal("Kool", entry[nameProperty]);
+ Assert.Equal(EntityState.Unchanged, entry.EntityState);
+ Assert.Equal("Pickle", entry[nameProperty]);
+ Assert.Equal("Pickle", entry.GetOriginalValue(nameProperty));
+ }
}
- private static IModel BuildOneToOneModel()
+ [ConditionalFact]
+ public virtual void AcceptChanges_makes_Modified_entities_Unchanged_and_effectively_resets_unused_original_values()
{
- var modelBuilder = InMemoryTestHelpers.Instance.CreateConventionBuilder();
+ using (var context = new TKContext())
+ {
+ var entry = context.Entry(new TSomeEntity()).GetInfrastructure();
+ var entityType = entry.EntityType;
+ var keyProperty = entityType.FindProperty("Id");
+ var nameProperty = entityType.FindProperty("Name");
- modelBuilder
- .Entity()
- .HasOne(e => e.Second)
- .WithOne(e => e.First)
- .HasForeignKey(e => e.Id)
- .OnDelete(DeleteBehavior.Cascade);
+ entry[keyProperty] = 1;
+ entry[nameProperty] = "Kool";
- modelBuilder
- .Entity(
- b =>
- {
- b.Property(e => e.Id).ValueGeneratedNever();
+ entry.SetEntityState(EntityState.Modified);
- b.HasOne(e => e.First)
- .WithOne(e => e.Root)
- .HasForeignKey(e => e.Id);
- });
+ entry[nameProperty] = "Pickle";
+
+ entry.AcceptChanges();
- return modelBuilder.FinalizeModel();
+ Assert.Equal(EntityState.Unchanged, entry.EntityState);
+ Assert.Equal("Pickle", entry[nameProperty]);
+ Assert.Equal("Pickle", entry.GetOriginalValue(nameProperty));
+ }
}
- private static IModel BuildOneToOneCompositeModel(bool required)
+ [ConditionalFact]
+ public virtual void AcceptChanges_detaches_Deleted_entities()
{
- var modelBuilder = InMemoryTestHelpers.Instance.CreateConventionBuilder();
+ using (var context = new TKContext())
+ {
+ var entry = context.Entry(new TSomeEntity()).GetInfrastructure();
+ var entityType = entry.EntityType;
+ var keyProperty = entityType.FindProperty("Id");
+ var nameProperty = entityType.FindProperty("Name");
- modelBuilder
- .Entity()
- .HasKey(
- e => new
- {
- e.Id1,
- e.Id2
- });
+ entry[keyProperty] = 1;
+ entry[nameProperty] = "Kool";
- modelBuilder
- .Entity()
- .HasKey(
- e => new
- {
- e.Id1,
- e.Id2
- });
+ entry.SetEntityState(EntityState.Deleted);
- modelBuilder
- .Entity()
- .HasKey(
- e => new
- {
- e.Id1,
- e.Id2
- });
-
- modelBuilder
- .Entity()
- .HasOne(e => e.First)
- .WithOne(e => e.Root)
- .HasForeignKey(
- e => new
- {
- e.RootId1,
- e.RootId2
- })
- .IsRequired(required);
-
- modelBuilder
- .Entity()
- .HasOne(e => e.Second)
- .WithOne(e => e.First)
- .HasForeignKey(
- e => new
- {
- e.FirstId1,
- e.FirstId2
- })
- .IsRequired(required);
+ entry.AcceptChanges();
- return modelBuilder.FinalizeModel();
+ Assert.Equal(EntityState.Detached, entry.EntityState);
+ }
}
[ConditionalFact]
public void Unchanged_entity_with_conceptually_null_FK_with_cascade_delete_is_marked_Deleted()
{
- var model = BuildOneToOneModel();
- var entityType = model.FindEntityType(typeof(SecondDependent).FullName);
- var fkProperty = entityType.FindProperty("Id");
-
- var entry = CreateInternalEntry(InMemoryTestHelpers.Instance.CreateContextServices(model), entityType, new SecondDependent());
+ using (var context = new KcContext())
+ {
+ var entry = context.Entry(new TSecondDependent()).GetInfrastructure();
+ var fkProperty = entry.EntityType.FindProperty("Id");
- entry[fkProperty] = 77;
- entry.SetEntityState(EntityState.Unchanged);
+ entry[fkProperty] = 77;
+ entry.SetEntityState(EntityState.Unchanged);
- entry[fkProperty] = null;
- entry.HandleConceptualNulls(false, force: false, isCascadeDelete: false);
+ entry[fkProperty] = null;
+ entry.HandleConceptualNulls(false, force: false, isCascadeDelete: false);
- Assert.Equal(EntityState.Deleted, entry.EntityState);
+ Assert.Equal(EntityState.Deleted, entry.EntityState);
+ }
}
[ConditionalFact]
public void Added_entity_with_conceptually_null_FK_with_cascade_delete_is_detached()
{
- var model = BuildOneToOneModel();
- var entityType = model.FindEntityType(typeof(SecondDependent).FullName);
- var fkProperty = entityType.FindProperty("Id");
-
- var entry = CreateInternalEntry(InMemoryTestHelpers.Instance.CreateContextServices(model), entityType, new SecondDependent());
+ using (var context = new KcContext())
+ {
+ var entry = context.Entry(new TSecondDependent()).GetInfrastructure();
+ var fkProperty = entry.EntityType.FindProperty("Id");
- entry[fkProperty] = 77;
- entry.SetEntityState(EntityState.Added);
+ entry[fkProperty] = 77;
+ entry.SetEntityState(EntityState.Added);
- entry[fkProperty] = null;
- entry.HandleConceptualNulls(false, force: false, isCascadeDelete: false);
+ entry[fkProperty] = null;
+ entry.HandleConceptualNulls(false, force: false, isCascadeDelete: false);
- Assert.Equal(EntityState.Detached, entry.EntityState);
+ Assert.Equal(EntityState.Detached, entry.EntityState);
+ }
}
[ConditionalFact]
public void Entity_with_partially_null_composite_FK_with_cascade_delete_is_marked_Deleted()
{
- var model = BuildOneToOneCompositeModel(required: true);
- var entityType = model.FindEntityType(typeof(CompositeSecondDependent).FullName);
- var fkProperty1 = entityType.FindProperty("FirstId1");
- var fkProperty2 = entityType.FindProperty("FirstId2");
-
- var entry = CreateInternalEntry(
- InMemoryTestHelpers.Instance.CreateContextServices(model), entityType, new CompositeSecondDependent());
+ using (var context = new KcrContext())
+ {
+ var entry = context.Entry(new TCompositeSecondDependent()).GetInfrastructure();
+ var entityType = entry.EntityType;
+ var fkProperty1 = entityType.FindProperty("FirstId1");
+ var fkProperty2 = entityType.FindProperty("FirstId2");
- entry[entityType.FindProperty("Id1")] = 66;
- entry[entityType.FindProperty("Id2")] = "Bar";
- entry[fkProperty1] = 77;
- entry[fkProperty2] = "Foo";
- entry.SetEntityState(EntityState.Unchanged);
+ entry[entityType.FindProperty("Id1")] = 66;
+ entry[entityType.FindProperty("Id2")] = "Bar";
+ entry[fkProperty1] = 77;
+ entry[fkProperty2] = "Foo";
+ entry.SetEntityState(EntityState.Unchanged);
- entry[fkProperty1] = null;
- entry.HandleConceptualNulls(false, force: false, isCascadeDelete: false);
+ entry[fkProperty1] = null;
+ entry.HandleConceptualNulls(false, force: false, isCascadeDelete: false);
- Assert.Equal(EntityState.Deleted, entry.EntityState);
+ Assert.Equal(EntityState.Deleted, entry.EntityState);
+ }
}
[ConditionalFact]
public void Entity_with_partially_null_composite_FK_without_cascade_delete_is_orphaned()
{
- var model = BuildOneToOneCompositeModel(required: false);
- var entityType = model.FindEntityType(typeof(CompositeSecondDependent).FullName);
- var fkProperty1 = entityType.FindProperty("FirstId1");
- var fkProperty2 = entityType.FindProperty("FirstId2");
-
- var entry = CreateInternalEntry(
- InMemoryTestHelpers.Instance.CreateContextServices(model), entityType, new CompositeSecondDependent());
-
- entry[entityType.FindProperty("Id1")] = 66;
- entry[entityType.FindProperty("Id2")] = "Bar";
- entry[fkProperty1] = 77;
- entry[fkProperty2] = "Foo";
- entry.SetEntityState(EntityState.Unchanged);
-
- entry[fkProperty1] = null;
- entry.HandleConceptualNulls(false, force: false, isCascadeDelete: false);
-
- Assert.Equal(EntityState.Modified, entry.EntityState);
-
- Assert.Equal(77, entry[fkProperty1]);
- Assert.Null(entry[fkProperty2]);
- }
-
- // ReSharper disable once ClassNeverInstantiated.Local
- private class Root
- {
- public int Id { get; set; }
-
- public FirstDependent First { get; set; }
- }
-
- // ReSharper disable once ClassNeverInstantiated.Local
- private class FirstDependent
- {
- public int Id { get; set; }
-
- public Root Root { get; set; }
+ using (var context = new KcContext())
+ {
+ var entry = context.Entry(new TCompositeSecondDependent()).GetInfrastructure();
+ var entityType = entry.EntityType;
+ var fkProperty1 = entityType.FindProperty("FirstId1");
+ var fkProperty2 = entityType.FindProperty("FirstId2");
- public SecondDependent Second { get; set; }
- }
+ entry[entityType.FindProperty("Id1")] = 66;
+ entry[entityType.FindProperty("Id2")] = "Bar";
+ entry[fkProperty1] = 77;
+ entry[fkProperty2] = "Foo";
+ entry.SetEntityState(EntityState.Unchanged);
- private class SecondDependent
- {
- public int Id { get; set; }
+ entry[fkProperty1] = null;
+ entry.HandleConceptualNulls(false, force: false, isCascadeDelete: false);
- public FirstDependent First { get; set; }
- }
+ Assert.Equal(EntityState.Modified, entry.EntityState);
- // ReSharper disable once ClassNeverInstantiated.Local
- private class CompositeRoot
- {
- public int Id1 { get; set; }
- public string Id2 { get; set; }
-
- public CompositeFirstDependent First { get; set; }
+ Assert.Equal(77, entry[fkProperty1]);
+ Assert.Null(entry[fkProperty2]);
+ }
}
- // ReSharper disable once ClassNeverInstantiated.Local
- private class CompositeFirstDependent
+ public class KContext : DbContext
{
- public int Id1 { get; set; }
- public string Id2 { get; set; }
-
- public int RootId1 { get; set; }
- public string RootId2 { get; set; }
-
- // ReSharper disable once MemberHidesStaticFromOuterClass
- public CompositeRoot Root { get; set; }
-
- public CompositeSecondDependent Second { get; set; }
- }
+ protected internal override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ => optionsBuilder.UseInMemoryDatabase(Guid.NewGuid().ToString());
- private class CompositeSecondDependent
- {
- public int Id1 { get; set; }
- public string Id2 { get; set; }
+ protected internal override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property("Id");
+ b.HasKey("Id");
+ b.Property("NonId").ValueGeneratedOnAdd();
+ b.HasAlternateKey("NonId");
+ });
- public int FirstId1 { get; set; }
- public string FirstId2 { get; set; }
- public CompositeFirstDependent First { get; set; }
- }
+ modelBuilder.Entity().Property("Name").IsConcurrencyToken().ValueGeneratedOnAdd();
- protected virtual InternalEntityEntry CreateInternalEntry(
- IServiceProvider contextServices, IEntityType entityType, object entity)
- => contextServices
- .GetRequiredService()
- .GetOrCreateEntry(entity, entityType);
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property("Id1");
+ b.Property("Id2");
+ b.HasKey("Id1", "Id2");
+ });
- protected virtual InternalEntityEntry CreateInternalEntry(
- IServiceProvider contextServices, IEntityType entityType, object entity, in ValueBuffer valueBuffer)
- => contextServices
- .GetRequiredService()
- .StartTrackingFromQuery(entityType, entity, valueBuffer, new HashSet());
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property("SomeEntityId");
+ b.HasOne().WithMany().HasForeignKey("SomeEntityId");
+ b.Property("JustAProperty").HasValueGenerator((p, e) => new InMemoryIntegerValueGenerator(p.GetIndex()));
+ });
- protected virtual IMutableModel BuildModel(bool finalize = true)
- {
- var modelBuilder = new ModelBuilder(new ConventionSet());
- var model = modelBuilder.Model;
-
- var someSimpleEntityType = model.AddEntityType(typeof(SomeSimpleEntityBase));
- var simpleKeyProperty = someSimpleEntityType.AddProperty("Id", typeof(int));
- simpleKeyProperty.ValueGenerated = ValueGenerated.OnAdd;
- someSimpleEntityType.SetPrimaryKey(simpleKeyProperty);
-
- var someCompositeEntityType = model.AddEntityType(typeof(SomeCompositeEntityBase));
- var compositeKeyProperty1 = someCompositeEntityType.AddProperty("Id1", typeof(int));
- var compositeKeyProperty2 = someCompositeEntityType.AddProperty("Id2", typeof(string));
- compositeKeyProperty2.IsNullable = false;
- someCompositeEntityType.SetPrimaryKey(new[] { compositeKeyProperty1, compositeKeyProperty2 });
-
- var entityType1 = model.AddEntityType(typeof(SomeEntity));
- entityType1.BaseType = someSimpleEntityType;
- var property3 = entityType1.AddProperty("Name", typeof(string));
- property3.IsConcurrencyToken = true;
- property3.ValueGenerated = ValueGenerated.OnAdd;
-
- var entityType2 = model.AddEntityType(typeof(SomeDependentEntity));
- entityType2.BaseType = someCompositeEntityType;
- var fk = entityType2.AddProperty("SomeEntityId", typeof(int));
- entityType2.AddForeignKey(new[] { fk }, entityType1.FindPrimaryKey(), entityType1);
- // TODO: declare this on the derived type
- // #2611
- var justAProperty = someCompositeEntityType.AddProperty("JustAProperty", typeof(int));
- justAProperty.ValueGenerated = ValueGenerated.OnAdd;
- someCompositeEntityType.AddKey(justAProperty);
-
- var entityType3 = model.AddEntityType(typeof(FullNotificationEntity));
- var property6 = entityType3.AddProperty("Id", typeof(int));
- entityType3.SetPrimaryKey(property6);
- var property7 = entityType3.AddProperty("Name", typeof(string));
- property7.IsConcurrencyToken = true;
- entityType3.SetChangeTrackingStrategy(ChangeTrackingStrategy.ChangingAndChangedNotifications);
-
- var entityType4 = model.AddEntityType(typeof(ChangedOnlyEntity));
- var property8 = entityType4.AddProperty("Id", typeof(int));
- entityType4.SetPrimaryKey(property8);
- var property9 = entityType4.AddProperty("Name", typeof(string));
- property9.IsConcurrencyToken = true;
- entityType4.SetChangeTrackingStrategy(ChangeTrackingStrategy.ChangedNotifications);
-
- var entityType5 = model.AddEntityType(typeof(SomeMoreDependentEntity));
- entityType5.BaseType = someSimpleEntityType;
- var fk5a = entityType5.AddProperty("Fk1", typeof(int));
- var fk5b = entityType5.AddProperty("Fk2", typeof(string));
- entityType5.AddForeignKey(new[] { fk5a, fk5b }, entityType2.FindPrimaryKey(), entityType2);
-
- modelBuilder.Entity(
- eb =>
- {
- eb.HasKey(e => e.Id);
- var owned = eb.OwnsOne(e => e.Owned);
- owned.WithOwner().HasForeignKey("Id");
- owned.HasKey("Id");
- owned.Property(e => e.Value);
- });
-
- return finalize ? (IMutableModel)model.FinalizeModel() : model;
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property("Fk11");
+ b.Property("Fk2");
+ b.HasOne().WithMany().HasForeignKey("Fk1", "Fk2");
+ });
+ }
}
- protected interface ISomeEntity
+ public class KcContext : KContext
{
- int Id { get; set; }
- string Name { get; set; }
- }
+ protected internal override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property("Id");
+ b.HasOne(e => (TSecondDependent)e.Second)
+ .WithOne(e => (TFirstDependent)e.First)
+ .HasForeignKey("Id")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
- protected class SomeSimpleEntityBase
- {
- public int Id { get; set; }
- }
+ modelBuilder
+ .Entity(
+ b =>
+ {
+ b.Property("Id").ValueGeneratedNever();
+ b.HasOne(e => (TFirstDependent)e.First)
+ .WithOne(e => (TRoot)e.Root)
+ .HasForeignKey("Id");
+ });
+
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property("Id1");
+ b.Property("Id2");
+ b.HasKey("Id1", "Id2");
+ });
- protected class SomeEntity : SomeSimpleEntityBase, ISomeEntity
- {
- public string Name { get; set; }
- }
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property("Id1");
+ b.Property("Id2");
+ b.Property("RootId1");
+ b.Property("RootId2");
+ b.HasKey("Id1", "Id2");
+ });
- protected class SomeCompositeEntityBase
- {
- public int Id1 { get; set; }
- public string Id2 { get; set; }
- }
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property("FirstId1");
+ b.Property("FirstId2");
+ b.Property("Id1");
+ b.Property("Id2");
+ b.HasKey("Id1", "Id2");
+ });
- protected class SomeDependentEntity : SomeCompositeEntityBase
- {
- public int SomeEntityId { get; set; }
- public int JustAProperty { get; set; }
- }
+ modelBuilder.Entity(
+ b =>
+ {
+ b.HasOne(e => (TCompositeFirstDependent)e.First)
+ .WithOne(e => (TCompositeRoot)e.Root)
+ .HasForeignKey("RootId1", "RootId2")
+ .IsRequired(false);
+ });
- protected class SomeMoreDependentEntity : SomeSimpleEntityBase
- {
- public int Fk1 { get; set; }
- public string Fk2 { get; set; }
+ modelBuilder.Entity(
+ b =>
+ {
+ b.HasOne(e => (TCompositeSecondDependent)e.Second)
+ .WithOne(e => (TCompositeFirstDependent)e.First)
+ .HasForeignKey("FirstId1", "FirstId2")
+ .IsRequired(false);
+ });
+ }
}
- protected class FullNotificationEntity : INotifyPropertyChanging, INotifyPropertyChanged, ISomeEntity
+ public class KcrContext : KcContext
{
- private int _id;
- private string _name;
-
- public int Id
+ protected internal override void OnModelCreating(ModelBuilder modelBuilder)
{
- get => _id;
- set
- {
- if (_id != value)
+ base.OnModelCreating(modelBuilder);
+
+ modelBuilder.Entity(
+ b =>
{
- NotifyChanging();
- _id = value;
- NotifyChanged();
- }
- }
- }
+ b.Property("Id1");
+ b.Property("Id2");
+ b.HasKey("Id1", "Id2");
+ b.HasOne(e => (TCompositeFirstDependent)e.First)
+ .WithOne(e => (TCompositeRoot)e.Root)
+ .HasForeignKey("RootId1", "RootId2")
+ .IsRequired();
+ });
- public string Name
- {
- get => _name;
- set
- {
- if (_name != value)
+ modelBuilder.Entity(
+ b =>
{
- NotifyChanging();
- _name = value;
- NotifyChanged();
- }
- }
+ b.HasOne(e => (TCompositeSecondDependent)e.Second)
+ .WithOne(e => (TCompositeFirstDependent)e.First)
+ .HasForeignKey("FirstId1", "FirstId2")
+ .IsRequired();
+ });
}
-
- public event PropertyChangingEventHandler PropertyChanging;
- public event PropertyChangedEventHandler PropertyChanged;
-
- private void NotifyChanged([CallerMemberName] string propertyName = "")
- => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
-
- private void NotifyChanging([CallerMemberName] string propertyName = "")
- => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
}
- protected class ChangedOnlyEntity : INotifyPropertyChanged, ISomeEntity
+ public class KSnapContext : KContext
{
- private int _id;
- private string _name;
-
- public int Id
+ protected internal override void OnModelCreating(ModelBuilder modelBuilder)
{
- get => _id;
- set
- {
- if (_id != value)
+ modelBuilder.Entity(
+ b =>
{
- _id = value;
- NotifyChanged();
- }
- }
+ b.Property