Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -53,50 +53,58 @@ public virtual void ProcessModelFinalizing(
var checkConstraints = new Dictionary<(string, string?), (IConventionCheckConstraint, StoreObjectIdentifier)>();
var defaultConstraints = new Dictionary<(string, string?), (IConventionProperty, StoreObjectIdentifier)>();
var triggers = new Dictionary<string, (IConventionTrigger, StoreObjectIdentifier)>();
foreach (var ((tableName, schema), conventionEntityTypes) in tables)
foreach (var schemaGroup in tables.GroupBy(t => t.Key.Schema).OrderBy(g => g.Key))
{
columns.Clear();

if (!KeysUniqueAcrossTables)
if (!KeysUniqueAcrossSchemas)
{
keys.Clear();
}

if (!ForeignKeysUniqueAcrossTables)
foreach (var ((tableName, schema), conventionEntityTypes) in schemaGroup.OrderBy(t => t.Key.TableName))
{
foreignKeys.Clear();
}
columns.Clear();

if (!IndexesUniqueAcrossTables)
{
indexes.Clear();
}
if (!KeysUniqueAcrossTables)
{
keys.Clear();
}

if (!CheckConstraintsUniqueAcrossTables)
{
checkConstraints.Clear();
}
if (!ForeignKeysUniqueAcrossTables)
{
foreignKeys.Clear();
}

if (!DefaultConstraintsUniqueAcrossTables)
{
defaultConstraints.Clear();
}
if (!IndexesUniqueAcrossTables)
{
indexes.Clear();
}

if (!TriggersUniqueAcrossTables)
{
triggers.Clear();
}
if (!CheckConstraintsUniqueAcrossTables)
{
checkConstraints.Clear();
}

var storeObject = StoreObjectIdentifier.Table(tableName, schema);
foreach (var entityType in conventionEntityTypes)
{
UniquifyColumnNames(entityType, columns, storeObject, maxLength);
UniquifyKeyNames(entityType, keys, storeObject, maxLength);
UniquifyForeignKeyNames(entityType, foreignKeys, storeObject, maxLength);
UniquifyIndexNames(entityType, indexes, storeObject, maxLength);
UniquifyCheckConstraintNames(entityType, checkConstraints, storeObject, maxLength);
UniquifyDefaultConstraintNames(entityType, defaultConstraints, storeObject, maxLength);
UniquifyTriggerNames(entityType, triggers, storeObject, maxLength);
if (!DefaultConstraintsUniqueAcrossTables)
{
defaultConstraints.Clear();
}

if (!TriggersUniqueAcrossTables)
{
triggers.Clear();
}

var storeObject = StoreObjectIdentifier.Table(tableName, schema);
foreach (var entityType in conventionEntityTypes)
{
UniquifyColumnNames(entityType, columns, storeObject, maxLength);
UniquifyKeyNames(entityType, keys, storeObject, maxLength);
UniquifyForeignKeyNames(entityType, foreignKeys, storeObject, maxLength);
UniquifyIndexNames(entityType, indexes, storeObject, maxLength);
UniquifyCheckConstraintNames(entityType, checkConstraints, storeObject, maxLength);
UniquifyDefaultConstraintNames(entityType, defaultConstraints, storeObject, maxLength);
UniquifyTriggerNames(entityType, triggers, storeObject, maxLength);
}
}
}
}
Expand All @@ -107,6 +115,12 @@ public virtual void ProcessModelFinalizing(
protected virtual bool KeysUniqueAcrossTables
=> false;

/// <summary>
/// Gets a value indicating whether key names should be unique across schemas.
/// </summary>
protected virtual bool KeysUniqueAcrossSchemas
=> true;
Comment thread
AndriySvyryd marked this conversation as resolved.

/// <summary>
/// Gets a value indicating whether foreign key names should be unique across tables.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Infrastructure.Internal;

// ReSharper disable InconsistentNaming
namespace Microsoft.EntityFrameworkCore.Metadata.Conventions;

public class SharedTableConventionTest
{
[ConditionalFact]
public virtual void Keys_are_not_uniquified_across_schemas_when_KeysUniqueAcrossSchemas_is_false()
{
var (modelBuilder, context) = GetModelBuilder(keysUniqueAcrossSchemas: false);
using (context)
{
modelBuilder.Entity<Order>().ToTable("MyTable", "Schema1").HasKey(e => e.Id);
modelBuilder.Entity<Customer>().ToTable("MyTable", "Schema2").HasKey(e => e.Id);

var finalizedModel = modelBuilder.Model.FinalizeModel();

var orderEntityType = finalizedModel.FindEntityType(typeof(Order))!;
var customerEntityType = finalizedModel.FindEntityType(typeof(Customer))!;

var orderPkName = orderEntityType.FindPrimaryKey()!.GetName(
StoreObjectIdentifier.Table("MyTable", "Schema1"));
var customerPkName = customerEntityType.FindPrimaryKey()!.GetName(
StoreObjectIdentifier.Table("MyTable", "Schema2"));

Assert.Equal("PK_MyTable", orderPkName);
Assert.Equal("PK_MyTable", customerPkName);
}
}

[ConditionalFact]
public virtual void Keys_are_uniquified_across_schemas_when_KeysUniqueAcrossSchemas_is_true()
{
var (modelBuilder, context) = GetModelBuilder(keysUniqueAcrossSchemas: true);
using (context)
{
modelBuilder.Entity<Order>().ToTable("MyTable", "Schema1").HasKey(e => e.Id);
modelBuilder.Entity<Customer>().ToTable("MyTable", "Schema2").HasKey(e => e.Id);

var finalizedModel = modelBuilder.Model.FinalizeModel();

var orderEntityType = finalizedModel.FindEntityType(typeof(Order))!;
var customerEntityType = finalizedModel.FindEntityType(typeof(Customer))!;

var orderPkName = orderEntityType.FindPrimaryKey()!.GetName(
StoreObjectIdentifier.Table("MyTable", "Schema1"));
var customerPkName = customerEntityType.FindPrimaryKey()!.GetName(
StoreObjectIdentifier.Table("MyTable", "Schema2"));

Assert.Equal("PK_MyTable", orderPkName);
Assert.Equal("PK_MyTable1", customerPkName);
}
}

private class Order
{
public int Id { get; set; }
}

private class Customer
{
public int Id { get; set; }
}

private class TestSharedTableConvention(
ProviderConventionSetBuilderDependencies dependencies,
RelationalConventionSetBuilderDependencies relationalDependencies)
: SharedTableConvention(dependencies, relationalDependencies)
{
protected override bool KeysUniqueAcrossTables
=> true;

protected override bool KeysUniqueAcrossSchemas
=> false;
}

private (ModelBuilder, DbContext) GetModelBuilder(bool keysUniqueAcrossSchemas)
{
var conventionSet = new ConventionSet();

var context = new DbContext(new DbContextOptions<DbContext>());
var dependencies = CreateDependencies()
.With(new CurrentDbContext(context));
var relationalDependencies = CreateRelationalDependencies();

if (keysUniqueAcrossSchemas)
{
conventionSet.ModelFinalizingConventions.Add(
new KeysUniqueAcrossTablesSharedTableConvention(dependencies, relationalDependencies));
}
else
{
conventionSet.ModelFinalizingConventions.Add(
new TestSharedTableConvention(dependencies, relationalDependencies));
}

return (new ModelBuilder(conventionSet), context);
}

private class KeysUniqueAcrossTablesSharedTableConvention(
ProviderConventionSetBuilderDependencies dependencies,
RelationalConventionSetBuilderDependencies relationalDependencies)
: SharedTableConvention(dependencies, relationalDependencies)
{
protected override bool KeysUniqueAcrossTables
=> true;
}

private ProviderConventionSetBuilderDependencies CreateDependencies()
=> FakeRelationalTestHelpers.Instance.CreateContextServices().GetRequiredService<ProviderConventionSetBuilderDependencies>();

private RelationalConventionSetBuilderDependencies CreateRelationalDependencies()
=> FakeRelationalTestHelpers.Instance.CreateContextServices().GetRequiredService<RelationalConventionSetBuilderDependencies>();
Comment thread
AndriySvyryd marked this conversation as resolved.
}
Loading