Skip to content

Commit

Permalink
SqlServer Migrations: Persist ValueGenerationStrategy.None in snapshot
Browse files Browse the repository at this point in the history
Part of #20971
  • Loading branch information
bricelam committed Aug 27, 2020
1 parent a57d2e5 commit a8ef717
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,17 @@ private IReadOnlyList<MethodCallCodeFragment> GenerateValueGenerationStrategy(
IDictionary<string, IAnnotation> annotations,
bool onModel)
{
var strategy = GetAndRemove<SqlServerValueGenerationStrategy>(SqlServerAnnotationNames.ValueGenerationStrategy);
SqlServerValueGenerationStrategy strategy;
if (annotations.TryGetValue(SqlServerAnnotationNames.ValueGenerationStrategy, out var strategyAnnotation)
&& strategyAnnotation.Value != null)
{
annotations.Remove(SqlServerAnnotationNames.ValueGenerationStrategy);
strategy = (SqlServerValueGenerationStrategy)strategyAnnotation.Value;
}
else
{
return Array.Empty<MethodCallCodeFragment>();
}

switch (strategy)
{
Expand Down Expand Up @@ -154,7 +164,13 @@ private IReadOnlyList<MethodCallCodeFragment> GenerateValueGenerationStrategy(
};

case SqlServerValueGenerationStrategy.None:
return Array.Empty<MethodCallCodeFragment>();
return new List<MethodCallCodeFragment>
{
new MethodCallCodeFragment(
nameof(ModelBuilder.HasAnnotation),
SqlServerAnnotationNames.ValueGenerationStrategy,
SqlServerValueGenerationStrategy.None)
};

default:
throw new ArgumentOutOfRangeException();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
Expand Down Expand Up @@ -46,28 +47,58 @@ public virtual void ProcessModelFinalizing(
{
foreach (var property in entityType.GetDeclaredProperties())
{
var strategy = SqlServerValueGenerationStrategy.None;
// Needed for the annotation to show up in the model snapshot
SqlServerValueGenerationStrategy? strategy = null;
var copyStrategyNone = false;
var table = entityType.GetTableName();
if (table != null)
{
strategy = property.GetValueGenerationStrategy(StoreObjectIdentifier.Table(table, entityType.GetSchema()));
var storeObject = StoreObjectIdentifier.Table(table, entityType.GetSchema());
strategy = property.GetValueGenerationStrategy(storeObject);
if (strategy == SqlServerValueGenerationStrategy.None)
{
copyStrategyNone = ShouldCopyStrategyNone(property, storeObject);
}
}
else
{
var view = entityType.GetViewName();
if (view != null)
{
strategy = property.GetValueGenerationStrategy(StoreObjectIdentifier.View(view, entityType.GetViewSchema()));
var storeObject = StoreObjectIdentifier.View(view, entityType.GetViewSchema());
strategy = property.GetValueGenerationStrategy(storeObject);
if (strategy == SqlServerValueGenerationStrategy.None)
{
copyStrategyNone = ShouldCopyStrategyNone(property, storeObject);
}
}
}

if (strategy != SqlServerValueGenerationStrategy.None)
// Needed for the annotation to show up in the model snapshot
if (strategy.HasValue
&& (strategy.Value != SqlServerValueGenerationStrategy.None || copyStrategyNone))
{
property.Builder.HasValueGenerationStrategy(strategy);
}
}
}

static bool ShouldCopyStrategyNone(IProperty property, StoreObjectIdentifier storeObject)
{
if (property.ValueGenerated == ValueGenerated.OnAdd
&& property.GetDefaultValue(storeObject) == null
&& property.GetDefaultValueSql(storeObject) == null
&& property.GetComputedColumnSql(storeObject) == null
&& property.DeclaringEntityType.Model.GetValueGenerationStrategy() == SqlServerValueGenerationStrategy.IdentityColumn)
{
var providerClrType = (property.GetValueConverter() ?? property.FindRelationalTypeMapping(storeObject)?.Converter)
?.ProviderClrType.UnwrapNullableType();

return providerClrType != null
&& (providerClrType.IsInteger() || providerClrType == typeof(decimal));
}

return false;
}
}
}
}
40 changes: 40 additions & 0 deletions test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2293,6 +2293,46 @@ public virtual void Property_ValueGenerated_value_is_stored_in_snapshot()
o => Assert.Equal(ValueGenerated.OnAdd, o.GetEntityTypes().First().FindProperty("AlternateId").ValueGenerated));
}