Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[6.0.x] Return null constraint names for keys and FKs on entity types not mapped to a table. #27857

Merged
merged 1 commit into from
May 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ public static class RelationalForeignKeyExtensions
/// <returns>The foreign key constraint name.</returns>
public static string? GetConstraintName(this IReadOnlyForeignKey foreignKey)
{
var tableName = foreignKey.DeclaringEntityType.GetTableName();
if (tableName == null)
{
return null;
}

var annotation = foreignKey.FindAnnotation(RelationalAnnotationNames.Name);
return annotation != null
? (string?)annotation.Value
Expand All @@ -44,6 +50,12 @@ public static class RelationalForeignKeyExtensions
in StoreObjectIdentifier storeObject,
in StoreObjectIdentifier principalStoreObject)
{
if (storeObject.StoreObjectType != StoreObjectType.Table
|| principalStoreObject.StoreObjectType != StoreObjectType.Table)
{
return null;
}

var annotation = foreignKey.FindAnnotation(RelationalAnnotationNames.Name);
return annotation != null
? (string?)annotation.Value
Expand Down Expand Up @@ -85,6 +97,12 @@ public static string GetDefaultName(this IReadOnlyForeignKey foreignKey)
in StoreObjectIdentifier storeObject,
in StoreObjectIdentifier principalStoreObject)
{
if (storeObject.StoreObjectType != StoreObjectType.Table
|| principalStoreObject.StoreObjectType != StoreObjectType.Table)
{
return null;
}

var propertyNames = foreignKey.Properties.GetColumnNames(storeObject);
var principalPropertyNames = foreignKey.PrincipalKey.Properties.GetColumnNames(principalStoreObject);
if (propertyNames == null
Expand Down
19 changes: 17 additions & 2 deletions src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ public static class RelationalKeyExtensions
/// <param name="key">The key.</param>
/// <returns>The key constraint name for this key.</returns>
public static string? GetName(this IReadOnlyKey key)
=> key.GetName(StoreObjectIdentifier.Table(key.DeclaringEntityType.GetTableName()!, key.DeclaringEntityType.GetSchema()));
{
var table = StoreObjectIdentifier.Create(key.DeclaringEntityType, StoreObjectType.Table);
return !table.HasValue ? null : key.GetName(table.Value);
}

/// <summary>
/// Returns the key constraint name for this key for a particular table.
Expand All @@ -34,8 +37,15 @@ public static class RelationalKeyExtensions
/// <param name="storeObject">The identifier of the containing store object.</param>
/// <returns>The key constraint name for this key.</returns>
public static string? GetName(this IReadOnlyKey key, in StoreObjectIdentifier storeObject)
=> (string?)key[RelationalAnnotationNames.Name]
{
if (storeObject.StoreObjectType != StoreObjectType.Table)
{
return null;
}

return (string?)key[RelationalAnnotationNames.Name]
?? key.GetDefaultName(storeObject);
}

/// <summary>
/// Returns the default key constraint name that would be used for this key.
Expand Down Expand Up @@ -65,6 +75,11 @@ public static string GetDefaultName(this IReadOnlyKey key)
/// <returns>The default key constraint name that would be used for this key.</returns>
public static string? GetDefaultName(this IReadOnlyKey key, in StoreObjectIdentifier storeObject)
{
if (storeObject.StoreObjectType != StoreObjectType.Table)
{
return null;
}

string? name;
if (key.IsPrimaryKey())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,82 @@ public static ModelBuilderTest.TestOwnedNavigationBuilder<TOwnerEntity, TRelated
return builder;
}

public static ModelBuilderTest.TestEntityTypeBuilder<TEntity> ToView<TEntity>(
this ModelBuilderTest.TestEntityTypeBuilder<TEntity> builder,
string? schema)
where TEntity : class
{
switch (builder)
{
case IInfrastructure<EntityTypeBuilder<TEntity>> genericBuilder:
genericBuilder.Instance.ToView(schema);
break;
case IInfrastructure<EntityTypeBuilder> nongenericBuilder:
nongenericBuilder.Instance.ToView(schema);
break;
}

return builder;
}

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

return builder;
}

public static ModelBuilderTest.TestOwnedNavigationBuilder<TOwnerEntity, TRelatedEntity> ToView<TOwnerEntity, TRelatedEntity>(
this ModelBuilderTest.TestOwnedNavigationBuilder<TOwnerEntity, TRelatedEntity> builder,
string? schema)
where TOwnerEntity : class
where TRelatedEntity : class
{
switch (builder)
{
case IInfrastructure<OwnedNavigationBuilder<TOwnerEntity, TRelatedEntity>> genericBuilder:
genericBuilder.Instance.ToView(schema);
break;
case IInfrastructure<OwnedNavigationBuilder> nongenericBuilder:
nongenericBuilder.Instance.ToView(schema);
break;
}

return builder;
}

public static ModelBuilderTest.TestOwnedNavigationBuilder<TOwnerEntity, TRelatedEntity> ToView<TOwnerEntity, TRelatedEntity>(
this ModelBuilderTest.TestOwnedNavigationBuilder<TOwnerEntity, TRelatedEntity> builder,
string? name,
string? schema)
where TOwnerEntity : class
where TRelatedEntity : class
{
switch (builder)
{
case IInfrastructure<OwnedNavigationBuilder<TOwnerEntity, TRelatedEntity>> genericBuilder:
genericBuilder.Instance.ToView(name, schema);
break;
case IInfrastructure<OwnedNavigationBuilder> nongenericBuilder:
nongenericBuilder.Instance.ToView(name, schema);
break;
}

return builder;
}

public static ModelBuilderTest.TestEntityTypeBuilder<TEntity> HasCheckConstraint<TEntity>(
this ModelBuilderTest.TestEntityTypeBuilder<TEntity> builder,
string name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,84 @@ public virtual void Owned_type_collections_can_be_mapped_to_different_tables()
Assert.Equal("blah", owned.GetTableName());
Assert.Null(owned.GetSchema());
}

[ConditionalFact]
public virtual void Owned_type_collections_can_be_mapped_to_a_view()
{
var modelBuilder = CreateModelBuilder();

modelBuilder.Entity<Customer>().OwnsMany(
c => c.Orders,
r =>
{
r.HasKey(o => o.OrderId);
r.Ignore(o => o.OrderCombination);
r.Ignore(o => o.Details);
r.ToView("bar", "foo");
});

var model = modelBuilder.FinalizeModel();

var owner = model.FindEntityType(typeof(Customer));
var ownership = owner.FindNavigation(nameof(Customer.Orders)).ForeignKey;
var owned = ownership.DeclaringEntityType;
Assert.True(ownership.IsOwnership);
Assert.Equal(nameof(Order.Customer), ownership.DependentToPrincipal.Name);
Assert.Empty(ownership.GetMappedConstraints());

Assert.Equal(nameof(Customer), owner.GetTableName());
Assert.Null(owner.GetSchema());

Assert.Null(owned.GetForeignKeys().Single().GetConstraintName());
Assert.Single(owned.GetIndexes());
Assert.Null(owned.FindPrimaryKey().GetName());
Assert.Equal(
new[] { nameof(Order.OrderId), nameof(Order.AnotherCustomerId), nameof(Order.CustomerId) },
owned.GetProperties().Select(p => p.GetColumnBaseName()));
Assert.Null(owned.GetTableName());
Assert.Null(owned.GetSchema());
Assert.Equal("bar", owned.GetViewName());
Assert.Equal("foo", owned.GetViewSchema());
}

[ConditionalFact]
public virtual void Owner_can_be_mapped_to_a_view()
{
var modelBuilder = CreateModelBuilder();

modelBuilder.Entity<Customer>().OwnsMany(
c => c.Orders,
r =>
{
r.HasKey(o => o.OrderId);
r.Ignore(o => o.OrderCombination);
r.Ignore(o => o.Details);
})
.ToView("bar", "foo");

var model = modelBuilder.FinalizeModel();

var owner = model.FindEntityType(typeof(Customer));
var ownership = owner.FindNavigation(nameof(Customer.Orders)).ForeignKey;
var owned = ownership.DeclaringEntityType;
Assert.True(ownership.IsOwnership);
Assert.Equal(nameof(Order.Customer), ownership.DependentToPrincipal.Name);
Assert.Empty(ownership.GetMappedConstraints());

Assert.Null(owner.GetTableName());
Assert.Null(owner.GetSchema());
Assert.Equal("bar", owner.GetViewName());
Assert.Equal("foo", owner.GetViewSchema());

Assert.Equal("FK_Order__CustomerId", owned.GetForeignKeys().Single().GetConstraintName());
Assert.Equal("IX_Order_CustomerId", owned.GetIndexes().Single().GetDatabaseName());
Assert.Equal("PK_Order", owned.FindPrimaryKey().GetName());
Assert.Equal(
new[] { nameof(Order.OrderId), nameof(Order.AnotherCustomerId), nameof(Order.CustomerId) },
owned.GetProperties().Select(p => p.GetColumnBaseName()));
Assert.Equal(nameof(Order), owned.GetTableName());
Assert.Null(owned.GetSchema());
}

[ConditionalFact]
public override void Can_configure_owned_type()
Expand Down