Proper support for table splitting (#55)

Fixes #54
This commit is contained in:
Shay Rojansky
2020-12-17 15:25:00 +02:00
committed by GitHub
parent 1f7549dc73
commit 4cb06461dd
6 changed files with 228 additions and 35 deletions

View File

@@ -9,7 +9,12 @@
<PackageReference Include="xunit.runner.visualstudio" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Specification.Tests" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Specification.Tests" />
<PackageReference Include="Microsoft.Extensions.Configuration" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,103 @@
// 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.Linq;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Xunit;
namespace EFCore.NamingConventions.Test
{
public class EndToEndTest : IClassFixture<EndToEndTest.EndToEndTestFixture>
{
public EndToEndTest(EndToEndTestFixture fixture)
=> Fixture = fixture;
[Fact]
public void Table_splitting()
{
using var context = CreateContext();
var split1EntityType = context.Model.FindEntityType(typeof(Split1));
var split2EntityType = context.Model.FindEntityType(typeof(Split2));
var table = StoreObjectIdentifier.Create(split1EntityType, StoreObjectType.Table)!.Value;
Assert.Equal(table, StoreObjectIdentifier.Create(split2EntityType, StoreObjectType.Table));
Assert.Equal("common", split1EntityType.FindProperty("Common").GetColumnName(table));
Assert.Equal("split2_common", split2EntityType.FindProperty("Common").GetColumnName(table));
var split1 = context.Set<Split1>().Include(s1 => s1.Split2).Single();
Assert.Equal(100, split1.Common);
Assert.Equal(101, split1.Split2.Common);
}
TestContext CreateContext() => Fixture.CreateContext();
readonly EndToEndTestFixture Fixture;
public class TestContext : DbContext
{
public TestContext(SqliteConnection connection)
: base(new DbContextOptionsBuilder<TestContext>()
.UseSqlite(connection)
.UseSnakeCaseNamingConvention()
.Options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Split1>(e =>
{
e.ToTable("split");
e.HasOne(s1 => s1.Split2).WithOne(s2 => s2.Split1).HasForeignKey<Split2>(s2 => s2.Id);
e.HasData(new Split1 { Id = 1, OneProp = 1, Common = 100 });
});
modelBuilder.Entity<Split2>(e =>
{
e.ToTable("split");
e.HasData(new Split2 { Id = 1, TwoProp = 2, Common = 101 });
});
}
}
public class Split1
{
public int Id { get; set; }
public int OneProp { get; set; }
public int Common { get; set; }
public Split2 Split2 { get; set; }
}
public class Split2
{
public int Id { get; set; }
public int TwoProp { get; set; }
public int Common { get; set; }
public Split1 Split1 { get; set; }
}
public class EndToEndTestFixture : IDisposable
{
private readonly SqliteConnection _connection;
public TestContext CreateContext() => new(_connection);
public EndToEndTestFixture()
{
_connection = new SqliteConnection("Filename=:memory:");
_connection.Open();
using var context = new TestContext(_connection);
context.Database.EnsureCreated();
}
public void Dispose() => _connection.Dispose();
}
}
}

View File

@@ -133,6 +133,54 @@ namespace EFCore.NamingConventions.Test
Assert.Equal("ix_simple_blog_indexed_property", entityType.GetIndexes().Single().GetDatabaseName());
}
[Fact]
public void Table_splitting()
{
var model = BuildModel(b =>
{
b.Entity("One", e =>
{
e.ToTable("table");
e.Property<int>("Id");
e.Property<int>("OneProp");
e.Property<int>("Common");
e.HasOne("Two").WithOne().HasForeignKey("Two", "Id");
});
b.Entity("Two", e =>
{
e.ToTable("table");
e.Property<int>("Id");
e.Property<int>("TwoProp");
e.Property<int>("Common");
});
});
var oneEntityType = model.FindEntityType("One");
var twoEntityType = model.FindEntityType("Two");
var table = StoreObjectIdentifier.Create(oneEntityType, StoreObjectType.Table)!.Value;
Assert.Equal(table, StoreObjectIdentifier.Create(twoEntityType, StoreObjectType.Table));
Assert.Equal("table", oneEntityType.GetTableName());
Assert.Equal("one_prop", oneEntityType.FindProperty("OneProp").GetColumnName(table));
Assert.Equal("table", twoEntityType.GetTableName());
Assert.Equal("two_prop", twoEntityType.FindProperty("TwoProp").GetColumnName(table));
var foreignKey = twoEntityType.GetForeignKeys().Single();
Assert.Same(oneEntityType.FindPrimaryKey(), foreignKey.PrincipalKey);
Assert.Same(twoEntityType.FindPrimaryKey().Properties.Single(), foreignKey.Properties.Single());
Assert.Equal(oneEntityType.FindPrimaryKey().GetName(), twoEntityType.FindPrimaryKey().GetName());
Assert.Equal(
foreignKey.PrincipalKey.Properties.Single().GetColumnName(table),
foreignKey.Properties.Single().GetColumnName(table));
Assert.Empty(oneEntityType.GetForeignKeys());
}
#region Owned entities
[Fact]