Skip to content

Commit

Permalink
Cosmos: Fail in model validation for owned types that are mapped to a…
Browse files Browse the repository at this point in the history
… different container.

Fixes #26538
  • Loading branch information
AndriySvyryd authored Aug 10, 2022
1 parent 1e122ac commit d6f1418
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ protected virtual void ValidateSharedContainerCompatibility(
continue;
}

var ownership = entityType.FindOwnership();
if (ownership != null)
{
throw new InvalidOperationException(CosmosStrings.OwnedTypeDifferentContainer(
entityType.DisplayName(), ownership.PrincipalEntityType.DisplayName(), container));
}

if (!containers.TryGetValue(container, out var mappedTypes))
{
mappedTypes = new List<IEntityType>();
Expand Down
8 changes: 8 additions & 0 deletions src/EFCore.Cosmos/Properties/CosmosStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/EFCore.Cosmos/Properties/CosmosStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@
<data name="OrphanedNestedDocumentSensitive" xml:space="preserve">
<value>The entity of type '{entityType}' is mapped as part of the document mapped to '{missingEntityType}', but there is no tracked entity of this type with the key value '{keyValue}'.</value>
</data>
<data name="OwnedTypeDifferentContainer" xml:space="preserve">
<value>The entity type '{entityType}' is owned by the entity type '{owner}', but is mapped to the container '{container}'. Owned types mapped to a container directly are not supported, remove this configuration to allow the owned type to be embedded in the same document as the owner.</value>
</data>
<data name="PartitionKeyMismatch" xml:space="preserve">
<value>The partition key specified in the 'WithPartitionKey' call '{partitionKey1}' and the partition key specified in the 'Where' predicate '{partitionKey2}' must be identical to return any results. Remove one of them.</value>
</data>
Expand Down
40 changes: 20 additions & 20 deletions src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ private static void ValidateSproc(IStoredProcedure sproc, string mappingStrategy
RelationalStrings.StoredProcedureKeyless(
entityType.DisplayName(), storeObjectIdentifier.DisplayName()));
}

var properties = entityType.GetDeclaredProperties().ToDictionary(p => p.Name);
if (mappingStrategy == RelationalAnnotationNames.TphMappingStrategy)
{
Expand Down Expand Up @@ -339,12 +339,12 @@ private static void ValidateSproc(IStoredProcedure sproc, string mappingStrategy
{
break;
}

foreach (var property in baseType.GetDeclaredProperties())
{
properties.Add(property.Name, property);
}

baseType = baseType.BaseType;
}
}
Expand Down Expand Up @@ -372,14 +372,14 @@ private static void ValidateSproc(IStoredProcedure sproc, string mappingStrategy
RelationalStrings.StoredProcedureResultColumnNotFound(
resultColumn.PropertyName, entityType.DisplayName(), storeObjectIdentifier.DisplayName()));
}

if (!resultColumnNames.Add(resultColumn.Name))
{
throw new InvalidOperationException(
RelationalStrings.StoredProcedureDuplicateResultColumnName(
resultColumn.Name, storeObjectIdentifier.DisplayName()));
}

if (resultColumn.PropertyName == null)
{
continue;
Expand All @@ -406,7 +406,7 @@ private static void ValidateSproc(IStoredProcedure sproc, string mappingStrategy
break;
}
}

var parameterNames = new HashSet<string>();
foreach (var parameter in sproc.Parameters)
{
Expand All @@ -429,14 +429,14 @@ private static void ValidateSproc(IStoredProcedure sproc, string mappingStrategy
parameter.PropertyName, entityType.DisplayName(), storeObjectIdentifier.DisplayName()));
}
}

if (!parameterNames.Add(parameter.Name))
{
throw new InvalidOperationException(
RelationalStrings.StoredProcedureDuplicateParameterName(
parameter.Name, storeObjectIdentifier.DisplayName()));
}

if (parameter.PropertyName == null)
{
continue;
Expand Down Expand Up @@ -472,7 +472,7 @@ private static void ValidateSproc(IStoredProcedure sproc, string mappingStrategy
RelationalStrings.StoredProcedureDeleteNonKeyProperty(
entityType.DisplayName(), parameter.PropertyName, storeObjectIdentifier.DisplayName()));
}

break;
default:
Check.DebugFail("Unexpected stored procedure type: " + storeObjectIdentifier.StoreObjectType);
Expand All @@ -486,17 +486,17 @@ private static void ValidateSproc(IStoredProcedure sproc, string mappingStrategy
{
continue;
}

properties.Remove(resultColumn.PropertyName);

if (!storeGeneratedProperties.Remove(resultColumn.PropertyName))
{
throw new InvalidOperationException(
RelationalStrings.StoredProcedureResultColumnParameterConflict(
entityType.DisplayName(), resultColumn.PropertyName, storeObjectIdentifier.DisplayName()));
}
}

if (storeGeneratedProperties.Count > 0)
{
throw new InvalidOperationException(
Expand Down Expand Up @@ -1098,7 +1098,7 @@ protected virtual void ValidateSharedColumnsCompatibility(
{
continue;
}

missingConcurrencyTokens?.Remove(columnName);
if (!propertyMappings.TryGetValue(columnName, out var duplicateProperty))
{
Expand Down Expand Up @@ -1700,7 +1700,7 @@ protected override void ValidateInheritanceMapping(
RelationalStrings.AbstractTpc(entityType.DisplayName(), storeObject));
}
}

foreach (var key in entityType.GetKeys())
{
ValidateValueGeneration(entityType, key, logger);
Expand Down Expand Up @@ -1739,12 +1739,12 @@ protected override void ValidateInheritanceMapping(
ValidateTphMapping(entityType, StoreObjectType.InsertStoredProcedure);
ValidateTphMapping(entityType, StoreObjectType.DeleteStoredProcedure);
ValidateTphMapping(entityType, StoreObjectType.UpdateStoredProcedure);

ValidateDiscriminatorValues(entityType);
}
else
{
if (mappingStrategy != RelationalAnnotationNames.TpcMappingStrategy
if (mappingStrategy != RelationalAnnotationNames.TpcMappingStrategy
&& entityType.FindPrimaryKey() == null)
{
throw new InvalidOperationException(
Expand Down Expand Up @@ -1957,7 +1957,7 @@ private static void ValidateTphMapping(IEntityType rootEntityType, StoreObjectTy
protected override bool IsRedundant(IForeignKey foreignKey)
=> base.IsRedundant(foreignKey)
&& !foreignKey.DeclaringEntityType.GetMappingFragments().Any();

/// <summary>
/// Validates the entity type mapping fragments.
/// </summary>
Expand Down Expand Up @@ -2027,7 +2027,7 @@ protected virtual void ValidateMappingFragments(

continue;
}

if (!property.IsPrimaryKey())
{
propertiesFound = true;
Expand Down Expand Up @@ -2218,7 +2218,7 @@ private static IEnumerable<StoreObjectIdentifier> GetAllMappedStoreObjects(
{
yield return declaringStoreObject.Value;
}

foreach (var fragment in fragments)
{
overrides = RelationalPropertyOverrides.Find(property, fragment.StoreObject);
Expand Down Expand Up @@ -2261,7 +2261,7 @@ private static IEnumerable<StoreObjectIdentifier> GetAllMappedStoreObjects(
queue.Enqueue(containingType);
}
}
}
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/EFCore.Relational/Metadata/IStoreStoredProcedure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ public interface IStoreStoredProcedure : ITableBase
/// Gets the entity type mappings.
/// </summary>
new IEnumerable<IStoredProcedureMapping> EntityTypeMappings { get; }

/// <summary>
/// Gets the return for this stored procedure.
/// </summary>
IStoreStoredProcedureReturnValue? ReturnValue { get; }

/// <summary>
/// Gets the parameters for this stored procedure.
/// </summary>
Expand Down Expand Up @@ -81,7 +81,7 @@ string ToDebugString(MetadataDebugStringOptions options = MetadataDebugStringOpt
builder
.Append(indentString)
.Append("StoreStoredProcedure: ");

if (Schema != null)
{
builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public StoreStoredProcedure(IRuntimeStoredProcedure sproc, RelationalModel model
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual SortedSet<IStoredProcedure> StoredProcedures { get; }

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,23 @@ public virtual void Detects_property_and_embedded_type_mapped_to_same_property()
nameof(Order.OrderDetails), nameof(Order.PartitionId), typeof(Order).Name, "Details"), modelBuilder);
}

[ConditionalFact]
public virtual void Detects_owned_type_mapped_to_a_container()
{
var modelBuilder = CreateConventionModelBuilder();
modelBuilder.Entity<Customer>();
modelBuilder.Entity<Order>(
ob =>
{
var ownedType = ob.OwnsOne(o => o.OrderDetails).OwnedEntityType;
ownedType.SetContainer("Details");
});

VerifyError(
CosmosStrings.OwnedTypeDifferentContainer(
nameof(OrderDetails), nameof(Order), "Details"), modelBuilder);
}

[ConditionalFact]
public virtual void Detects_missing_discriminator()
{
Expand Down

0 comments on commit d6f1418

Please sign in to comment.