diff --git a/src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.cs b/src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.cs
index 9b258e3fc4c..68c9ed47297 100644
--- a/src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.cs
+++ b/src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.cs
@@ -26,6 +26,12 @@ public static class RelationalForeignKeyExtensions
/// The foreign key constraint name.
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
@@ -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
@@ -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
diff --git a/src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs b/src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs
index bddee9d0b1a..5eab8584ec3 100644
--- a/src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs
+++ b/src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs
@@ -25,7 +25,10 @@ public static class RelationalKeyExtensions
/// The key.
/// The key constraint name for this key.
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);
+ }
///
/// Returns the key constraint name for this key for a particular table.
@@ -34,8 +37,15 @@ public static class RelationalKeyExtensions
/// The identifier of the containing store object.
/// The key constraint name for this key.
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);
+ }
///
/// Returns the default key constraint name that would be used for this key.
@@ -65,6 +75,11 @@ public static string GetDefaultName(this IReadOnlyKey key)
/// The default key constraint name that would be used for this key.
public static string? GetDefaultName(this IReadOnlyKey key, in StoreObjectIdentifier storeObject)
{
+ if (storeObject.StoreObjectType != StoreObjectType.Table)
+ {
+ return null;
+ }
+
string? name;
if (key.IsPrimaryKey())
{
diff --git a/test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs b/test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs
index e5550344414..8d8580503b6 100644
--- a/test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs
+++ b/test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs
@@ -277,6 +277,82 @@ public static ModelBuilderTest.TestOwnedNavigationBuilder ToView(
+ this ModelBuilderTest.TestEntityTypeBuilder builder,
+ string? schema)
+ where TEntity : class
+ {
+ switch (builder)
+ {
+ case IInfrastructure> genericBuilder:
+ genericBuilder.Instance.ToView(schema);
+ break;
+ case IInfrastructure nongenericBuilder:
+ nongenericBuilder.Instance.ToView(schema);
+ break;
+ }
+
+ return builder;
+ }
+
+ public static ModelBuilderTest.TestEntityTypeBuilder ToView(
+ this ModelBuilderTest.TestEntityTypeBuilder builder,
+ string? name,
+ string? schema)
+ where TEntity : class
+ {
+ switch (builder)
+ {
+ case IInfrastructure> genericBuilder:
+ genericBuilder.Instance.ToView(name, schema);
+ break;
+ case IInfrastructure nongenericBuilder:
+ nongenericBuilder.Instance.ToView(name, schema);
+ break;
+ }
+
+ return builder;
+ }
+
+ public static ModelBuilderTest.TestOwnedNavigationBuilder ToView(
+ this ModelBuilderTest.TestOwnedNavigationBuilder builder,
+ string? schema)
+ where TOwnerEntity : class
+ where TRelatedEntity : class
+ {
+ switch (builder)
+ {
+ case IInfrastructure> genericBuilder:
+ genericBuilder.Instance.ToView(schema);
+ break;
+ case IInfrastructure nongenericBuilder:
+ nongenericBuilder.Instance.ToView(schema);
+ break;
+ }
+
+ return builder;
+ }
+
+ public static ModelBuilderTest.TestOwnedNavigationBuilder ToView(
+ this ModelBuilderTest.TestOwnedNavigationBuilder builder,
+ string? name,
+ string? schema)
+ where TOwnerEntity : class
+ where TRelatedEntity : class
+ {
+ switch (builder)
+ {
+ case IInfrastructure> genericBuilder:
+ genericBuilder.Instance.ToView(name, schema);
+ break;
+ case IInfrastructure nongenericBuilder:
+ nongenericBuilder.Instance.ToView(name, schema);
+ break;
+ }
+
+ return builder;
+ }
+
public static ModelBuilderTest.TestEntityTypeBuilder HasCheckConstraint(
this ModelBuilderTest.TestEntityTypeBuilder builder,
string name,
diff --git a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs
index 633c22fa350..ce901bbb878 100644
--- a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs
+++ b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs
@@ -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().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().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()