using System; using System.Globalization; using System.Linq; using System.Threading.Tasks; using EntityFrameworkCore.Jet; using Extensions.DependencyInjection; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Xunit; namespace EntityFramework.Jet.FunctionalTests { public class CompositeKeyEndToEndTest { [Fact] public async Task Can_use_two_non_generated_integers_as_composite_key_end_to_end() { var serviceProvider = new ServiceCollection() .AddEntityFrameworkJet() .BuildServiceProvider(); var ticks = DateTime.UtcNow.Ticks % 15091969; using (var context = new BronieContext(serviceProvider, "CompositePegasuses")) { context.Database.EnsureCreated(); context.Add(new Pegasus { Id1 = ticks, Id2 = ticks + 1, Name = "Rainbow Dash" }); await context.SaveChangesAsync(); } using (var context = new BronieContext(serviceProvider, "CompositePegasuses")) { var pegasus = context.Pegasuses.Single(e => e.Id1 == ticks && e.Id2 == ticks + 1); pegasus.Name = "Rainbow Crash"; await context.SaveChangesAsync(); } using (var context = new BronieContext(serviceProvider, "CompositePegasuses")) { var pegasus = context.Pegasuses.Single(e => e.Id1 == ticks && e.Id2 == ticks + 1); Assert.Equal("Rainbow Crash", pegasus.Name); context.Pegasuses.Remove(pegasus); await context.SaveChangesAsync(); } using (var context = new BronieContext(serviceProvider, "CompositePegasuses")) { Assert.Equal(0, context.Pegasuses.Count(e => e.Id1 == ticks && e.Id2 == ticks + 1)); } } [Fact] public async Task Can_use_generated_values_in_composite_key_end_to_end() { var serviceProvider = new ServiceCollection() .AddEntityFrameworkJet() .BuildServiceProvider(); long id1; var id2 = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture); Guid id3; using (var context = new BronieContext(serviceProvider, "CompositeUnicorns")) { context.Database.EnsureCreated(); var added = context.Add(new Unicorn { Id2 = id2, Name = "Rarity" }).Entity; Assert.True(added.Id1 < 0); Assert.NotEqual(Guid.Empty, added.Id3); await context.SaveChangesAsync(); Assert.True(added.Id1 > 0); id1 = added.Id1; id3 = added.Id3; } using (var context = new BronieContext(serviceProvider, "CompositeUnicorns")) { Assert.Equal(1, context.Unicorns.Count(e => e.Id1 == id1 && e.Id2 == id2 && e.Id3 == id3)); } using (var context = new BronieContext(serviceProvider, "CompositeUnicorns")) { var unicorn = context.Unicorns.Single(e => e.Id1 == id1 && e.Id2 == id2 && e.Id3 == id3); unicorn.Name = "Bad Hair Day"; await context.SaveChangesAsync(); } using (var context = new BronieContext(serviceProvider, "CompositeUnicorns")) { var unicorn = context.Unicorns.Single(e => e.Id1 == id1 && e.Id2 == id2 && e.Id3 == id3); Assert.Equal("Bad Hair Day", unicorn.Name); context.Unicorns.Remove(unicorn); await context.SaveChangesAsync(); } using (var context = new BronieContext(serviceProvider, "CompositeUnicorns")) { Assert.Equal(0, context.Unicorns.Count(e => e.Id1 == id1 && e.Id2 == id2 && e.Id3 == id3)); } } [Fact] public async Task Only_one_part_of_a_composite_key_needs_to_vary_for_uniquness() { var serviceProvider = new ServiceCollection() .AddEntityFrameworkJet() .BuildServiceProvider(); var ids = new int[3]; using (var context = new BronieContext(serviceProvider, "CompositeEarthPonies")) { context.Database.EnsureCreated(); var pony1 = context.Add(new EarthPony { Id2 = 7, Name = "Apple Jack 1" }).Entity; var pony2 = context.Add(new EarthPony { Id2 = 7, Name = "Apple Jack 2" }).Entity; var pony3 = context.Add(new EarthPony { Id2 = 7, Name = "Apple Jack 3" }).Entity; await context.SaveChangesAsync(); ids[0] = pony1.Id1; ids[1] = pony2.Id1; ids[2] = pony3.Id1; } using (var context = new BronieContext(serviceProvider, "CompositeEarthPonies")) { var ponies = context.EarthPonies.ToList(); Assert.Equal(ponies.Count, ponies.Count(e => e.Name == "Apple Jack 1") * 3); Assert.Equal("Apple Jack 1", ponies.Single(e => e.Id1 == ids[0]).Name); Assert.Equal("Apple Jack 2", ponies.Single(e => e.Id1 == ids[1]).Name); Assert.Equal("Apple Jack 3", ponies.Single(e => e.Id1 == ids[2]).Name); ponies.Single(e => e.Id1 == ids[1]).Name = "Pinky Pie 2"; await context.SaveChangesAsync(); } using (var context = new BronieContext(serviceProvider, "CompositeEarthPonies")) { var ponies = context.EarthPonies.ToArray(); Assert.Equal(ponies.Length, ponies.Count(e => e.Name == "Apple Jack 1") * 3); Assert.Equal("Apple Jack 1", ponies.Single(e => e.Id1 == ids[0]).Name); Assert.Equal("Pinky Pie 2", ponies.Single(e => e.Id1 == ids[1]).Name); Assert.Equal("Apple Jack 3", ponies.Single(e => e.Id1 == ids[2]).Name); context.EarthPonies.RemoveRange(ponies); await context.SaveChangesAsync(); } using (var context = new BronieContext(serviceProvider, "CompositeEarthPonies")) { Assert.Equal(0, context.EarthPonies.Count()); } } private class BronieContext : DbContext { private readonly string _databaseName; private readonly IServiceProvider _serviceProvider; public BronieContext(IServiceProvider serviceProvider, string databaseName) { _databaseName = databaseName; _serviceProvider = serviceProvider; } public DbSet Pegasuses { get; set; } public DbSet Unicorns { get; set; } public DbSet EarthPonies { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .UseJet(JetTestStore.CreateConnectionString(_databaseName)) .UseInternalServiceProvider(_serviceProvider); } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity(b => { b.ToTable("Pegasus"); b.HasKey(e => new { e.Id1, e.Id2 }); }); modelBuilder.Entity(b => { b.ToTable("Unicorn"); b.HasKey(e => new { e.Id1, e.Id2, e.Id3 }); b.Property(e => e.Id1).ValueGeneratedOnAdd(); b.Property(e => e.Id3).ValueGeneratedOnAdd(); }); modelBuilder.Entity(b => { b.ToTable("EarthPony"); b.HasKey(e => new { e.Id1, e.Id2 }); b.Property(e => e.Id1).ValueGeneratedOnAdd(); }); } } private class Pegasus { public long Id1 { get; set; } public long Id2 { get; set; } public string Name { get; set; } } private class Unicorn { public int Id1 { get; set; } public string Id2 { get; set; } public Guid Id3 { get; set; } public string Name { get; set; } } private class EarthPony { public int Id1 { get; set; } public int Id2 { get; set; } public string Name { get; set; } } } }