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

Fix for 20590. Added OwnedNavigationBuilder version of HasCheckConstraint() #20632

Merged
merged 1 commit into from
Apr 16, 2020
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
@@ -0,0 +1,71 @@
// 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 JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Utilities;

// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore
{
/// <summary>
/// Relational database specific extension methods for <see cref="OwnedNavigationBuilder" />.
/// </summary>
public static class RelationalOwnedNavigationBuilderExtensions
{
/// <summary>
/// Configures a database check constraint when targeting a relational database.
/// </summary>
/// <param name="ownedNavigationBuilder"> The navigation builder for the owned type. </param>
/// <param name="name"> The name of the check constraint. </param>
/// <param name="sql"> The logical constraint sql used in the check constraint. </param>
/// <returns> A builder to further configure the navigation. </returns>
public static OwnedNavigationBuilder HasCheckConstraint(
[NotNull] this OwnedNavigationBuilder ownedNavigationBuilder,
[NotNull] string name,
[CanBeNull] string sql)
{
Check.NotNull(ownedNavigationBuilder, nameof(ownedNavigationBuilder));
Check.NotEmpty(name, nameof(name));
Check.NullButNotEmpty(sql, nameof(sql));

var entityType = ownedNavigationBuilder.Metadata.DeclaringEntityType;

var constraint = entityType.FindCheckConstraint(name);
if (constraint != null)
{
if (constraint.Sql == sql)
{
return ownedNavigationBuilder;
}

entityType.RemoveCheckConstraint(name);
}

if (sql != null)
{
entityType.AddCheckConstraint(name, sql);
}

return ownedNavigationBuilder;
}

/// <summary>
/// Configures a database check constraint when targeting a relational database.
/// </summary>
/// <typeparam name="TEntity"> The entity type owning the relationship. </typeparam>
/// <typeparam name="TDependentEntity"> The dependent entity type of the relationship. </typeparam>
/// <param name="ownedNavigationBuilder"> The navigation builder for the owned type. </param>
/// <param name="name"> The name of the check constraint. </param>
/// <param name="sql"> The logical constraint sql used in the check constraint. </param>
/// <returns> A builder to further configure the navigation. </returns>
public static OwnedNavigationBuilder<TEntity, TDependentEntity> HasCheckConstraint<TEntity, TDependentEntity>(
[NotNull] this OwnedNavigationBuilder<TEntity, TDependentEntity> ownedNavigationBuilder,
[NotNull] string name,
[CanBeNull] string sql)
where TEntity : class
where TDependentEntity : class
=> (OwnedNavigationBuilder<TEntity, TDependentEntity>)
HasCheckConstraint((OwnedNavigationBuilder)ownedNavigationBuilder, name, sql);
}
}
97 changes: 97 additions & 0 deletions test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,25 @@ private class EntityWithGenericProperty<TProperty>
public TProperty Property { get; set; }
}

public class TestOwner
{
public int Id { get; set; }
public ICollection<TestOwnee> OwnedEntities { get; set; }
}

public class TestOwnee
{
public int Id { get; set; }
public TestEnum TestEnum { get; set; }
}

public enum TestEnum : int
{
Value0 = 0,
Value1,
Value2
}

private class BaseEntity
{
public int Id { get; set; }
Expand Down Expand Up @@ -1428,6 +1447,84 @@ public virtual void Weak_owned_types_are_stored_in_snapshot()
});
}

[ConditionalFact]
public virtual void Snapshot_with_OwnedNavigationBuilder_HasCheckConstraint_compiles()
{
Test(
modelBuilder =>
{
modelBuilder.Entity<TestOwner>()
.OwnsMany(o => o.OwnedEntities);
},
@"// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;

namespace RootNamespace
{
[DbContext(typeof(DbContext))]
partial class Snapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation(""Relational:MaxIdentifierLength"", 128)
.HasAnnotation(""SqlServer:ValueGenerationStrategy"", SqlServerValueGenerationStrategy.IdentityColumn);

modelBuilder.Entity(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+TestOwner"", b =>
{
b.Property<int>(""Id"")
.ValueGeneratedOnAdd()
.HasColumnType(""int"")
.HasAnnotation(""SqlServer:ValueGenerationStrategy"", SqlServerValueGenerationStrategy.IdentityColumn);

b.HasKey(""Id"");

b.ToTable(""TestOwner"");
});

modelBuilder.Entity(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+TestOwner"", b =>
{
b.OwnsMany(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+TestOwnee"", ""OwnedEntities"", b1 =>
{
b1.Property<int>(""TestOwnerId"")
.HasColumnType(""int"");

b1.Property<int>(""Id"")
.ValueGeneratedOnAdd()
.HasColumnType(""int"")
.HasAnnotation(""SqlServer:ValueGenerationStrategy"", SqlServerValueGenerationStrategy.IdentityColumn);

b1.Property<int>(""TestEnum"")
.HasColumnType(""int"");

b1.HasKey(""TestOwnerId"", ""Id"");

b1.ToTable(""TestOwnee"");

b1.HasCheckConstraint(""CK_TestOwnee_TestEnum_Enum_Constraint"", ""[TestEnum] IN(0, 1, 2)"");

b1.WithOwner()
.HasForeignKey(""TestOwnerId"");
});
});
#pragma warning restore 612, 618
}
}
}
",
model =>
{
Assert.Equal(2, model.GetEntityTypes().Count());
var testOwnee = model.FindEntityType(
"Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+TestOwnee");
Assert.NotNull(testOwnee.FindCheckConstraint("CK_TestOwnee_TestEnum_Enum_Constraint"));
});
}

private class Order
{
public int Id { get; set; }
Expand Down