Skip to content

Commit

Permalink
Cleanup CosmosJsonIdConvention
Browse files Browse the repository at this point in the history
  • Loading branch information
AndriySvyryd committed Dec 18, 2024
1 parent b8ddc5b commit 8b8892e
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 35 deletions.
29 changes: 9 additions & 20 deletions src/EFCore.Cosmos/Metadata/Conventions/CosmosJsonIdConvention.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,10 @@ private void ProcessEntityType(IConventionEntityType entityType, IConventionCont
var computedIdProperty = entityType.FindDeclaredProperty(DefaultIdPropertyName);

var primaryKey = entityType.FindPrimaryKey();
if (entityType.BaseType != null // Requires: IEntityTypeBaseTypeChangedConvention
|| !entityType.IsDocumentRoot() // Requires: IEntityTypeAnnotationChangedConvention (ContainerName)
|| entityType.GetForeignKeys()
.Any(fk => fk.IsOwnership) // Requires: IForeignKeyOwnershipChangedConvention, IForeignKeyRemovedConvention
|| primaryKey == null) // Requires: IKeyAddedConvention, IKeyRemovedConvention
if (entityType.BaseType != null
|| !entityType.IsDocumentRoot()
|| entityType.GetForeignKeys().Any(fk => fk.IsOwnership)
|| primaryKey == null)
{
// If the entity type is not a keyed, root document in the container, then it doesn't have an `id` mapping, so
// undo anything that was done by previous execution of this convention.
Expand All @@ -93,7 +92,8 @@ private void ProcessEntityType(IConventionEntityType entityType, IConventionCont
if (computedIdProperty is not null
&& computedIdProperty != jsonIdProperty)
{
entityType.Builder.RemoveUnusedImplicitProperties([computedIdProperty]); }
entityType.Builder.RemoveUnusedImplicitProperties([computedIdProperty]);
}

return;
}
Expand All @@ -102,17 +102,9 @@ private void ProcessEntityType(IConventionEntityType entityType, IConventionCont
// key is represented by a single string property, and the discriminator is not being included in the JSON `id`.
// If these conditions are not met, or if the user has opted-in, then we will create a computed property that transforms
// the appropriate values into a single string for the JSON `id` property.

// The line below requires: IModelAnnotationChangedConvention, IPropertyAnnotationChangedConvention
var alwaysCreateId = entityType.GetHasShadowId();
if (alwaysCreateId != true)
{
// The line below requires:
// - IModelAnnotationChangedConvention, IPropertyAnnotationChangedConvention
// - IKeyAddedConvention, IKeyRemovedConvention
// - IPropertyAddedConvention, IPropertyRemovedConvention
// - IDiscriminatorPropertySetConvention
// - IEntityTypeBaseTypeChangedConvention
var idDefinition = DefinitionFactory.Create((IEntityType)entityType)!;
if (idDefinition is { IncludesDiscriminator: false, Properties.Count: 1 })
{
Expand Down Expand Up @@ -183,13 +175,10 @@ private void ProcessEntityType(IConventionEntityType entityType, IConventionCont
return;
}

if (computedIdPropertyBuilder.Metadata.GetJsonPropertyName() != IdPropertyJsonName)
{
computedIdPropertyBuilder = computedIdPropertyBuilder.ToJsonProperty(IdPropertyJsonName)
?? computedIdPropertyBuilder;
}

// Don't chain, because each of these could return null if the property has been explicitly configured with some other value.
computedIdPropertyBuilder = computedIdPropertyBuilder.ToJsonProperty(IdPropertyJsonName)
?? computedIdPropertyBuilder;

computedIdPropertyBuilder = computedIdPropertyBuilder.IsRequired(true)
?? computedIdPropertyBuilder;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ public virtual void Hierarchical_partition_key_is_added_to_the_alternate_key_if_
{
var modelBuilder = CreateModelBuilder();

modelBuilder.Entity<Customer>().AlwaysHasShadowId();
modelBuilder.Entity<Customer>().HasShadowId();
modelBuilder.Entity<Customer>().HasKey(CosmosJsonIdConvention.DefaultIdPropertyName);

modelBuilder.Entity<Customer>()
Expand Down Expand Up @@ -311,7 +311,7 @@ public virtual void No_alternate_key_is_created_if_primary_key_contains_id()
{
var modelBuilder = CreateModelBuilder();

modelBuilder.Entity<Customer>().AlwaysHasShadowId();
modelBuilder.Entity<Customer>().HasShadowId();
modelBuilder.Entity<Customer>().HasKey(CosmosJsonIdConvention.DefaultIdPropertyName);

modelBuilder.Entity<Customer>()
Expand All @@ -335,7 +335,7 @@ public virtual void No_alternate_key_is_created_if_primary_key_contains_id_and_p
{
var modelBuilder = CreateModelBuilder();

modelBuilder.Entity<Customer>().AlwaysHasShadowId();
modelBuilder.Entity<Customer>().HasShadowId();
modelBuilder.Entity<Customer>().HasKey(nameof(Customer.AlternateKey), CosmosJsonIdConvention.DefaultIdPropertyName);

modelBuilder.Entity<Customer>()
Expand All @@ -359,7 +359,7 @@ public virtual void No_alternate_key_is_created_if_primary_key_contains_id_and_h
{
var modelBuilder = CreateModelBuilder();

modelBuilder.Entity<Customer>().AlwaysHasShadowId();
modelBuilder.Entity<Customer>().HasShadowId();

modelBuilder.Entity<Customer>().HasKey(
nameof(Customer.AlternateKey),
Expand Down Expand Up @@ -404,7 +404,7 @@ public virtual void No_alternate_key_is_created_if_primary_key_contains_id_and_h
{
var modelBuilder = CreateModelBuilder();

modelBuilder.Entity<Customer>().AlwaysHasShadowId();
modelBuilder.Entity<Customer>().HasShadowId();

modelBuilder.Entity<Customer>().HasKey(
nameof(Customer.Title),
Expand Down Expand Up @@ -449,7 +449,7 @@ public virtual void Hierarchical_partition_key_is_added_to_the_alternate_key_if_
{
var modelBuilder = CreateModelBuilder();

modelBuilder.Entity<Customer>().AlwaysHasShadowId();
modelBuilder.Entity<Customer>().HasShadowId();

modelBuilder.Entity<Customer>().HasKey(
nameof(Customer.Title),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,49 @@ namespace Microsoft.EntityFrameworkCore.ModelBuilding;

public static class CosmosTestModelBuilderExtensions
{
public static ModelBuilderTest.TestEntityTypeBuilder<TEntity> HasPartitionKey<TEntity, TProperty>(
public static ModelBuilderTest.TestModelBuilder HasShadowIds(
this ModelBuilderTest.TestModelBuilder builder,
bool? alwaysCreate = true)
{
if (builder is IInfrastructure<ModelBuilder> nonGenericBuilder)
{
nonGenericBuilder.Instance.HasShadowIds(alwaysCreate);
}

return builder;
}

public static ModelBuilderTest.TestEntityTypeBuilder<TEntity> HasShadowId<TEntity>(
this ModelBuilderTest.TestEntityTypeBuilder<TEntity> builder,
Expression<Func<TEntity, TProperty>> propertyExpression)
bool? alwaysCreate = true)
where TEntity : class
{
switch (builder)
{
case IInfrastructure<EntityTypeBuilder<TEntity>> genericBuilder:
genericBuilder.Instance.HasPartitionKey(propertyExpression);
genericBuilder.Instance.HasShadowId(alwaysCreate);
break;
case IInfrastructure<EntityTypeBuilder> nonGenericBuilder:
var names = propertyExpression.GetMemberAccessList().Select(e => e.GetSimpleMemberName()).ToList();
nonGenericBuilder.Instance.HasPartitionKey(names.FirstOrDefault(), names.Count > 1 ? names.Skip(1).ToArray() : []);
nonGenericBuilder.Instance.HasShadowId(alwaysCreate);
break;
}

return builder;
}

public static ModelBuilderTest.TestEntityTypeBuilder<TEntity> AlwaysHasShadowId<TEntity>(
public static ModelBuilderTest.TestEntityTypeBuilder<TEntity> HasPartitionKey<TEntity, TProperty>(
this ModelBuilderTest.TestEntityTypeBuilder<TEntity> builder,
bool? alwaysCreate = true)
Expression<Func<TEntity, TProperty>> propertyExpression)
where TEntity : class
{
switch (builder)
{
case IInfrastructure<EntityTypeBuilder<TEntity>> genericBuilder:
genericBuilder.Instance.HasShadowId(alwaysCreate);
genericBuilder.Instance.HasPartitionKey(propertyExpression);
break;
case IInfrastructure<EntityTypeBuilder> nonGenericBuilder:
nonGenericBuilder.Instance.HasShadowId(alwaysCreate);
var names = propertyExpression.GetMemberAccessList().Select(e => e.GetSimpleMemberName()).ToList();
nonGenericBuilder.Instance.HasPartitionKey(names.FirstOrDefault(), names.Count > 1 ? names.Skip(1).ToArray() : []);
break;
}

Expand All @@ -63,6 +75,40 @@ public static ModelBuilderTest.TestEntityTypeBuilder<TEntity> HasPartitionKey<TE
return builder;
}

public static ModelBuilderTest.TestEntityTypeBuilder<TEntity> ToContainer<TEntity>(
this ModelBuilderTest.TestEntityTypeBuilder<TEntity> builder,
string name)
where TEntity : class
{
switch (builder)
{
case IInfrastructure<EntityTypeBuilder<TEntity>> genericBuilder:
genericBuilder.Instance.ToContainer(name);
break;
case IInfrastructure<EntityTypeBuilder> nonGenericBuilder:
nonGenericBuilder.Instance.ToContainer(name);
break;
}

return builder;
}
public static ModelBuilderTest.TestEntityTypeBuilder<TEntity> UseETagConcurrency<TEntity>(
this ModelBuilderTest.TestEntityTypeBuilder<TEntity> builder)
where TEntity : class
{
switch (builder)
{
case IInfrastructure<EntityTypeBuilder<TEntity>> genericBuilder:
genericBuilder.Instance.UseETagConcurrency();
break;
case IInfrastructure<EntityTypeBuilder> nonGenericBuilder:
nonGenericBuilder.Instance.UseETagConcurrency();
break;
}

return builder;
}

public static ModelBuilderTest.TestPropertyBuilder<TProperty> ToJsonProperty<TProperty>(
this ModelBuilderTest.TestPropertyBuilder<TProperty> builder,
string name)
Expand Down

0 comments on commit 8b8892e

Please sign in to comment.