diff --git a/test/EFCore.Relational.Specification.Tests/MigrationsTestBase.cs b/test/EFCore.Relational.Specification.Tests/MigrationsTestBase.cs index 7e79736b8bb..36468f1e89b 100644 --- a/test/EFCore.Relational.Specification.Tests/MigrationsTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/MigrationsTestBase.cs @@ -357,6 +357,26 @@ protected virtual Task ExecuteAsync(IServiceProvider services, Action(); + var operations = modelDiffer.GetDifferences(sourceModel, targetModel); + + Assert.Equal(0, operations.Count); + } + protected virtual void BuildFirstMigration(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( diff --git a/test/EFCore.Specification.Tests/MusicStoreTestBase.cs b/test/EFCore.Specification.Tests/MusicStoreTestBase.cs index 74e7c0de608..965325ad046 100644 --- a/test/EFCore.Specification.Tests/MusicStoreTestBase.cs +++ b/test/EFCore.Specification.Tests/MusicStoreTestBase.cs @@ -2,9 +2,11 @@ // 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.Threading.Tasks; using Microsoft.EntityFrameworkCore.TestModels.MusicStore; +using Microsoft.Extensions.Primitives; using Xunit; namespace Microsoft.EntityFrameworkCore @@ -18,6 +20,320 @@ protected MusicStoreTestBase(TFixture fixture) fixture.ListLoggerFactory.Clear(); } + [ConditionalFact] + public async Task Browse_ReturnsViewWithGenre() + { + using (var context = CreateContext()) + { + using (Fixture.BeginTransaction(context)) + { + const string genreName = "Genre 1"; + CreateTestGenres(numberOfGenres: 3, numberOfAlbums: 3, context: context); + + var controller = new StoreController(context); + + var result = await controller.Browse(genreName); + + Assert.Equal(genreName, result.Name); + Assert.NotNull(result.Albums); + Assert.Equal(3, result.Albums.Count); + } + } + } + + [ConditionalFact] + public async Task Index_CreatesViewWithGenres() + { + using (var context = CreateContext()) + { + using (Fixture.BeginTransaction(context)) + { + CreateTestGenres(numberOfGenres: 10, numberOfAlbums: 1, context: context); + + var controller = new StoreController(context); + + var result = await controller.Index(); + + Assert.Equal(10, result.Count); + } + } + } + + [ConditionalFact] + public async Task Details_ReturnsAlbumDetail() + { + using (var context = CreateContext()) + { + using (Fixture.BeginTransaction(context)) + { + var genres = CreateTestGenres(numberOfGenres: 3, numberOfAlbums: 3, context: context); + var albumId = genres.First().Albums[2].AlbumId; + + var controller = new StoreController(context); + + var result = await controller.Details(albumId); + + Assert.NotNull(result.Genre); + var genre = genres.SingleOrDefault(g => g.GenreId == result.GenreId); + Assert.NotNull(genre); + Assert.NotNull(genre.Albums.SingleOrDefault(a => a.AlbumId == albumId)); + Assert.NotNull(result.Artist); + Assert.NotEqual(0, result.ArtistId); + } + } + } + + private static Genre[] CreateTestGenres(int numberOfGenres, int numberOfAlbums, DbContext context) + { + var artist = new Artist + { + Name = "Artist1" + }; + + var genres = Enumerable.Range(1, numberOfGenres).Select( + g => + new Genre + { + Name = "Genre " + g, + Albums = Enumerable.Range(1, numberOfAlbums).Select( + n => + new Album + { + Artist = artist, Title = "Greatest Hits" + }).ToList() + }).ToList(); + + context.AddRange(genres); + context.SaveChanges(); + + return genres.ToArray(); + } + + [ConditionalFact] + public async Task Index_GetsSixTopAlbums() + { + using (var context = CreateContext()) + { + using (Fixture.BeginTransaction(context)) + { + var controller = new HomeController(); + + var albums = TestAlbumDataProvider.GetAlbums(); + + foreach (var album in albums) + { + context.Add(album); + } + + context.SaveChanges(); + + var result = await controller.Index(context); + + Assert.Equal(6, result.Count); + } + } + } + + private static class TestAlbumDataProvider + { + public static Album[] GetAlbums() + { + var genres = Enumerable.Range(1, 10).Select( + n => + new Genre + { + Name = "Genre Name " + n + }).ToArray(); + + var artists = Enumerable.Range(1, 10).Select( + n => + new Artist + { + Name = "Artist Name " + n + }).ToArray(); + + var albums = Enumerable.Range(1, 10).Select( + n => + new Album + { + Artist = artists[n - 1], Genre = genres[n - 1], Title = "Greatest Hits" + }).ToArray(); + + return albums; + } + } + + [ConditionalFact] + public async Task GenreMenuComponent_Returns_NineGenres() + { + using (var context = CreateContext()) + { + using (Fixture.BeginTransaction(context)) + { + var genreMenuComponent = new GenreMenuComponent(context); + + var genres = Enumerable.Range(1, 10).Select( + n => new Genre + { + Name = $"G{n}" + }); + + context.AddRange(genres); + context.SaveChanges(); + + var result = await genreMenuComponent.InvokeAsync(); + + Assert.Equal(9, result.Count); + } + } + } + + [ConditionalFact] + public async Task AddressAndPayment_RedirectToCompleteWhenSuccessful() + { + const string cartId = "CartId_A"; + + var order = CreateOrder(); + + var formCollection = new Dictionary + { + { + "PromoCode", new[] + { + "FREE" + } + } + }; + + using (var context = CreateContext()) + { + using (Fixture.BeginTransaction(context)) + { + var cartItems = CreateTestCartItems(cartId, itemPrice: 10, numberOfItems: 1); + context.AddRange(cartItems.Select(n => n.Album).Distinct()); + context.AddRange(cartItems); + context.SaveChanges(); + + var controller = new CheckoutController(formCollection); + + var result = await controller.AddressAndPayment(context, cartId, order); + + Assert.Equal(order.OrderId, result); + } + } + } + + [ConditionalFact] + public async Task AddressAndPayment_ReturnsOrderIfInvalidPromoCode() + { + const string cartId = "CartId_A"; + + using (var context = CreateContext()) + { + using (Fixture.BeginTransaction(context)) + { + var controller = new CheckoutController(); + var order = CreateOrder(); + + var result = await controller.AddressAndPayment(context, cartId, order); + + Assert.Null(result); + } + } + } + + protected Order CreateOrder(string userName = "RainbowDash") + => new Order + { + Username = userName, + FirstName = "Macavity", + LastName = "Clark", + Address = "11 Meadow Drive", + City = "Healing", + State = "IA", + PostalCode = "DN37 7RU", + Country = "USK", + Phone = "555 887876", + Email = "mc@sample.com" + }; + + [ConditionalFact] + public async Task Complete_ReturnsOrderIdIfValid() + { + using (var context = CreateContext()) + { + using (Fixture.BeginTransaction(context)) + { + var controller = new CheckoutController(); + + var order = context.Add(CreateOrder()).Entity; + context.SaveChanges(); + + var result = await controller.Complete(context, order.OrderId); + + Assert.Equal(order.OrderId, result); + } + } + } + + [ConditionalFact] + public async Task Complete_ReturnsErrorIfInvalidOrder() + { + using (var context = CreateContext()) + { + using (Fixture.BeginTransaction(context)) + { + var controller = new CheckoutController(); + + var result = await controller.Complete(context, -3333); + + Assert.Equal("Error", result); + } + } + } + + [ConditionalFact] + public async Task CartSummaryComponent_returns_items() + { + const string cartId = "CartId_A"; + const string albumTitle = "Good goat, M.A.A.D Village"; + const int itemCount = 10; + + using (var context = CreateContext()) + { + using (Fixture.BeginTransaction(context)) + { + var album = new Album + { + Title = albumTitle, + Artist = new Artist + { + Name = "Kung Fu Kenny" + }, + Genre = new Genre + { + Name = "Rap" + } + }; + + var cartItems = Enumerable.Range(1, itemCount).Select( + n => + new CartItem + { + Album = album, Count = 1, CartId = cartId + }).ToArray(); + + context.AddRange(cartItems); + context.SaveChanges(); + + var result = await new CartSummaryComponent(context, cartId).InvokeAsync(); + + Assert.Equal(itemCount, result.CartCount); + Assert.Equal(albumTitle, result.CartSummary); + } + } + } + [ConditionalFact] public void Music_store_project_to_mapped_entity() { @@ -29,10 +345,10 @@ public void Music_store_project_to_mapped_entity() 10, new Artist { - ArtistId = 1, Name = "Kung Fu Kenny" + Name = "Kung Fu Kenny" }, new Genre { - GenreId = 1, Name = "Rap" + Name = "Rap" }); context.Albums.AddRange(albums); @@ -70,25 +386,25 @@ join artist in context.Artists on album.ArtistId equals artist.ArtistId public async Task RemoveFromCart_removes_items_from_cart() { const string cartId = "CartId_A"; - const int cartItemId = 3; - const int numberOfItem = 5; + const int numberOfItems = 5; const int unitPrice = 10; using (var context = CreateContext()) { using (Fixture.BeginTransaction(context)) { - var cartItems = CreateTestCartItems(cartId, unitPrice, numberOfItem); + var cartItems = CreateTestCartItems(cartId, unitPrice, numberOfItems); context.AddRange(cartItems.Select(n => n.Album).Distinct()); context.AddRange(cartItems); context.SaveChanges(); var controller = new ShoppingCartController(context, cartId); + var cartItemId = cartItems[2].CartItemId; var viewModel = await controller.RemoveFromCart(cartItemId); - Assert.Equal(numberOfItem - 1, viewModel.CartCount); - Assert.Equal((numberOfItem - 1) * 10, viewModel.CartTotal); + Assert.Equal(numberOfItems - 1, viewModel.CartCount); + Assert.Equal((numberOfItems - 1) * 10, viewModel.CartTotal); Assert.Equal("Greatest Hits has been removed from your shopping cart.", viewModel.Message); var cart = ShoppingCart.GetCart(context, cartId); @@ -115,7 +431,7 @@ public async Task Cart_is_empty_when_no_items_have_been_added(string cartId) } } - [Fact] + [ConditionalFact] public async Task Cart_has_items_once_they_have_been_added() { const string cartId = "CartId_A"; @@ -127,7 +443,7 @@ public async Task Cart_has_items_once_they_have_been_added() var cartItems = CreateTestCartItems( cartId, itemPrice: 10, - numberOfItem: 5); + numberOfItems: 5); context.AddRange(cartItems.Select(n => n.Album).Distinct()); context.AddRange(cartItems); @@ -142,12 +458,10 @@ public async Task Cart_has_items_once_they_have_been_added() } } - [Fact] + [ConditionalFact] public async Task Can_add_items_to_cart() { const string cartId = "CartId_A"; - const int albumId = 3; - using (var context = CreateContext()) { @@ -157,16 +471,17 @@ public async Task Can_add_items_to_cart() 10, new Artist { - ArtistId = 1, Name = "Kung Fu Kenny" + Name = "Kung Fu Kenny" }, new Genre { - GenreId = 1, Name = "Rap" + Name = "Rap" }); context.AddRange(albums); context.SaveChanges(); var controller = new ShoppingCartController(context, cartId); + var albumId = albums[2].AlbumId; await controller.AddToCart(albumId); var cart = ShoppingCart.GetCart(context, cartId); @@ -176,23 +491,23 @@ public async Task Can_add_items_to_cart() } } - private static CartItem[] CreateTestCartItems(string cartId, decimal itemPrice, int numberOfItem) + private static CartItem[] CreateTestCartItems(string cartId, decimal itemPrice, int numberOfItems) { var albums = CreateTestAlbums( - itemPrice, new Artist + itemPrice, + new Artist { - ArtistId = 1, Name = "Kung Fu Kenny" + Name = "Kung Fu Kenny" }, new Genre { - GenreId = 1, Name = "Rap" + Name = "Rap" }); - var cartItems = Enumerable.Range(1, numberOfItem).Select( - n => - new CartItem() - { - Count = 1, CartId = cartId, AlbumId = n % albums.Length, Album = albums[n % albums.Length], - }).ToArray(); + var cartItems = Enumerable.Range(1, numberOfItems).Select( + n => new CartItem + { + Count = 1, CartId = cartId, Album = albums[n % albums.Length] + }).ToArray(); return cartItems; } @@ -203,14 +518,41 @@ private static Album[] CreateTestAlbums(decimal itemPrice, Artist artist, Genre n => new Album { - Title = "Greatest Hits", - AlbumId = n, - Price = itemPrice, - Artist = artist, - Genre = genre + Title = "Greatest Hits", Price = itemPrice, Artist = artist, Genre = genre }).ToArray(); } + protected class CartSummaryComponent + { + private readonly MusicStoreContext _context; + private readonly string _cartId; + + public CartSummaryComponent(MusicStoreContext context, string cartId) + { + _context = context; + _cartId = cartId; + } + + public async Task InvokeAsync() + { + var cartItems = await ShoppingCart.GetCart(_context, _cartId).GetCartItems(); + + var viewBag = new CartSummaryViewBag + { + CartCount = cartItems.Sum(c => c.Count), + CartSummary = string.Join("\n", cartItems.Select(c => c.Album.Title).Distinct()) + }; + + return viewBag; + } + } + + protected class CartSummaryViewBag + { + public int CartCount { get; set; } + public string CartSummary { get; set; } + } + protected class ShoppingCartController { private readonly MusicStoreContext _context; @@ -284,6 +626,134 @@ public async Task AddToCart(int id) } } + public class CheckoutController + { + private readonly Dictionary _formCollection; + private const string PromoCode = "FREE"; + + public CheckoutController(Dictionary formCollection = null) + { + _formCollection = formCollection ?? new Dictionary(); + } + + public async Task AddressAndPayment(MusicStoreContext context, string cartId, Order order) + { + try + { + if (!string.Equals( + _formCollection["PromoCode"].FirstOrDefault(), + PromoCode, + StringComparison.OrdinalIgnoreCase)) + { + return null; + } + + order.Username = "RainbowDash"; + order.OrderDate = DateTime.Now; + context.Orders.Add(order); + + var cart = ShoppingCart.GetCart(context, cartId); + await cart.CreateOrder(order); + await context.SaveChangesAsync(); + + return order.OrderId; + } + catch (Exception) + { + return null; + } + } + + public async Task Complete(MusicStoreContext context, int id) + { + var userName = "RainbowDash"; + + var isValid = await context.Orders.AnyAsync( + o => o.OrderId == id && + o.Username == userName); + + if (isValid) + { + return id; + } + + return "Error"; + } + } + + public class GenreMenuComponent + { + private readonly MusicStoreContext _context; + + public GenreMenuComponent(MusicStoreContext context) + { + _context = context; + } + + public async Task> InvokeAsync() + { + var genres = await _context.Genres.Select(g => g.Name).Take(9).ToListAsync(); + + return genres; + } + } + + public class HomeController + { + public async Task> Index(MusicStoreContext context) + { + var albums = await GetTopSellingAlbumsAsync(context, 6); + + return albums; + } + + private Task> GetTopSellingAlbumsAsync(MusicStoreContext dbContext, int count) + { + return dbContext.Albums + .OrderByDescending(a => a.OrderDetails.Count) + .Take(count) + .ToListAsync(); + } + } + + public class StoreController + { + private readonly MusicStoreContext _context; + + public StoreController(MusicStoreContext context) + { + _context = context; + } + + public async Task> Index() + { + var genres = await _context.Genres.ToListAsync(); + + return genres; + } + + public async Task Browse(string genre) + { + var genreModel = await _context.Genres + .Include(g => g.Albums) + .Where(g => g.Name == genre) + .FirstOrDefaultAsync(); + + return genreModel; + } + + public async Task Details(int id) + { + var album = await _context.Albums + .Where(a => a.AlbumId == id) + .Include(a => a.Artist) + .Include(a => a.Genre) + .FirstOrDefaultAsync(); + + return album; + } + } + protected TFixture Fixture { get; } protected MusicStoreContext CreateContext() => Fixture.CreateContext(); diff --git a/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityDbContext.cs b/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityDbContext.cs index 56018c3f808..d093b75d570 100644 --- a/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityDbContext.cs +++ b/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityDbContext.cs @@ -3,8 +3,7 @@ namespace Microsoft.EntityFrameworkCore.TestModels.AspNetIdentity { - public class IdentityDbContext : IdentityDbContext - where TUser : IdentityUser + public class IdentityDbContext : IdentityDbContext { public IdentityDbContext(DbContextOptions options) : base(options) diff --git a/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityDbContext`.cs b/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityDbContext`.cs index 29c37cee9e0..56018c3f808 100644 --- a/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityDbContext`.cs +++ b/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityDbContext`.cs @@ -1,14 +1,10 @@ // 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; - namespace Microsoft.EntityFrameworkCore.TestModels.AspNetIdentity { - public class IdentityDbContext : IdentityDbContext, IdentityUserRole, IdentityUserLogin, IdentityRoleClaim, IdentityUserToken> - where TUser : IdentityUser - where TRole : IdentityRole - where TKey : IEquatable + public class IdentityDbContext : IdentityDbContext + where TUser : IdentityUser { public IdentityDbContext(DbContextOptions options) : base(options) diff --git a/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityDbContext```.cs b/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityDbContext```.cs new file mode 100644 index 00000000000..32fcaed859e --- /dev/null +++ b/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityDbContext```.cs @@ -0,0 +1,23 @@ +// 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; + +namespace Microsoft.EntityFrameworkCore.TestModels.AspNetIdentity +{ + public class IdentityDbContext : IdentityDbContext, + IdentityUserRole, IdentityUserLogin, IdentityRoleClaim, IdentityUserToken> + where TUser : IdentityUser + where TRole : IdentityRole + where TKey : IEquatable + { + public IdentityDbContext(DbContextOptions options) + : base(options) + { + } + + protected IdentityDbContext() + { + } + } +} diff --git a/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityUserContext.cs b/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityUserContext.cs index dd44b7709af..2b851ecc00a 100644 --- a/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityUserContext.cs +++ b/test/EFCore.Specification.Tests/TestModels/AspNetIdentity/IdentityUserContext.cs @@ -39,11 +39,17 @@ public PersonalDataConverter(IPersonalDataProtector protector) } } + private class PersonalDataProtector : IPersonalDataProtector + { + public string Protect(string data) => data; + public string Unprotect(string data) => data; + } + protected override void OnModelCreating(ModelBuilder builder) { - var maxKeyLength = 0; - var encryptPersonalData = false; - PersonalDataConverter converter = null; + const int maxKeyLength = 128; + const bool encryptPersonalData = true; + var converter = new PersonalDataConverter(new PersonalDataProtector()); builder.Entity( b => @@ -60,7 +66,6 @@ protected override void OnModelCreating(ModelBuilder builder) if (encryptPersonalData) { - converter = new PersonalDataConverter(this.GetService()); var personalDataProps = typeof(TUser).GetProperties().Where( prop => Attribute.IsDefined(prop, typeof(ProtectedPersonalDataAttribute))); foreach (var p in personalDataProps) diff --git a/test/EFCore.Specification.Tests/TestModels/MusicStore/Album.cs b/test/EFCore.Specification.Tests/TestModels/MusicStore/Album.cs index cc151d9b6fc..1d3a4dc2cc2 100644 --- a/test/EFCore.Specification.Tests/TestModels/MusicStore/Album.cs +++ b/test/EFCore.Specification.Tests/TestModels/MusicStore/Album.cs @@ -11,7 +11,6 @@ namespace Microsoft.EntityFrameworkCore.TestModels.MusicStore public class Album { [ScaffoldColumn(false)] - [DatabaseGenerated(DatabaseGeneratedOption.None)] public int AlbumId { get; set; } public int GenreId { get; set; } diff --git a/test/EFCore.Specification.Tests/TestModels/MusicStore/Artist.cs b/test/EFCore.Specification.Tests/TestModels/MusicStore/Artist.cs index 4ace89b5acd..c29a59c088d 100644 --- a/test/EFCore.Specification.Tests/TestModels/MusicStore/Artist.cs +++ b/test/EFCore.Specification.Tests/TestModels/MusicStore/Artist.cs @@ -2,13 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; namespace Microsoft.EntityFrameworkCore.TestModels.MusicStore { public class Artist { - [DatabaseGenerated(DatabaseGeneratedOption.None)] public int ArtistId { get; set; } [Required] diff --git a/test/EFCore.Specification.Tests/TestModels/MusicStore/Genre.cs b/test/EFCore.Specification.Tests/TestModels/MusicStore/Genre.cs index 7653cc96321..9aa71ea3f8d 100644 --- a/test/EFCore.Specification.Tests/TestModels/MusicStore/Genre.cs +++ b/test/EFCore.Specification.Tests/TestModels/MusicStore/Genre.cs @@ -3,13 +3,11 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; namespace Microsoft.EntityFrameworkCore.TestModels.MusicStore { public class Genre { - [DatabaseGenerated(DatabaseGeneratedOption.None)] public int GenreId { get; set; } [Required] diff --git a/test/EFCore.Specification.Tests/TestModels/MusicStore/Order.cs b/test/EFCore.Specification.Tests/TestModels/MusicStore/Order.cs index 44f93e5da3b..2e4052cb48d 100644 --- a/test/EFCore.Specification.Tests/TestModels/MusicStore/Order.cs +++ b/test/EFCore.Specification.Tests/TestModels/MusicStore/Order.cs @@ -11,7 +11,6 @@ namespace Microsoft.EntityFrameworkCore.TestModels.MusicStore public class Order { [ScaffoldColumn(false)] - [DatabaseGenerated(DatabaseGeneratedOption.None)] public int OrderId { get; set; } [ScaffoldColumn(false)] diff --git a/test/EFCore.SqlServer.FunctionalTests/MigrationsSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/MigrationsSqlServerTest.cs index 3b7e2496baa..fd32d99b28b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/MigrationsSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/MigrationsSqlServerTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Data.Common; using System.Threading.Tasks; +using Identity30.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Internal; @@ -12,6 +13,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal; using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.TestModels.AspNetIdentity; using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; @@ -500,14 +502,7 @@ public override void Can_diff_against_2_2_model() { using (var context = new ModelSnapshot22.BloggingContext()) { - var snapshot = new BloggingContextModelSnapshot22(); - var sourceModel = snapshot.Model; - var targetModel = context.Model; - - var modelDiffer = context.GetService(); - var operations = modelDiffer.GetDifferences(sourceModel, targetModel); - - Assert.Equal(0, operations.Count); + DiffSnapshot(new BloggingContextModelSnapshot22(), context); } } @@ -521,46 +516,778 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - modelBuilder.Entity("ModelSnapshot22.Blog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + modelBuilder.Entity( + "ModelSnapshot22.Blog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("Name"); + b.Property("Name"); - b.HasKey("Id"); + b.HasKey("Id"); - b.ToTable("Blogs"); - }); + b.ToTable("Blogs"); + }); - modelBuilder.Entity("ModelSnapshot22.Post", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + modelBuilder.Entity( + "ModelSnapshot22.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("BlogId"); + b.Property("BlogId"); - b.Property("Content"); + b.Property("Content"); - b.Property("EditDate"); + b.Property("EditDate"); - b.Property("Title"); + b.Property("Title"); - b.HasKey("Id"); + b.HasKey("Id"); - b.HasIndex("BlogId"); + b.HasIndex("BlogId"); - b.ToTable("Post"); - }); + b.ToTable("Post"); + }); - modelBuilder.Entity("ModelSnapshot22.Post", b => - { - b.HasOne("ModelSnapshot22.Blog", "Blog") - .WithMany("Posts") - .HasForeignKey("BlogId"); - }); + modelBuilder.Entity( + "ModelSnapshot22.Post", b => + { + b.HasOne("ModelSnapshot22.Blog", "Blog") + .WithMany("Posts") + .HasForeignKey("BlogId"); + }); +#pragma warning restore 612, 618 + } + } + + public override void Can_diff_against_2_1_ASP_NET_Identity_model() + { + using (var context = new ApplicationDbContext()) + { + DiffSnapshot(new AspNetIdentity21ModelSnapshot(), context); + } + } + + public class AspNetIdentity21ModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Name") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("RoleId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed"); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash"); + + b.Property("PhoneNumber"); + + b.Property("PhoneNumberConfirmed"); + + b.Property("SecurityStamp"); + + b.Property("TwoFactorEnabled"); + + b.Property("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasMaxLength(128); + + b.Property("ProviderDisplayName"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(128); + + b.Property("Name") + .HasMaxLength(128); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } + + public override void Can_diff_against_2_2_ASP_NET_Identity_model() + { + using (var context = new ApplicationDbContext()) + { + DiffSnapshot(new AspNetIdentity22ModelSnapshot(), context); + } + } + + public class AspNetIdentity22ModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.0-preview1") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Name") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("RoleId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed"); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash"); + + b.Property("PhoneNumber"); + + b.Property("PhoneNumberConfirmed"); + + b.Property("SecurityStamp"); + + b.Property("TwoFactorEnabled"); + + b.Property("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasMaxLength(128); + + b.Property("ProviderDisplayName"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(128); + + b.Property("Name") + .HasMaxLength(128); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } + + public override void Can_diff_against_3_0_ASP_NET_Identity_model() + { + using (var context = new ApplicationDbContext()) + { + DiffSnapshot(new AspNetIdentity30ModelSnapshot(), context); + } + } + + public class AspNetIdentity30ModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.0-preview1") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Name") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("RoleId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed"); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash"); + + b.Property("PhoneNumber"); + + b.Property("PhoneNumberConfirmed"); + + b.Property("SecurityStamp"); + + b.Property("TwoFactorEnabled"); + + b.Property("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasMaxLength(128); + + b.Property("ProviderDisplayName"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(128); + + b.Property("Name") + .HasMaxLength(128); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity( + "Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); #pragma warning restore 612, 618 } } @@ -595,3 +1322,62 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) public DbSet Blogs { get; set; } } } + +namespace Identity30.Data +{ + public class ApplicationDbContext : IdentityDbContext + { + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0"); + + protected override void OnModelCreating(ModelBuilder builder) + { + base.OnModelCreating(builder); + + builder.Entity( + b => + { + b.HasIndex(u => u.NormalizedUserName).HasName("UserNameIndex").IsUnique(); + b.HasIndex(u => u.NormalizedEmail).HasName("EmailIndex"); + b.ToTable("AspNetUsers"); + }); + + builder.Entity>( + b => + { + b.ToTable("AspNetUserClaims"); + }); + + builder.Entity>( + b => + { + b.ToTable("AspNetUserLogins"); + }); + + builder.Entity>( + b => + { + b.ToTable("AspNetUserTokens"); + }); + + builder.Entity( + b => + { + b.HasIndex(r => r.NormalizedName).HasName("RoleNameIndex").IsUnique(); + b.ToTable("AspNetRoles"); + }); + + builder.Entity>( + b => + { + b.ToTable("AspNetRoleClaims"); + }); + + builder.Entity>( + b => + { + b.ToTable("AspNetUserRoles"); + }); + } + } +} diff --git a/test/EFCore.Sqlite.FunctionalTests/MigrationsSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/MigrationsSqliteTest.cs index 517cb6b6560..24c9f6a3a86 100644 --- a/test/EFCore.Sqlite.FunctionalTests/MigrationsSqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/MigrationsSqliteTest.cs @@ -4,11 +4,13 @@ using System; using System.Collections.Generic; using System.Data.Common; +using Identity30.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; +using Microsoft.EntityFrameworkCore.TestModels.AspNetIdentity; using Xunit; namespace Microsoft.EntityFrameworkCore @@ -305,14 +307,7 @@ public override void Can_diff_against_2_2_model() { using (var context = new ModelSnapshot22.BloggingContext()) { - var snapshot = new BloggingContextModelSnapshot22(); - var sourceModel = snapshot.Model; - var targetModel = context.Model; - - var modelDiffer = context.GetService(); - var operations = modelDiffer.GetDifferences(sourceModel, targetModel); - - Assert.Equal(0, operations.Count); + DiffSnapshot(new BloggingContextModelSnapshot22(), context); } } @@ -368,6 +363,681 @@ protected override void BuildModel(ModelBuilder modelBuilder) #pragma warning restore 612, 618 } } + + public class AspNetIdentity21ModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.0"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Name") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("RoleId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed"); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash"); + + b.Property("PhoneNumber"); + + b.Property("PhoneNumberConfirmed"); + + b.Property("SecurityStamp"); + + b.Property("TwoFactorEnabled"); + + b.Property("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasMaxLength(128); + + b.Property("ProviderDisplayName"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(128); + + b.Property("Name") + .HasMaxLength(128); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } + + public override void Can_diff_against_2_1_ASP_NET_Identity_model() + { + using (var context = new ApplicationDbContext()) + { + DiffSnapshot(new AspNetIdentity21ModelSnapshot(), context); + } + } + + public class AspNetIdentity22ModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.0-preview1"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Name") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("RoleId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed"); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash"); + + b.Property("PhoneNumber"); + + b.Property("PhoneNumberConfirmed"); + + b.Property("SecurityStamp"); + + b.Property("TwoFactorEnabled"); + + b.Property("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasMaxLength(128); + + b.Property("ProviderDisplayName"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(128); + + b.Property("Name") + .HasMaxLength(128); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } + + public override void Can_diff_against_2_2_ASP_NET_Identity_model() + { + using (var context = new ApplicationDbContext()) + { + DiffSnapshot(new AspNetIdentity22ModelSnapshot(), context); + } + } + + public class AspNetIdentity30ModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.0-preview1"); // This came from 3.0 preview 6 + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Name") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("RoleId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed"); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash"); + + b.Property("PhoneNumber"); + + b.Property("PhoneNumberConfirmed"); + + b.Property("SecurityStamp"); + + b.Property("TwoFactorEnabled"); + + b.Property("UserName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasMaxLength(128); + + b.Property("ProviderDisplayName"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider") + .HasMaxLength(128); + + b.Property("Name") + .HasMaxLength(128); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } + + public override void Can_diff_against_3_0_ASP_NET_Identity_model() + { + using (var context = new ApplicationDbContext()) + { + DiffSnapshot(new AspNetIdentity30ModelSnapshot(), context); + } + } } } @@ -400,3 +1070,61 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) } } +namespace Identity30.Data +{ + public class ApplicationDbContext : IdentityDbContext + { + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseSqlite("DataSource=Test.db"); + + protected override void OnModelCreating(ModelBuilder builder) + { + base.OnModelCreating(builder); + + builder.Entity( + b => + { + b.HasIndex(u => u.NormalizedUserName).HasName("UserNameIndex").IsUnique(); + b.HasIndex(u => u.NormalizedEmail).HasName("EmailIndex"); + b.ToTable("AspNetUsers"); + }); + + builder.Entity>( + b => + { + b.ToTable("AspNetUserClaims"); + }); + + builder.Entity>( + b => + { + b.ToTable("AspNetUserLogins"); + }); + + builder.Entity>( + b => + { + b.ToTable("AspNetUserTokens"); + }); + + builder.Entity( + b => + { + b.HasIndex(r => r.NormalizedName).HasName("RoleNameIndex").IsUnique(); + b.ToTable("AspNetRoles"); + }); + + builder.Entity>( + b => + { + b.ToTable("AspNetRoleClaims"); + }); + + builder.Entity>( + b => + { + b.ToTable("AspNetUserRoles"); + }); + } + } +}