Skip to content

Commit

Permalink
Metadata: Avoid sharing default mappings for entity types (#25734)
Browse files Browse the repository at this point in the history
Resolves #23981
  • Loading branch information
smitpatel committed Aug 27, 2021
1 parent d30d9ea commit a6ad9e5
Show file tree
Hide file tree
Showing 14 changed files with 320 additions and 237 deletions.
2 changes: 1 addition & 1 deletion src/EFCore.Relational/Metadata/Internal/RelationalModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ public static IRelationalModel Create(
private static void AddDefaultMappings(RelationalModel databaseModel, IEntityType entityType)
{
var rootType = entityType.GetRootType();
var name = rootType.HasSharedClrType ? rootType.Name : rootType.ShortName();
var name = rootType.Name;
if (!databaseModel.DefaultTables.TryGetValue(name, out var defaultTable))
{
defaultTable = new TableBase(name, null, databaseModel);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.TestUtilities;
using Xunit;

namespace Microsoft.EntityFrameworkCore.Query
{
Expand All @@ -13,5 +14,55 @@ protected TestSqlLoggerFactory TestSqlLoggerFactory
protected void ClearLog() => TestSqlLoggerFactory.Clear();

protected void AssertSql(params string[] expected) => TestSqlLoggerFactory.AssertBaseline(expected);

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Multiple_different_entity_type_from_different_namespaces(bool async)
{
var contextFactory = await InitializeAsync<Context23981>();
using var context = contextFactory.CreateContext();
//var good1 = context.Set<NameSpace1.TestQuery>().FromSqlRaw(@"SELECT 1 AS MyValue").ToList(); // OK
//var good2 = context.Set<NameSpace2.TestQuery>().FromSqlRaw(@"SELECT 1 AS MyValue").ToList(); // OK
var bad = context.Set<NameSpace1.TestQuery>().FromSqlRaw(@"SELECT cast(null as int) AS MyValue").ToList(); // Exception
}

protected class Context23981 : DbContext
{
public Context23981(DbContextOptions options)
: base(options)
{
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var mb = modelBuilder.Entity(typeof(NameSpace1.TestQuery));

mb.HasBaseType((Type)null);
mb.HasNoKey();
mb.ToTable((string)null);

mb = modelBuilder.Entity(typeof(NameSpace2.TestQuery));

mb.HasBaseType((Type)null);
mb.HasNoKey();
mb.ToTable((string)null);
}
}
}
}

namespace NameSpace1
{
public class TestQuery
{
public int? MyValue { get; set; }
}
}

namespace NameSpace2
{
public class TestQuery
{
public int MyValue { get; set; }
}
}
47 changes: 45 additions & 2 deletions test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ private static void AssertDefaultMappings(IRelationalModel model)
Assert.Equal(
new[] { nameof(Order.AlternateId), nameof(Order.CustomerId), nameof(Order.Id), "OrderDate" },
ordersTable.Columns.Select(m => m.Name));
Assert.Equal("Order", ordersTable.Name);
Assert.Equal("Microsoft.EntityFrameworkCore.Metadata.RelationalModelTest+Order", ordersTable.Name);
Assert.Null(ordersTable.Schema);

var orderDate = orderType.FindProperty(nameof(Order.OrderDate));
Expand Down Expand Up @@ -122,7 +122,7 @@ private static void AssertDefaultMappings(IRelationalModel model)

var customerType = model.Model.FindEntityType(typeof(Customer));
var customerTable = customerType.GetDefaultMappings().Single().Table;
Assert.Equal("Customer", customerTable.Name);
Assert.Equal("Microsoft.EntityFrameworkCore.Metadata.RelationalModelTest+Customer", customerTable.Name);
Assert.Null(customerTable.Schema);

var specialCustomerType = model.Model.FindEntityType(typeof(SpecialCustomer));
Expand Down Expand Up @@ -907,6 +907,33 @@ public void Can_use_relational_model_with_functions()
Assert.Equal(tvfDbFunction.Parameters.Single().Name, tvfFunction.Parameters.Single().DbFunctionParameters.Single().Name);
}

[ConditionalFact]
public void Default_mappings_does_not_share_tableBase()
{
var modelBuilder = CreateConventionModelBuilder();
modelBuilder.Entity<NameSpace1.SameEntityType>().HasNoKey().ToTable((string)null);
modelBuilder.Entity<NameSpace2.SameEntityType>().HasNoKey().ToTable((string)null);

var model = Finalize(modelBuilder);

Assert.Equal(2, model.Model.GetEntityTypes().Count());
Assert.Empty(model.Tables);
Assert.Empty(model.Views);
Assert.Empty(model.Functions);
Assert.Empty(model.Queries);

var entityType1 = model.Model.FindEntityType(typeof(NameSpace1.SameEntityType));
var entityType2 = model.Model.FindEntityType(typeof(NameSpace2.SameEntityType));

var defaultMapping1 = Assert.Single(entityType1.GetDefaultMappings());
var defaultMapping2 = Assert.Single(entityType2.GetDefaultMappings());

Assert.NotSame(defaultMapping1, defaultMapping2);

Assert.True(defaultMapping1.Table.Columns.Single().IsNullable);
Assert.False(defaultMapping2.Table.Columns.Single().IsNullable);
}

private static IRelationalModel Finalize(TestHelpers.TestModelBuilder modelBuilder)
=> modelBuilder.FinalizeModel(designTime: true).GetRelationalModel();

Expand Down Expand Up @@ -994,3 +1021,19 @@ private class Address
}
}
}

namespace NameSpace1
{
public class SameEntityType
{
public int? MyValue { get; set; }
}
}

namespace NameSpace2
{
public class SameEntityType
{
public int MyValue { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1108,18 +1108,18 @@ public void Multiple_complex_includes_from_sql()
Assert.Equal(13, results.Count);

AssertSql(
@"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id], [l0].[Id], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Optional_Self_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToMany_Required_Self_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[OneToOne_Optional_Self2Id], [l1].[Id], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id], [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [t].[Id0], [t].[Level2_Optional_Id], [t].[Level2_Required_Id], [t].[Name0], [t].[OneToMany_Optional_Inverse3Id], [t].[OneToMany_Optional_Self_Inverse3Id], [t].[OneToMany_Required_Inverse3Id], [t].[OneToMany_Required_Self_Inverse3Id], [t].[OneToOne_Optional_PK_Inverse3Id], [t].[OneToOne_Optional_Self3Id]
@"SELECT [m].[Id], [m].[Date], [m].[Name], [m].[OneToMany_Optional_Self_Inverse1Id], [m].[OneToMany_Required_Self_Inverse1Id], [m].[OneToOne_Optional_Self1Id], [l].[Id], [l].[Date], [l].[Level1_Optional_Id], [l].[Level1_Required_Id], [l].[Name], [l].[OneToMany_Optional_Inverse2Id], [l].[OneToMany_Optional_Self_Inverse2Id], [l].[OneToMany_Required_Inverse2Id], [l].[OneToMany_Required_Self_Inverse2Id], [l].[OneToOne_Optional_PK_Inverse2Id], [l].[OneToOne_Optional_Self2Id], [l0].[Id], [l0].[Level2_Optional_Id], [l0].[Level2_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse3Id], [l0].[OneToMany_Optional_Self_Inverse3Id], [l0].[OneToMany_Required_Inverse3Id], [l0].[OneToMany_Required_Self_Inverse3Id], [l0].[OneToOne_Optional_PK_Inverse3Id], [l0].[OneToOne_Optional_Self3Id], [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [t].[Id0], [t].[Level2_Optional_Id], [t].[Level2_Required_Id], [t].[Name0], [t].[OneToMany_Optional_Inverse3Id], [t].[OneToMany_Optional_Self_Inverse3Id], [t].[OneToMany_Required_Inverse3Id], [t].[OneToMany_Required_Self_Inverse3Id], [t].[OneToOne_Optional_PK_Inverse3Id], [t].[OneToOne_Optional_Self3Id]
FROM (
SELECT * FROM [LevelOne]
) AS [l]
LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id]
LEFT JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[OneToMany_Optional_Inverse3Id]
) AS [m]
LEFT JOIN [LevelTwo] AS [l] ON [m].[Id] = [l].[Level1_Optional_Id]
LEFT JOIN [LevelThree] AS [l0] ON [l].[Id] = [l0].[OneToMany_Optional_Inverse3Id]
LEFT JOIN (
SELECT [l2].[Id], [l2].[Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_Inverse2Id], [l2].[OneToMany_Optional_Self_Inverse2Id], [l2].[OneToMany_Required_Inverse2Id], [l2].[OneToMany_Required_Self_Inverse2Id], [l2].[OneToOne_Optional_PK_Inverse2Id], [l2].[OneToOne_Optional_Self2Id], [l3].[Id] AS [Id0], [l3].[Level2_Optional_Id], [l3].[Level2_Required_Id], [l3].[Name] AS [Name0], [l3].[OneToMany_Optional_Inverse3Id], [l3].[OneToMany_Optional_Self_Inverse3Id], [l3].[OneToMany_Required_Inverse3Id], [l3].[OneToMany_Required_Self_Inverse3Id], [l3].[OneToOne_Optional_PK_Inverse3Id], [l3].[OneToOne_Optional_Self3Id]
FROM [LevelTwo] AS [l2]
LEFT JOIN [LevelThree] AS [l3] ON [l2].[Id] = [l3].[Level2_Optional_Id]
) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id]
ORDER BY [l].[Id], [l0].[Id], [l1].[Id], [t].[Id]");
SELECT [l1].[Id], [l1].[Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse2Id], [l1].[OneToMany_Optional_Self_Inverse2Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[OneToMany_Required_Self_Inverse2Id], [l1].[OneToOne_Optional_PK_Inverse2Id], [l1].[OneToOne_Optional_Self2Id], [l2].[Id] AS [Id0], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Name] AS [Name0], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Optional_Self_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToMany_Required_Self_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[OneToOne_Optional_Self3Id]
FROM [LevelTwo] AS [l1]
LEFT JOIN [LevelThree] AS [l2] ON [l1].[Id] = [l2].[Level2_Optional_Id]
) AS [t] ON [m].[Id] = [t].[OneToMany_Optional_Inverse2Id]
ORDER BY [m].[Id], [l].[Id], [l0].[Id], [t].[Id]");
}

public override async Task Where_navigation_property_to_collection(bool async)
Expand Down
Loading

0 comments on commit a6ad9e5

Please sign in to comment.