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

Add a way to configure identity columns and triggers for split entities #28354

Merged
merged 1 commit into from
Jul 1, 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
166 changes: 111 additions & 55 deletions src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,80 +316,103 @@ protected virtual void GenerateSequence(
ISequence sequence,
IndentedStringBuilder stringBuilder)
{
stringBuilder
.AppendLine()
var sequenceBuilderNameBuilder = new StringBuilder();
sequenceBuilderNameBuilder
.Append(modelBuilderName)
.Append(".HasSequence");

if (sequence.Type != Sequence.DefaultClrType)
{
stringBuilder
sequenceBuilderNameBuilder
.Append("<")
.Append(Code.Reference(sequence.Type))
.Append(">");
}

stringBuilder
sequenceBuilderNameBuilder
.Append("(")
.Append(Code.Literal(sequence.Name));

if (!string.IsNullOrEmpty(sequence.Schema)
&& sequence.Model.GetDefaultSchema() != sequence.Schema)
{
stringBuilder
sequenceBuilderNameBuilder
.Append(", ")
.Append(Code.Literal(sequence.Schema));
}

stringBuilder.Append(")");
sequenceBuilderNameBuilder.Append(")");
var sequenceBuilderName = sequenceBuilderNameBuilder.ToString();

using (stringBuilder.Indent())
stringBuilder
.AppendLine()
.Append(sequenceBuilderName);

// Note that GenerateAnnotations below does the corresponding decrement
stringBuilder.IncrementIndent();

if (sequence.StartValue != Sequence.DefaultStartValue)
{
if (sequence.StartValue != Sequence.DefaultStartValue)
{
stringBuilder
.AppendLine()
.Append(".StartsAt(")
.Append(Code.Literal(sequence.StartValue))
.Append(")");
}
stringBuilder
.AppendLine()
.Append(".StartsAt(")
.Append(Code.Literal(sequence.StartValue))
.Append(")");
}

if (sequence.IncrementBy != Sequence.DefaultIncrementBy)
{
stringBuilder
.AppendLine()
.Append(".IncrementsBy(")
.Append(Code.Literal(sequence.IncrementBy))
.Append(")");
}
if (sequence.IncrementBy != Sequence.DefaultIncrementBy)
{
stringBuilder
.AppendLine()
.Append(".IncrementsBy(")
.Append(Code.Literal(sequence.IncrementBy))
.Append(")");
}

if (sequence.MinValue != Sequence.DefaultMinValue)
{
stringBuilder
.AppendLine()
.Append(".HasMin(")
.Append(Code.Literal(sequence.MinValue))
.Append(")");
}
if (sequence.MinValue != Sequence.DefaultMinValue)
{
stringBuilder
.AppendLine()
.Append(".HasMin(")
.Append(Code.Literal(sequence.MinValue))
.Append(")");
}

if (sequence.MaxValue != Sequence.DefaultMaxValue)
{
stringBuilder
.AppendLine()
.Append(".HasMax(")
.Append(Code.Literal(sequence.MaxValue))
.Append(")");
}
if (sequence.MaxValue != Sequence.DefaultMaxValue)
{
stringBuilder
.AppendLine()
.Append(".HasMax(")
.Append(Code.Literal(sequence.MaxValue))
.Append(")");
}

if (sequence.IsCyclic != Sequence.DefaultIsCyclic)
{
stringBuilder
.AppendLine()
.Append(".IsCyclic()");
}
if (sequence.IsCyclic != Sequence.DefaultIsCyclic)
{
stringBuilder
.AppendLine()
.Append(".IsCyclic()");
}

stringBuilder.AppendLine(";");
GenerateSequenceAnnotations(sequenceBuilderName, sequence, stringBuilder);
}

/// <summary>
/// Generates code for sequence annotations.
/// </summary>
/// <param name="sequenceBuilderName">The name of the sequence builder variable.</param>
/// <param name="sequence">The sequence.</param>
/// <param name="stringBuilder">The builder code is added to.</param>
protected virtual void GenerateSequenceAnnotations(
string sequenceBuilderName,
ISequence sequence,
IndentedStringBuilder stringBuilder)
{
var annotations = Dependencies.AnnotationCodeGenerator
.FilterIgnoredAnnotations(sequence.GetAnnotations())
.ToDictionary(a => a.Name, a => a);

GenerateAnnotations(sequenceBuilderName, sequence, stringBuilder, annotations, inChainedCall: true);
}

/// <summary>
Expand Down Expand Up @@ -849,7 +872,7 @@ private void GenerateTableMapping(
annotations.Remove(isExcludedAnnotation.Name);
}

var hasTriggers = entityType.GetTriggers().Any();
var hasTriggers = entityType.GetTriggers().Any(t => t.TableName == tableName! && t.TableSchema == schema);
var hasOverrides = table != null
&& entityType.GetProperties().Select(p => p.FindOverrides(table.Value)).Any(o => o != null);
var requiresTableBuilder = isExcludedFromMigrations
Expand Down Expand Up @@ -889,8 +912,7 @@ private void GenerateTableMapping(

if (hasTriggers)
{
stringBuilder.AppendLine();
GenerateTriggers("t", entityType, stringBuilder);
GenerateTriggers("t", entityType, tableName!, schema, stringBuilder);
}

if (hasOverrides)
Expand All @@ -914,13 +936,14 @@ private void GenerateSplitTableMapping(
{
foreach (var fragment in entityType.GetMappingFragments(StoreObjectType.Table))
{
var table = fragment.StoreObject;
stringBuilder
.AppendLine()
.Append(entityTypeBuilderName)
.Append(".SplitToTable(")
.Append(Code.UnknownLiteral(fragment.StoreObject.Name))
.Append(Code.UnknownLiteral(table.Name))
.Append(", ")
.Append(Code.UnknownLiteral(fragment.StoreObject.Schema))
.Append(Code.UnknownLiteral(table.Schema))
.AppendLine(", t =>");

using (stringBuilder.Indent())
Expand All @@ -929,7 +952,9 @@ private void GenerateSplitTableMapping(

using (stringBuilder.Indent())
{
GenerateOverrides("t", entityType, fragment.StoreObject, stringBuilder);
GenerateTriggers("t", entityType, table.Name, table.Schema, stringBuilder);
GenerateOverrides("t", entityType, table, stringBuilder);
GenerateEntityTypeMappingFragmentAnnotations("t", fragment, stringBuilder);
}

stringBuilder
Expand Down Expand Up @@ -1025,6 +1050,7 @@ private void GenerateSplitViewMapping(
using (stringBuilder.Indent())
{
GenerateOverrides("v", entityType, fragment.StoreObject, stringBuilder);
GenerateEntityTypeMappingFragmentAnnotations("v", fragment, stringBuilder);
}

stringBuilder
Expand All @@ -1034,6 +1060,26 @@ private void GenerateSplitViewMapping(
}
}

/// <summary>
/// Generates code for mapping fragment annotations.
/// </summary>
/// <param name="tableBuilderName">The name of the table builder variable.</param>
/// <param name="fragment">The mapping fragment.</param>
/// <param name="stringBuilder">The builder code is added to.</param>
protected virtual void GenerateEntityTypeMappingFragmentAnnotations(
string tableBuilderName,
IEntityTypeMappingFragment fragment,
IndentedStringBuilder stringBuilder)
{
var annotations = Dependencies.AnnotationCodeGenerator
.FilterIgnoredAnnotations(fragment.GetAnnotations())
.ToDictionary(a => a.Name, a => a);
if (annotations.Count > 0)
{
GenerateAnnotations(tableBuilderName, fragment, stringBuilder, annotations, inChainedCall: false);
}
}

/// <summary>
/// Generates code for <see cref="ICheckConstraint" /> objects.
/// </summary>
Expand Down Expand Up @@ -1137,14 +1183,23 @@ protected virtual void GenerateCheckConstraintAnnotations(
/// </summary>
/// <param name="tableBuilderName">The name of the table builder variable.</param>
/// <param name="entityType">The entity type.</param>
/// <param name="table">The table name.</param>
/// <param name="schema">The table schema.</param>
/// <param name="stringBuilder">The builder code is added to.</param>
protected virtual void GenerateTriggers(
string tableBuilderName,
IEntityType entityType,
string table,
string? schema,
IndentedStringBuilder stringBuilder)
{
foreach (var trigger in entityType.GetTriggers())
{
if (trigger.TableName != table || trigger.TableSchema != schema)
{
continue;
}

GenerateTrigger(tableBuilderName, trigger, stringBuilder);
}
}
Expand All @@ -1161,13 +1216,14 @@ protected virtual void GenerateTrigger(
IndentedStringBuilder stringBuilder)
{
var triggerBuilderName = $"{tableBuilderName}.HasTrigger({Code.Literal(trigger.ModelName)})";
stringBuilder.Append(triggerBuilderName);
stringBuilder
.AppendLine()
.Append(triggerBuilderName);

// Note that GenerateAnnotations below does the corresponding decrement
stringBuilder.IncrementIndent();

if (trigger.Name != null
&& trigger.Name != (trigger.GetDefaultName() ?? trigger.ModelName))
if (trigger.Name != trigger.GetDefaultName()!)
{
stringBuilder
.AppendLine()
Expand Down
60 changes: 33 additions & 27 deletions src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -433,57 +433,63 @@ private void GenerateEntityType(IEntityType entityType)
{
_builder.AppendLine();

_builder.Append($"{EntityLambdaIdentifier}.{nameof(RelationalEntityTypeBuilderExtensions.ToTable)}(tb => ");
_builder.AppendLine($"{EntityLambdaIdentifier}.{nameof(RelationalEntityTypeBuilderExtensions.ToTable)}(tb =>");

// Note: no trigger annotation support as of yet

if (triggers.Length == 1)
{
var trigger = triggers[0];
if (trigger.Name is not null)
{
_builder.AppendLine($"tb.HasTrigger({_code.Literal(trigger.Name)}));");
}
}
else
using (_builder.Indent())
{
_builder.AppendLine("{");

using (_builder.Indent())
_builder.Append("{");
foreach (var trigger in entityType.GetTriggers().Where(t => t.Name is not null))
{
foreach (var trigger in entityType.GetTriggers().Where(t => t.Name is not null))
{
_builder.AppendLine($"tb.HasTrigger({_code.Literal(trigger.Name!)});");
}
GenerateTrigger("tb", trigger);
}

_builder.AppendLine("});");
}

}
}
}

private void AppendMultiLineFluentApi(IEntityType entityType, IList<string> lines)
private void GenerateTrigger(string tableBuilderName, ITrigger trigger)
{
var lines = new List<string> { $".HasTrigger({_code.Literal(trigger.Name!)})" };

var annotations = _annotationCodeGenerator
.FilterIgnoredAnnotations(trigger.GetAnnotations())
.ToDictionary(a => a.Name, a => a);

_annotationCodeGenerator.RemoveAnnotationsHandledByConventions(trigger, annotations);

GenerateAnnotations(trigger, annotations, lines);

AppendMultiLineFluentApi(null, lines, tableBuilderName);
}

private void AppendMultiLineFluentApi(IEntityType? entityType, IList<string> lines, string? builderName = null)
{
if (lines.Count <= 0)
{
return;
}

InitializeEntityTypeBuilder(entityType);
if (entityType != null)
{
InitializeEntityTypeBuilder(entityType);
}

using (_builder.Indent())
{
_builder.AppendLine();

_builder.Append(EntityLambdaIdentifier + lines[0]);
_builder
.AppendLine()
.Append(builderName ?? EntityLambdaIdentifier)
.Append(lines[0]);

using (_builder.Indent())
{
foreach (var line in lines.Skip(1))
{
_builder.AppendLine();
_builder.Append(line);
_builder
.AppendLine()
.Append(line);
}
}

Expand Down
Loading