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

Make the DatabaseGeneratedOption annotation configure ValueGenerationStrategy for SqlServer #6761

Merged
merged 1 commit into from
Oct 13, 2016
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
@@ -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 System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
Expand Down Expand Up @@ -90,7 +91,7 @@ protected virtual void ReplaceConvention<T1, T2>([NotNull] IList<T1> conventions
var oldConvention = conventionsList.OfType<T2>().FirstOrDefault();
if (oldConvention == null)
{
return;
throw new InvalidOperationException();
}
var index = conventionsList.IndexOf(oldConvention);
conventionsList.RemoveAt(index);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,7 @@ protected class KeyOnNavProp
}

[Fact]
public virtual void Key_property_is_not_used_for_FK_when_set_by_annotation()
public virtual ModelBuilder Key_property_is_not_used_for_FK_when_set_by_annotation()
{
var modelBuilder = CreateModelBuilder();

Expand All @@ -718,6 +718,8 @@ public virtual void Key_property_is_not_used_for_FK_when_set_by_annotation()
Assert.False(toy.Metadata.GetForeignKeys().Any(fk => fk.IsUnique == false && fk.Properties.Any(p => p.Name == nameof(Toy.IdRow))));

Validate(modelBuilder);

return modelBuilder;
}

public class Parent
Expand Down Expand Up @@ -750,6 +752,43 @@ public class Toy
public string Name { get; set; }
}

[Fact]
public virtual ModelBuilder DatabaseGeneratedOption_configures_the_property_correctly()
{
var modelBuilder = CreateModelBuilder();

modelBuilder.Entity<GeneratedEntity>();

var entity = modelBuilder.Model.FindEntityType(typeof(GeneratedEntity));

var id = entity.FindProperty(nameof(GeneratedEntity.Id));
Assert.Equal(ValueGenerated.Never, id.ValueGenerated);
Assert.False(id.RequiresValueGenerator);

var identity = entity.FindProperty(nameof(GeneratedEntity.Identity));
Assert.Equal(ValueGenerated.OnAdd, identity.ValueGenerated);

var version = entity.FindProperty(nameof(GeneratedEntity.Version));
Assert.Equal(ValueGenerated.OnAddOrUpdate, version.ValueGenerated);
Assert.False(version.RequiresValueGenerator);

Validate(modelBuilder);

return modelBuilder;
}

public class GeneratedEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Identity { get; set; }

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public Guid Version { get; set; }
}

[Fact]
public virtual ModelBuilder Timestamp_takes_precedence_over_MaxLength()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public static PropertyBuilder ForSqlServerHasColumnName(
Check.NotNull(propertyBuilder, nameof(propertyBuilder));
Check.NullButNotEmpty(name, nameof(name));

propertyBuilder.Metadata.SqlServer().ColumnName = name;
GetSqlServerInternalBuilder(propertyBuilder).ColumnName(name);

return propertyBuilder;
}
Expand Down Expand Up @@ -60,7 +60,7 @@ public static PropertyBuilder ForSqlServerHasColumnType(
Check.NotNull(propertyBuilder, nameof(propertyBuilder));
Check.NullButNotEmpty(typeName, nameof(typeName));

propertyBuilder.Metadata.SqlServer().ColumnType = typeName;
GetSqlServerInternalBuilder(propertyBuilder).ColumnType(typeName);

return propertyBuilder;
}
Expand Down Expand Up @@ -91,8 +91,7 @@ public static PropertyBuilder ForSqlServerHasDefaultValueSql(
Check.NotNull(propertyBuilder, nameof(propertyBuilder));
Check.NullButNotEmpty(sql, nameof(sql));

var internalPropertyBuilder = propertyBuilder.GetInfrastructure<InternalPropertyBuilder>();
internalPropertyBuilder.SqlServer(ConfigurationSource.Explicit).DefaultValueSql(sql);
GetSqlServerInternalBuilder(propertyBuilder).DefaultValueSql(sql);

return propertyBuilder;
}
Expand Down Expand Up @@ -121,8 +120,7 @@ public static PropertyBuilder ForSqlServerHasDefaultValue(
{
Check.NotNull(propertyBuilder, nameof(propertyBuilder));

var internalPropertyBuilder = propertyBuilder.GetInfrastructure<InternalPropertyBuilder>();
internalPropertyBuilder.SqlServer(ConfigurationSource.Explicit).DefaultValue(value);
GetSqlServerInternalBuilder(propertyBuilder).DefaultValue(value);

return propertyBuilder;
}
Expand Down Expand Up @@ -152,8 +150,7 @@ public static PropertyBuilder ForSqlServerHasComputedColumnSql(
Check.NotNull(propertyBuilder, nameof(propertyBuilder));
Check.NullButNotEmpty(sql, nameof(sql));

var internalPropertyBuilder = propertyBuilder.GetInfrastructure<InternalPropertyBuilder>();
internalPropertyBuilder.SqlServer(ConfigurationSource.Explicit).ComputedColumnSql(sql);
GetSqlServerInternalBuilder(propertyBuilder).ComputedColumnSql(sql);

return propertyBuilder;
}
Expand Down Expand Up @@ -198,9 +195,8 @@ public static PropertyBuilder ForSqlServerUseSequenceHiLo(
model.SqlServer().GetOrAddSequence(name, schema).IncrementBy = 10;
}

property.SqlServer().ValueGenerationStrategy = SqlServerValueGenerationStrategy.SequenceHiLo;
property.ValueGenerated = ValueGenerated.OnAdd;
property.RequiresValueGenerator = true;
GetSqlServerInternalBuilder(propertyBuilder).ValueGenerationStrategy(SqlServerValueGenerationStrategy.SequenceHiLo);

property.SqlServer().HiLoSequenceName = name;
property.SqlServer().HiLoSequenceSchema = schema;

Expand Down Expand Up @@ -233,13 +229,7 @@ public static PropertyBuilder UseSqlServerIdentityColumn(
{
Check.NotNull(propertyBuilder, nameof(propertyBuilder));

var property = propertyBuilder.Metadata;

property.SqlServer().ValueGenerationStrategy = SqlServerValueGenerationStrategy.IdentityColumn;
property.ValueGenerated = ValueGenerated.OnAdd;
property.RequiresValueGenerator = true;
property.SqlServer().HiLoSequenceName = null;
property.SqlServer().HiLoSequenceSchema = null;
GetSqlServerInternalBuilder(propertyBuilder).ValueGenerationStrategy(SqlServerValueGenerationStrategy.IdentityColumn);

return propertyBuilder;
}
Expand All @@ -254,5 +244,8 @@ public static PropertyBuilder UseSqlServerIdentityColumn(
public static PropertyBuilder<TProperty> UseSqlServerIdentityColumn<TProperty>(
[NotNull] this PropertyBuilder<TProperty> propertyBuilder)
=> (PropertyBuilder<TProperty>)UseSqlServerIdentityColumn((PropertyBuilder)propertyBuilder);

private static SqlServerPropertyBuilderAnnotations GetSqlServerInternalBuilder(PropertyBuilder propertyBuilder)
=> propertyBuilder.GetInfrastructure<InternalPropertyBuilder>().SqlServer(ConfigurationSource.Explicit);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
// 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.Reflection;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System.ComponentModel.DataAnnotations.Schema;

namespace Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal
{
/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public class SqlServerValueGenerationStrategyConvention : IModelConvention
public class SqlServerValueGenerationStrategyConvention : DatabaseGeneratedAttributeConvention, IModelConvention
{
public override InternalPropertyBuilder Apply(
InternalPropertyBuilder propertyBuilder, DatabaseGeneratedAttribute attribute, MemberInfo clrMember)
{
propertyBuilder.SqlServer(ConfigurationSource.DataAnnotation).ValueGenerationStrategy(
attribute.DatabaseGeneratedOption == DatabaseGeneratedOption.Identity
? SqlServerValueGenerationStrategy.IdentityColumn
: (SqlServerValueGenerationStrategy?)null);

return base.Apply(propertyBuilder, attribute, clrMember);
}

/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ public override ConventionSet AddConventions(ConventionSet conventionSet)

base.AddConventions(conventionSet);

conventionSet.ModelInitializedConventions.Add(new SqlServerValueGenerationStrategyConvention());
var valueGenerationStrategyConvention = new SqlServerValueGenerationStrategyConvention();
conventionSet.ModelInitializedConventions.Add(valueGenerationStrategyConvention);

ReplaceConvention(conventionSet.PropertyAddedConventions, (DatabaseGeneratedAttributeConvention)valueGenerationStrategyConvention);

var sqlServerInMemoryTablesConvention = new SqlServerInMemoryTablesConvention();
conventionSet.EntityTypeAnnotationSetConventions.Add(sqlServerInMemoryTablesConvention);
Expand All @@ -35,6 +38,8 @@ public override ConventionSet AddConventions(ConventionSet conventionSet)

conventionSet.IndexAddedConventions.Add(sqlServerInMemoryTablesConvention);

ReplaceConvention(conventionSet.PropertyFieldChangedConventions, (DatabaseGeneratedAttributeConvention)valueGenerationStrategyConvention);

return conventionSet;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,30 @@ public SqlServerPropertyBuilderAnnotations(
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public new virtual bool ValueGenerationStrategy(SqlServerValueGenerationStrategy? value) => SetValueGenerationStrategy(value);
public new virtual bool ValueGenerationStrategy(SqlServerValueGenerationStrategy? value)
{
if (value == null)
{
PropertyBuilder.ValueGenerated(ValueGenerated.Never, ConfigurationSource.Convention);
PropertyBuilder.RequiresValueGenerator(false, ConfigurationSource.Convention);
HiLoSequenceName(null);
HiLoSequenceSchema(null);
}
else if (value.Value == SqlServerValueGenerationStrategy.IdentityColumn)
{
PropertyBuilder.ValueGenerated(ValueGenerated.OnAdd, ConfigurationSource.Convention);
PropertyBuilder.RequiresValueGenerator(true, ConfigurationSource.Convention);
HiLoSequenceName(null);
HiLoSequenceSchema(null);
}
else if (value.Value == SqlServerValueGenerationStrategy.SequenceHiLo)
{
PropertyBuilder.ValueGenerated(ValueGenerated.OnAdd, ConfigurationSource.Convention);
PropertyBuilder.RequiresValueGenerator(true, ConfigurationSource.Convention);
}

return SetValueGenerationStrategy(value);
}
#pragma warning restore 109
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ public DataAnnotationInMemoryTest(DataAnnotationInMemoryFixture fixture)
{
}

public override ModelBuilder DatabaseGeneratedOption_configures_the_property_correctly()
{
var modelBuilder = base.DatabaseGeneratedOption_configures_the_property_correctly();

var identity = modelBuilder.Model.FindEntityType(typeof(GeneratedEntity)).FindProperty(nameof(GeneratedEntity.Identity));
Assert.False(identity.RequiresValueGenerator);

return modelBuilder;
}

public override void ConcurrencyCheckAttribute_throws_if_value_in_database_changed()
{
using (var context = CreateContext())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Specification.Tests;
using Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests.Utilities;
using Microsoft.EntityFrameworkCore.Storage;
Expand All @@ -21,7 +22,6 @@ public DataAnnotationSqlServerTest(DataAnnotationSqlServerFixture fixture)
protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
=> facade.UseTransaction(transaction.GetDbTransaction());

[Fact]
public override ModelBuilder Non_public_annotations_are_enabled()
{
var modelBuilder = base.Non_public_annotations_are_enabled();
Expand All @@ -33,7 +33,6 @@ public override ModelBuilder Non_public_annotations_are_enabled()
return modelBuilder;
}

[Fact]
public override ModelBuilder Field_annotations_are_enabled()
{
var modelBuilder = base.Field_annotations_are_enabled();
Expand All @@ -45,7 +44,6 @@ public override ModelBuilder Field_annotations_are_enabled()
return modelBuilder;
}

[Fact]
public override ModelBuilder Key_and_column_work_together()
{
var modelBuilder = base.Key_and_column_work_together();
Expand All @@ -57,7 +55,6 @@ public override ModelBuilder Key_and_column_work_together()
return modelBuilder;
}

[Fact]
public override ModelBuilder Key_and_MaxLength_64_produce_nvarchar_64()
{
var modelBuilder = base.Key_and_MaxLength_64_produce_nvarchar_64();
Expand All @@ -68,7 +65,6 @@ public override ModelBuilder Key_and_MaxLength_64_produce_nvarchar_64()
return modelBuilder;
}

[Fact]
public override ModelBuilder Timestamp_takes_precedence_over_MaxLength()
{
var modelBuilder = base.Timestamp_takes_precedence_over_MaxLength();
Expand All @@ -79,7 +75,6 @@ public override ModelBuilder Timestamp_takes_precedence_over_MaxLength()
return modelBuilder;
}

[Fact]
public override ModelBuilder Timestamp_takes_precedence_over_MaxLength_with_value()
{
var modelBuilder = base.Timestamp_takes_precedence_over_MaxLength_with_value();
Expand All @@ -90,7 +85,6 @@ public override ModelBuilder Timestamp_takes_precedence_over_MaxLength_with_valu
return modelBuilder;
}

[Fact]
public override ModelBuilder TableNameAttribute_affects_table_name_in_TPH()
{
var modelBuilder = base.TableNameAttribute_affects_table_name_in_TPH();
Expand All @@ -101,6 +95,17 @@ public override ModelBuilder TableNameAttribute_affects_table_name_in_TPH()
return modelBuilder;
}

public override ModelBuilder DatabaseGeneratedOption_configures_the_property_correctly()
{
var modelBuilder = base.DatabaseGeneratedOption_configures_the_property_correctly();

var identity = modelBuilder.Model.FindEntityType(typeof(GeneratedEntity)).FindProperty(nameof(GeneratedEntity.Identity));
Assert.True(identity.RequiresValueGenerator);
Assert.Equal(SqlServerValueGenerationStrategy.IdentityColumn, identity.SqlServer().ValueGenerationStrategy);

return modelBuilder;
}

public override void ConcurrencyCheckAttribute_throws_if_value_in_database_changed()
{
base.ConcurrencyCheckAttribute_throws_if_value_in_database_changed();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ public void Setting_SqlServer_identity_column_is_higher_priority_than_relational
var property = model.FindEntityType(typeof(Customer)).FindProperty(nameof(Customer.Id));

Assert.Equal(SqlServerValueGenerationStrategy.IdentityColumn, property.SqlServer().ValueGenerationStrategy);
Assert.Equal(ValueGenerated.OnAdd, property.ValueGenerated);
Assert.Equal(ValueGenerated.OnAddOrUpdate, property.ValueGenerated);
Assert.Null(property.Relational().DefaultValue);
Assert.Null(property.SqlServer().DefaultValue);
Assert.Null(property.Relational().DefaultValueSql);
Expand Down
Loading