smg
smg

Reputation: 1216

How to use custom name convention with owned types?

public class ProcessInitialization
{
    public Guid CorrelationId { get; set; }
    public MyProcessContext ProcessContext { get; set; }
}

public class MyProcessContext
{
    public int? ProcessId { get; set; }
}

Without using my convention I got

SELECT `process`.`CorrelationId`
FROM `ProcessInitialization` AS `process`
WHERE `process`.`ProcessContext_ProcessId` = 8

My convention makes snake_case from PascalCase:

public static void SetSimpleUnderscoreTableNameConvention(this ModelBuilder modelBuilder,
    bool preserveAcronyms,
    IDictionary<string, string> propertyMap = null,
    IDictionary<string, string> entityMap = null
    )
{
    var propMap = propertyMap ?? new Dictionary<string, string>();
    var entMap = entityMap ?? new Dictionary<string, string>();

    foreach (var entity in modelBuilder.Model.GetEntityTypes())
    {
        foreach (var prop in entity.GetProperties())
        {
            if (propMap.ContainsKey(prop.Name))
            {
                prop.Relational().ColumnName = propMap[prop.Name];
            }
            else
            {
                var underscoredProp = AddUndercoresToSentence(prop.Name, preserveAcronyms);
                prop.Relational().ColumnName = underscoredProp.ToLowerInvariant();
            }
        }

        var entName = entity.DisplayName();

        if (entMap.ContainsKey(entName))
        {
            entity.Relational().TableName = entMap[entName];
        }
        else
        {
            var underscored = AddUndercoresToSentence(entity.DisplayName(), preserveAcronyms);
            entity.Relational().TableName = underscored.ToLowerInvariant();
        }
    }
}

With it query becomes invalid:

SELECT `process`.`correlation_id`
FROM `process`
LEFT JOIN `process_initialization._process_context#_my_process_context` AS `process.ProcessContext` ON `process`.`correlation_id` = `process.ProcessContext`.`process_initialization_correlation_id`
WHERE `process.ProcessContext`.`process_id` = 8

Looks like I need to not apply my transformation to some of entity:

var underscored = AddUndercoresToSentence(entity.DisplayName(), preserveAcronyms);
if (underscored.Contains("#")) // any other way to understand it is special?
    continue;
entity.Relational().TableName = underscored.ToLowerInvariant();

After that I got:

The keys {'ProcessInitializationCorrelationId'} on 'ProcessInitialization.ProcessContext#MyProcessContext' and {'CorrelationId'} on 'ProcessInitialization' are both mapped to 'process_initialization.PK_process_initialization' but with different columns ({'process_initialization_correlation_id'} and {'correlation_id'}).

Upvotes: 1

Views: 480

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205769

Owned types require special processing.

First, you recognize them by using IEntityType.IsOwned() method.

Then, when the entity type is owned, you should skip the table name mapping (because they share the same table as the root owner entity). Also owned types have shadow PK properties which should be skipped, and for other properties you should build column name from the path from root owner to the owned type. The owner information is accessible through DefiningEntityType and DefiningNavigationName properties of IEntityType.

Applying all that to your code:

foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
    foreach (var prop in entity.GetProperties())
    {
        if (entity.IsOwned() && prop.IsPrimaryKey()) continue;
        IEntityType propOwner = entity;
        string propName = prop.Name, columnName = null;
        do
        {
            if (!propMap.TryGetValue(propName, out var name))
                name = AddUndercoresToSentence(propName, preserveAcronyms).ToLowerInvariant();
            columnName = columnName == null ? name : name + "_" + columnName;
            propName = propOwner.DefiningNavigationName;
            propOwner = propOwner.DefiningEntityType;
        }
        while (propName != null);
        prop.Relational().ColumnName = columnName;
    }

    if (entity.IsOwned()) continue;
    var entName = entity.DisplayName();
    if (!entMap.TryGetValue(entName, out var tableName))
        tableName = AddUndercoresToSentence(entName, preserveAcronyms).ToLowerInvariant();
    entity.Relational().TableName = tableName;
}

Upvotes: 2

Related Questions