Skip to content

Commit

Permalink
Add a way to configure identity columns and triggers on mapping fragm…
Browse files Browse the repository at this point in the history
…ents

Add support for annotations to mapping fragments, property overrides and sequences

Fixes #28195
Fixes #28237
  • Loading branch information
AndriySvyryd committed Jun 29, 2022
1 parent da9fe63 commit 853e21f
Show file tree
Hide file tree
Showing 23 changed files with 1,153 additions and 168 deletions.
160 changes: 109 additions & 51 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 @@ -890,7 +913,7 @@ private void GenerateTableMapping(
if (hasTriggers)
{
stringBuilder.AppendLine();
GenerateTriggers("t", entityType, stringBuilder);
GenerateTriggers("t", entityType, tableName!, schema, stringBuilder);
}

if (hasOverrides)
Expand All @@ -914,13 +937,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 +953,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 +1051,7 @@ private void GenerateSplitViewMapping(
using (stringBuilder.Indent())
{
GenerateOverrides("v", entityType, fragment.StoreObject, stringBuilder);
GenerateEntityTypeMappingFragmentAnnotations("v", fragment, stringBuilder);
}

stringBuilder
Expand All @@ -1034,6 +1061,28 @@ 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)
{
stringBuilder.AppendLine();

GenerateAnnotations(tableBuilderName, fragment, stringBuilder, annotations, inChainedCall: false);
}
}

/// <summary>
/// Generates code for <see cref="ICheckConstraint" /> objects.
/// </summary>
Expand Down Expand Up @@ -1137,14 +1186,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 Down
57 changes: 32 additions & 25 deletions src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -435,55 +435,62 @@ private void GenerateEntityType(IEntityType entityType)

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

// Note: no trigger annotation support as of yet
_builder.AppendLine("{");

if (triggers.Length == 1)
using (_builder.Indent())
{
var trigger = triggers[0];
if (trigger.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);
}
}
else
{
_builder.AppendLine("{");

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

_builder.AppendLine("});");
}
_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

0 comments on commit 853e21f

Please sign in to comment.