Skip to content

Commit

Permalink
Return null constraint names for keys and FKs on entity types not map…
Browse files Browse the repository at this point in the history
…ped to a table. (#27857)

Fixes #27854
  • Loading branch information
AndriySvyryd authored May 6, 2022
1 parent 06a0f01 commit ee7aa35
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 2 deletions.
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

0 comments on commit ee7aa35

Please sign in to comment.