Skip to content

[5.0.1] Fix issues with property called FooId on base type Foo in TPT #23112

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 2 commits into from
Nov 12, 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
@@ -1,6 +1,8 @@
// 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 System.Text;
using JetBrains.Annotations;
Expand Down Expand Up @@ -154,12 +156,13 @@ private IConventionIndexBuilder SetIndexFilter(IConventionIndexBuilder indexBuil
var index = indexBuilder.Metadata;
if (index.IsUnique
&& index.IsClustered() != true
&& index.Properties.Any(property => property.IsColumnNullable()))
&& GetNullableColumns(index) is List<string> nullableColumns
&& nullableColumns.Count > 0)
{
if (columnNameChanged
|| index.GetFilter() == null)
{
indexBuilder.HasFilter(CreateIndexFilter(index));
indexBuilder.HasFilter(CreateIndexFilter(nullableColumns));
}
}
else
Expand All @@ -173,20 +176,8 @@ private IConventionIndexBuilder SetIndexFilter(IConventionIndexBuilder indexBuil
return indexBuilder;
}

private string CreateIndexFilter(IIndex index)
private string CreateIndexFilter(List<string> nullableColumns)
{
var tableName = index.DeclaringEntityType.GetTableName();
if (tableName == null)
{
return null;
}

var table = StoreObjectIdentifier.Table(tableName, index.DeclaringEntityType.GetSchema());
var nullableColumns = index.Properties
.Where(property => property.IsColumnNullable(table))
.Select(property => property.GetColumnName(table))
.ToList();

var builder = new StringBuilder();
for (var i = 0; i < nullableColumns.Count; i++)
{
Expand All @@ -202,5 +193,36 @@ private string CreateIndexFilter(IIndex index)

return builder.ToString();
}

private List<string> GetNullableColumns(IIndex index)
{
var tableName = index.DeclaringEntityType.GetTableName();
if (tableName == null)
{
return null;
}

var useOldBehavior = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue23092_2", out var isEnabled) && isEnabled;
var nullableColumns = new List<string>();
var table = StoreObjectIdentifier.Table(tableName, index.DeclaringEntityType.GetSchema());
foreach (var property in index.Properties)
{
var columnName = property.GetColumnName(table);
if (columnName == null
&& !useOldBehavior)
{
return null;
}

if (!property.IsColumnNullable(table))
{
continue;
}

nullableColumns.Add(columnName);
}

return nullableColumns;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,17 @@ private IConventionForeignKeyBuilder DiscoverProperties(
IConventionForeignKeyBuilder relationshipBuilder,
IConventionContext context)
{
var useOldBehavior = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue23092_1", out var isEnabled) && isEnabled;

var foreignKey = relationshipBuilder.Metadata;
if (!ConfigurationSource.Convention.Overrides(foreignKey.GetPropertiesConfigurationSource()))
var foreignKeyProperties = FindCandidateForeignKeyProperties(relationshipBuilder.Metadata, onDependent: true);
var propertiesConfigurationSource = foreignKey.GetPropertiesConfigurationSource();
if (!ConfigurationSource.Convention.OverridesStrictly(propertiesConfigurationSource)
&& (propertiesConfigurationSource != ConfigurationSource.Convention
|| (!useOldBehavior
&& foreignKey.Properties.All(p => !p.IsImplicitlyCreated())
&& (foreignKeyProperties == null
|| !foreignKey.Properties.SequenceEqual(foreignKeyProperties)))))
{
var batch = context.DelayConventions();
using var foreignKeyReference = batch.Track(foreignKey);
Expand Down Expand Up @@ -184,7 +193,6 @@ private IConventionForeignKeyBuilder DiscoverProperties(
}
}

var foreignKeyProperties = FindCandidateForeignKeyProperties(relationshipBuilder.Metadata, onDependent: true);
if (foreignKeyProperties == null)
{
if (invertible
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,33 @@ public virtual void TPT_identifying_FK_are_created_only_on_declaring_type()
Assert.Single(sesameBunFk.GetMappedConstraints());
}

[ConditionalFact]
public virtual void TPT_index_can_use_inherited_properties()
{
var modelBuilder = CreateModelBuilder();
modelBuilder.Entity<BigMak>()
.Ignore(b => b.Bun)
.Ignore(b => b.Pickles);
modelBuilder.Entity<Ingredient>(b =>
{
b.ToTable("Ingredients");
b.Property<int?>("NullableProp");
b.Ignore(i => i.BigMak);
});
modelBuilder.Entity<Bun>(b =>
{
b.ToTable("Buns");
b.HasIndex(bun => bun.BurgerId);
b.HasIndex("NullableProp");
b.HasOne(i => i.BigMak).WithOne().HasForeignKey<Bun>(i => i.Id);
});

var model = modelBuilder.FinalizeModel();

var bunType = model.FindEntityType(typeof(Bun));
Assert.All(bunType.GetIndexes(), i => Assert.Null(i.GetFilter()));
}

public class Parent
{
public int Id { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,29 @@ public void Does_not_match_dependent_PK_for_self_ref()
ValidateModel();
}

[ConditionalFact]
public void Does_not_match_for_convention_identifying_FK()
{
var derivedType = PrincipalType.Builder.ModelBuilder.Entity(typeof(DerivedPrincipalEntity), ConfigurationSource.Convention);
derivedType.HasBaseType(PrincipalType, ConfigurationSource.Convention);

PrincipalType.Builder.Property(typeof(int), nameof(PrincipalEntity.PrincipalEntityId), ConfigurationSource.Convention);
var relationshipBuilder = derivedType.HasRelationship(
PrincipalType, PrincipalType.FindPrimaryKey().Properties, ConfigurationSource.Convention)
.IsUnique(true, ConfigurationSource.DataAnnotation);

var newRelationshipBuilder = RunConvention(relationshipBuilder);
Assert.Same(relationshipBuilder, newRelationshipBuilder);

var fk = (IForeignKey)relationshipBuilder.Metadata;
Assert.Equal(nameof(PrincipalEntity.PeeKay), fk.Properties.Single().Name);
Assert.Same(fk, derivedType.Metadata.GetForeignKeys().Single());
Assert.True(fk.IsUnique);
Assert.True(fk.IsRequired);

ValidateModel();
}

[ConditionalFact]
public void Matches_composite_dependent_PK_for_unique_FK()
{
Expand Down Expand Up @@ -1192,13 +1215,18 @@ private class PrincipalEntity
public static readonly PropertyInfo DependentEntityKayPeeProperty =
typeof(PrincipalEntity).GetProperty("DependentEntityKayPee");

public int PrincipalEntityId { get; set; }
public int PeeKay { get; set; }
public int? DependentEntityKayPee { get; set; }
public IEnumerable<DependentEntity> InverseNav { get; set; }
public DependentEntity InverseReferenceNav { get; set; }
public PrincipalEntity SelfRef { get; set; }
}

private class DerivedPrincipalEntity : PrincipalEntity
{
}

private class DependentEntity
{
public static readonly PropertyInfo SomeNavIDProperty = typeof(DependentEntity).GetProperty("SomeNavID");
Expand Down