From 2bb3a74fa2cb18a30aea366202ace3bb1a510bd9 Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Wed, 21 Jul 2021 12:47:21 +0200 Subject: [PATCH 01/15] Make GettingStarted the default Startup project --- JsonApiDotNetCore.sln | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/JsonApiDotNetCore.sln b/JsonApiDotNetCore.sln index 3d697e1ee5..3d1fcaa179 100644 --- a/JsonApiDotNetCore.sln +++ b/JsonApiDotNetCore.sln @@ -18,6 +18,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{02 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{076E1AE4-FD25-4684-B826-CAAE37FEA0AA}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GettingStarted", "src\Examples\GettingStarted\GettingStarted.csproj", "{067FFD7A-C66B-473D-8471-37F5C95DF61C}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonApiDotNetCoreExampleTests", "test\JsonApiDotNetCoreExampleTests\JsonApiDotNetCoreExampleTests.csproj", "{CAF331F8-9255-4D72-A1A8-A54141E99F1E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NoEntityFrameworkTests", "test\NoEntityFrameworkTests\NoEntityFrameworkTests.csproj", "{4F15A8F8-5BC6-45A1-BC51-03F921B726A4}" @@ -36,8 +38,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReportsExample", "src\Examp EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonApiDotNetCore", "src\JsonApiDotNetCore\JsonApiDotNetCore.csproj", "{21D27239-138D-4604-8E49-DCBE41BCE4C8}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GettingStarted", "src\Examples\GettingStarted\GettingStarted.csproj", "{067FFD7A-C66B-473D-8471-37F5C95DF61C}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MultiDbContextExample", "src\Examples\MultiDbContextExample\MultiDbContextExample.csproj", "{6CAFDDBE-00AB-4784-801B-AB419C3C3A26}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MultiDbContextTests", "test\MultiDbContextTests\MultiDbContextTests.csproj", "{EC3202C6-1D4C-4B14-A599-B9D3F27FE3BA}" From bd23e45689da70735f513c33483cd17407968551 Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Wed, 21 Jul 2021 12:50:24 +0200 Subject: [PATCH 02/15] Use native many-to-many in Example project --- .../JsonApiDotNetCoreExample/Data/AppDbContext.cs | 7 ------- .../JsonApiDotNetCoreExample/Models/Tag.cs | 4 ++++ .../JsonApiDotNetCoreExample/Models/TodoItem.cs | 6 +----- .../JsonApiDotNetCoreExample/Models/TodoItemTag.cs | 14 -------------- 4 files changed, 5 insertions(+), 26 deletions(-) delete mode 100644 src/Examples/JsonApiDotNetCoreExample/Models/TodoItemTag.cs diff --git a/src/Examples/JsonApiDotNetCoreExample/Data/AppDbContext.cs b/src/Examples/JsonApiDotNetCoreExample/Data/AppDbContext.cs index 9cb18cf548..cc59628fc6 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Data/AppDbContext.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Data/AppDbContext.cs @@ -18,13 +18,6 @@ public AppDbContext(DbContextOptions options) protected override void OnModelCreating(ModelBuilder builder) { - builder.Entity() - .HasKey(todoItemTag => new - { - todoItemTag.TodoItemId, - todoItemTag.TagId - }); - // When deleting a person, un-assign him/her from existing todo items. builder.Entity() .HasMany(person => person.AssignedTodoItems) diff --git a/src/Examples/JsonApiDotNetCoreExample/Models/Tag.cs b/src/Examples/JsonApiDotNetCoreExample/Models/Tag.cs index cd6e73552f..e0f5d0894c 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Models/Tag.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Models/Tag.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using JetBrains.Annotations; using JsonApiDotNetCore.Resources; @@ -12,5 +13,8 @@ public sealed class Tag : Identifiable [MinLength(1)] [Attr] public string Name { get; set; } + + [HasMany] + public ISet TodoItems { get; set; } } } diff --git a/src/Examples/JsonApiDotNetCoreExample/Models/TodoItem.cs b/src/Examples/JsonApiDotNetCoreExample/Models/TodoItem.cs index 95643e61a3..dbc0c59a04 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Models/TodoItem.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Models/TodoItem.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; using JetBrains.Annotations; using JsonApiDotNetCore.Resources; using JsonApiDotNetCore.Resources.Annotations; @@ -28,10 +27,7 @@ public sealed class TodoItem : Identifiable [HasOne] public Person Assignee { get; set; } - [NotMapped] - [HasManyThrough(nameof(TodoItemTags))] + [HasMany] public ISet Tags { get; set; } - - public ISet TodoItemTags { get; set; } } } diff --git a/src/Examples/JsonApiDotNetCoreExample/Models/TodoItemTag.cs b/src/Examples/JsonApiDotNetCoreExample/Models/TodoItemTag.cs deleted file mode 100644 index 8d1ef42d42..0000000000 --- a/src/Examples/JsonApiDotNetCoreExample/Models/TodoItemTag.cs +++ /dev/null @@ -1,14 +0,0 @@ -using JetBrains.Annotations; - -namespace JsonApiDotNetCoreExample.Models -{ - [UsedImplicitly(ImplicitUseTargetFlags.Members)] - public sealed class TodoItemTag - { - public int TodoItemId { get; set; } - public TodoItem TodoItem { get; set; } - - public int TagId { get; set; } - public Tag Tag { get; set; } - } -} From 533b324b46a5b6b92747f2aabebb499049f4c7f9 Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Fri, 23 Jul 2021 14:07:19 +0200 Subject: [PATCH 03/15] Updated WorkItem.Tags relationship in IntegrationTests to use native many-to-many --- .../InverseNavigationResolver.cs | 25 +++-- .../Resources/Annotations/HasManyAttribute.cs | 18 ++++ .../Annotations/HasManyThroughAttribute.cs | 5 + .../Services/JsonApiResourceService.cs | 10 +- .../ReadWrite/Creating/CreateResourceTests.cs | 7 +- ...eateResourceWithToManyRelationshipTests.cs | 31 +++--- .../ReadWrite/Deleting/DeleteResourceTests.cs | 24 ++--- .../Fetching/FetchRelationshipTests.cs | 30 ++---- .../ReadWrite/Fetching/FetchResourceTests.cs | 41 +++----- .../ReadWrite/ReadWriteDbContext.cs | 8 -- .../AddToToManyRelationshipTests.cs | 65 ++++--------- .../RemoveFromToManyRelationshipTests.cs | 48 +++------- .../ReplaceToManyRelationshipTests.cs | 78 ++++----------- .../ReplaceToManyRelationshipTests.cs | 95 +++++-------------- .../Updating/Resources/UpdateResourceTests.cs | 31 ++---- .../IntegrationTests/ReadWrite/WorkItem.cs | 5 +- .../IntegrationTests/ReadWrite/WorkItemTag.cs | 14 --- .../IntegrationTests/ReadWrite/WorkTag.cs | 4 + 18 files changed, 189 insertions(+), 350 deletions(-) delete mode 100644 test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItemTag.cs diff --git a/src/JsonApiDotNetCore/Configuration/InverseNavigationResolver.cs b/src/JsonApiDotNetCore/Configuration/InverseNavigationResolver.cs index 749abfde2d..83bb3f02b8 100644 --- a/src/JsonApiDotNetCore/Configuration/InverseNavigationResolver.cs +++ b/src/JsonApiDotNetCore/Configuration/InverseNavigationResolver.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using JetBrains.Annotations; using JsonApiDotNetCore.Repositories; using JsonApiDotNetCore.Resources.Annotations; @@ -35,25 +36,37 @@ public void Resolve() private void Resolve(DbContext dbContext) { - foreach (ResourceContext resourceContext in _resourceContextProvider.GetResourceContexts()) + foreach (ResourceContext resourceContext in _resourceContextProvider.GetResourceContexts().Where(context => context.Relationships.Any())) { IEntityType entityType = dbContext.Model.FindEntityType(resourceContext.ResourceType); if (entityType != null) { - ResolveRelationships(resourceContext.Relationships, entityType); + IDictionary navigationMap = GetNavigations(entityType); + ResolveRelationships(resourceContext.Relationships, navigationMap); } } } - private void ResolveRelationships(IReadOnlyCollection relationships, IEntityType entityType) + private static IDictionary GetNavigations(IEntityType entityType) + { + // @formatter:wrap_chained_method_calls chop_always + + return entityType.GetNavigations() + .Cast() + .Concat(entityType.GetSkipNavigations()) + .ToDictionary(navigation => navigation.Name); + + // @formatter:wrap_chained_method_calls restore + } + + private void ResolveRelationships(IReadOnlyCollection relationships, IDictionary navigationMap) { foreach (RelationshipAttribute relationship in relationships) { - if (!(relationship is HasManyThroughAttribute)) + if (navigationMap.TryGetValue(relationship.Property.Name, out INavigationBase navigation)) { - INavigation inverseNavigation = entityType.FindNavigation(relationship.Property.Name)?.Inverse; - relationship.InverseNavigationProperty = inverseNavigation?.PropertyInfo; + relationship.InverseNavigationProperty = navigation.Inverse?.PropertyInfo; } } } diff --git a/src/JsonApiDotNetCore/Resources/Annotations/HasManyAttribute.cs b/src/JsonApiDotNetCore/Resources/Annotations/HasManyAttribute.cs index 3a8b3bc16a..abe6b361a9 100644 --- a/src/JsonApiDotNetCore/Resources/Annotations/HasManyAttribute.cs +++ b/src/JsonApiDotNetCore/Resources/Annotations/HasManyAttribute.cs @@ -18,5 +18,23 @@ namespace JsonApiDotNetCore.Resources.Annotations [AttributeUsage(AttributeTargets.Property)] public class HasManyAttribute : RelationshipAttribute { + private static readonly CollectionConverter CollectionConverter = new(); + + /// + /// Inspects to determine if this is a many-to-many relationship. + /// + public virtual bool IsManyToMany + { + get + { + if (InverseNavigationProperty != null) + { + Type elementType = CollectionConverter.TryGetCollectionElementType(InverseNavigationProperty.PropertyType); + return elementType != null; + } + + return false; + } + } } } diff --git a/src/JsonApiDotNetCore/Resources/Annotations/HasManyThroughAttribute.cs b/src/JsonApiDotNetCore/Resources/Annotations/HasManyThroughAttribute.cs index 1ad1a86379..b76652d6ca 100644 --- a/src/JsonApiDotNetCore/Resources/Annotations/HasManyThroughAttribute.cs +++ b/src/JsonApiDotNetCore/Resources/Annotations/HasManyThroughAttribute.cs @@ -47,6 +47,11 @@ public sealed class HasManyThroughAttribute : HasManyAttribute { private static readonly CollectionConverter CollectionConverter = new(); + /// + /// Always returns true. + /// + public override bool IsManyToMany => true; + /// /// The name of the join property on the parent resource. In the example described above, this would be "ArticleTags". /// diff --git a/src/JsonApiDotNetCore/Services/JsonApiResourceService.cs b/src/JsonApiDotNetCore/Services/JsonApiResourceService.cs index 5a8c4efe91..92064666dc 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiResourceService.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiResourceService.cs @@ -257,11 +257,11 @@ public virtual async Task AddToToManyRelationshipAsync(TId primaryId, string rel AssertHasRelationship(_request.Relationship, relationshipName); - if (secondaryResourceIds.Any() && _request.Relationship is HasManyThroughAttribute hasManyThrough) + if (secondaryResourceIds.Any() && _request.Relationship is HasManyAttribute { IsManyToMany: true } manyToManyRelationship) { // In the case of a many-to-many relationship, creating a duplicate entry in the join table results in a // unique constraint violation. We avoid that by excluding already-existing entries from the set in advance. - await RemoveExistingIdsFromSecondarySetAsync(primaryId, secondaryResourceIds, hasManyThrough, cancellationToken); + await RemoveExistingIdsFromSecondarySetAsync(primaryId, secondaryResourceIds, manyToManyRelationship, cancellationToken); } try @@ -276,10 +276,10 @@ public virtual async Task AddToToManyRelationshipAsync(TId primaryId, string rel } } - private async Task RemoveExistingIdsFromSecondarySetAsync(TId primaryId, ISet secondaryResourceIds, - HasManyThroughAttribute hasManyThrough, CancellationToken cancellationToken) + private async Task RemoveExistingIdsFromSecondarySetAsync(TId primaryId, ISet secondaryResourceIds, HasManyAttribute hasManyRelationship, + CancellationToken cancellationToken) { - QueryLayer queryLayer = _queryLayerComposer.ComposeForHasMany(hasManyThrough, primaryId, secondaryResourceIds); + QueryLayer queryLayer = _queryLayerComposer.ComposeForHasMany(hasManyRelationship, primaryId, secondaryResourceIds); IReadOnlyCollection primaryResources = await _repositoryAccessor.GetAsync(queryLayer, cancellationToken); TResource primaryResource = primaryResources.FirstOrDefault(); diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Creating/CreateResourceTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Creating/CreateResourceTests.cs index 053c8c1516..ffcfabadcd 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Creating/CreateResourceTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Creating/CreateResourceTests.cs @@ -714,8 +714,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => WorkItem workItemInDatabase = await dbContext.WorkItems .Include(workItem => workItem.Assignee) .Include(workItem => workItem.Subscribers) - .Include(workItem => workItem.WorkItemTags) - .ThenInclude(workItemTag => workItemTag.Tag) + .Include(workItem => workItem.Tags) .FirstWithIdAsync(newWorkItemId); // @formatter:keep_existing_linebreaks restore @@ -729,8 +728,8 @@ await _testContext.RunOnDatabaseAsync(async dbContext => workItemInDatabase.Subscribers.Should().HaveCount(1); workItemInDatabase.Subscribers.Single().Id.Should().Be(existingUserAccounts[1].Id); - workItemInDatabase.WorkItemTags.Should().HaveCount(1); - workItemInDatabase.WorkItemTags.Single().Tag.Id.Should().Be(existingTag.Id); + workItemInDatabase.Tags.Should().HaveCount(1); + workItemInDatabase.Tags.Single().Id.Should().Be(existingTag.Id); }); } } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToManyRelationshipTests.cs index 1c5148f227..815df90212 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Creating/CreateResourceWithToManyRelationshipTests.cs @@ -27,7 +27,7 @@ public CreateResourceWithToManyRelationshipTests(ExampleIntegrationTestContext existingUserAccounts = _fakers.UserAccount.Generate(2); @@ -91,7 +91,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_create_HasMany_relationship_with_include() + public async Task Can_create_OneToMany_relationship_with_include() { // Arrange List existingUserAccounts = _fakers.UserAccount.Generate(2); @@ -162,7 +162,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_create_HasMany_relationship_with_include_and_secondary_fieldset() + public async Task Can_create_OneToMany_relationship_with_include_and_secondary_fieldset() { // Arrange List existingUserAccounts = _fakers.UserAccount.Generate(2); @@ -233,7 +233,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_create_HasManyThrough_relationship_with_include_and_fieldsets() + public async Task Can_create_ManyToMany_relationship_with_include_and_fieldsets() { // Arrange List existingTags = _fakers.WorkTag.Generate(3); @@ -312,21 +312,12 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true + WorkItem workItemInDatabase = await dbContext.WorkItems.Include(workItem => workItem.Tags).FirstWithIdAsync(newWorkItemId); - WorkItem workItemInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.WorkItemTags) - .ThenInclude(workItemTag => workItemTag.Tag) - .FirstWithIdAsync(newWorkItemId); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore - - workItemInDatabase.WorkItemTags.Should().HaveCount(3); - workItemInDatabase.WorkItemTags.Should().ContainSingle(workItemTag => workItemTag.Tag.Id == existingTags[0].Id); - workItemInDatabase.WorkItemTags.Should().ContainSingle(workItemTag => workItemTag.Tag.Id == existingTags[1].Id); - workItemInDatabase.WorkItemTags.Should().ContainSingle(workItemTag => workItemTag.Tag.Id == existingTags[2].Id); + workItemInDatabase.Tags.Should().HaveCount(3); + workItemInDatabase.Tags.Should().ContainSingle(workTag => workTag.Id == existingTags[0].Id); + workItemInDatabase.Tags.Should().ContainSingle(workTag => workTag.Id == existingTags[1].Id); + workItemInDatabase.Tags.Should().ContainSingle(workTag => workTag.Id == existingTags[2].Id); }); } @@ -615,7 +606,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_create_with_null_data_in_HasMany_relationship() + public async Task Cannot_create_with_null_data_in_OneToMany_relationship() { // Arrange var requestBody = new @@ -650,7 +641,7 @@ public async Task Cannot_create_with_null_data_in_HasMany_relationship() } [Fact] - public async Task Cannot_create_with_null_data_in_HasManyThrough_relationship() + public async Task Cannot_create_with_null_data_in_ManyToMany_relationship() { // Arrange var requestBody = new diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Deleting/DeleteResourceTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Deleting/DeleteResourceTests.cs index 2b9f8dd4d1..b24769210f 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Deleting/DeleteResourceTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Deleting/DeleteResourceTests.cs @@ -148,7 +148,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_delete_existing_resource_with_HasMany_relationship() + public async Task Can_delete_existing_resource_with_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -184,22 +184,19 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_delete_resource_with_HasManyThrough_relationship() + public async Task Can_delete_resource_with_ManyToMany_relationship() { // Arrange - var existingWorkItemTag = new WorkItemTag - { - Item = _fakers.WorkItem.Generate(), - Tag = _fakers.WorkTag.Generate() - }; + WorkItem existingWorkItem = _fakers.WorkItem.Generate(); + existingWorkItem.Tags = _fakers.WorkTag.Generate(1).ToHashSet(); await _testContext.RunOnDatabaseAsync(async dbContext => { - dbContext.WorkItemTags.Add(existingWorkItemTag); + dbContext.WorkItems.Add(existingWorkItem); await dbContext.SaveChangesAsync(); }); - string route = "/workItems/" + existingWorkItemTag.Item.StringId; + string route = "/workItems/" + existingWorkItem.StringId; // Act (HttpResponseMessage httpResponse, string responseDocument) = await _testContext.ExecuteDeleteAsync(route); @@ -211,14 +208,13 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - WorkItem workItemsInDatabase = await dbContext.WorkItems.FirstWithIdOrDefaultAsync(existingWorkItemTag.Item.Id); + WorkItem workItemInDatabase = await dbContext.WorkItems.FirstWithIdOrDefaultAsync(existingWorkItem.Id); - workItemsInDatabase.Should().BeNull(); + workItemInDatabase.Should().BeNull(); - WorkItemTag workItemTagsInDatabase = - await dbContext.WorkItemTags.FirstOrDefaultAsync(workItemTag => workItemTag.Item.Id == existingWorkItemTag.Item.Id); + WorkTag tagInDatabase = await dbContext.WorkTags.FirstWithIdOrDefaultAsync(existingWorkItem.Tags.ElementAt(0).Id); - workItemTagsInDatabase.Should().BeNull(); + tagInDatabase.Should().NotBeNull(); }); } } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Fetching/FetchRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Fetching/FetchRelationshipTests.cs index d1be21eec1..3a8796ae96 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Fetching/FetchRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Fetching/FetchRelationshipTests.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; @@ -25,7 +24,7 @@ public FetchRelationshipTests(ExampleIntegrationTestContext } [Fact] - public async Task Can_get_empty_HasOne_relationship() + public async Task Can_get_empty_ManyToOne_relationship() { WorkItem workItem = _fakers.WorkItem.Generate(); @@ -74,7 +73,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_get_HasMany_relationship() + public async Task Can_get_OneToMany_relationship() { // Arrange UserAccount userAccount = _fakers.UserAccount.Generate(); @@ -108,7 +107,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_get_empty_HasMany_relationship() + public async Task Can_get_empty_OneToMany_relationship() { // Arrange UserAccount userAccount = _fakers.UserAccount.Generate(); @@ -131,22 +130,11 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_get_HasManyThrough_relationship() + public async Task Can_get_ManyToMany_relationship() { // Arrange WorkItem workItem = _fakers.WorkItem.Generate(); - - workItem.WorkItemTags = new List - { - new() - { - Tag = _fakers.WorkTag.Generate() - }, - new() - { - Tag = _fakers.WorkTag.Generate() - } - }; + workItem.Tags = _fakers.WorkTag.Generate(2).ToHashSet(); await _testContext.RunOnDatabaseAsync(async dbContext => { @@ -164,19 +152,19 @@ await _testContext.RunOnDatabaseAsync(async dbContext => responseDocument.ManyData.Should().HaveCount(2); - ResourceObject item1 = responseDocument.ManyData.Single(resource => resource.Id == workItem.WorkItemTags.ElementAt(0).Tag.StringId); + ResourceObject item1 = responseDocument.ManyData.Single(resource => resource.Id == workItem.Tags.ElementAt(0).StringId); item1.Type.Should().Be("workTags"); item1.Attributes.Should().BeNull(); item1.Relationships.Should().BeNull(); - ResourceObject item2 = responseDocument.ManyData.Single(resource => resource.Id == workItem.WorkItemTags.ElementAt(1).Tag.StringId); + ResourceObject item2 = responseDocument.ManyData.Single(resource => resource.Id == workItem.Tags.ElementAt(1).StringId); item2.Type.Should().Be("workTags"); item2.Attributes.Should().BeNull(); item2.Relationships.Should().BeNull(); } [Fact] - public async Task Can_get_empty_HasManyThrough_relationship() + public async Task Can_get_empty_ManyToMany_relationship() { // Arrange WorkItem workItem = _fakers.WorkItem.Generate(); diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Fetching/FetchResourceTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Fetching/FetchResourceTests.cs index 94f8db25e7..de22ee8844 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Fetching/FetchResourceTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Fetching/FetchResourceTests.cs @@ -142,7 +142,7 @@ public async Task Cannot_get_primary_resource_for_unknown_ID() } [Fact] - public async Task Can_get_secondary_HasOne_resource() + public async Task Can_get_secondary_ManyToOne_resource() { // Arrange WorkItem workItem = _fakers.WorkItem.Generate(); @@ -171,7 +171,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_get_unknown_secondary_HasOne_resource() + public async Task Can_get_unknown_secondary_ManyToOne_resource() { // Arrange WorkItem workItem = _fakers.WorkItem.Generate(); @@ -194,7 +194,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_get_secondary_HasMany_resources() + public async Task Can_get_secondary_OneToMany_resources() { // Arrange UserAccount userAccount = _fakers.UserAccount.Generate(); @@ -232,7 +232,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_get_unknown_secondary_HasMany_resource() + public async Task Can_get_unknown_secondary_OneToMany_resource() { // Arrange UserAccount userAccount = _fakers.UserAccount.Generate(); @@ -255,22 +255,11 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_get_secondary_HasManyThrough_resources() + public async Task Can_get_secondary_ManyToMany_resources() { // Arrange WorkItem workItem = _fakers.WorkItem.Generate(); - - workItem.WorkItemTags = new List - { - new() - { - Tag = _fakers.WorkTag.Generate() - }, - new() - { - Tag = _fakers.WorkTag.Generate() - } - }; + workItem.Tags = _fakers.WorkTag.Generate(2).ToHashSet(); await _testContext.RunOnDatabaseAsync(async dbContext => { @@ -288,21 +277,21 @@ await _testContext.RunOnDatabaseAsync(async dbContext => responseDocument.ManyData.Should().HaveCount(2); - ResourceObject item1 = responseDocument.ManyData.Single(resource => resource.Id == workItem.WorkItemTags.ElementAt(0).Tag.StringId); + ResourceObject item1 = responseDocument.ManyData.Single(resource => resource.Id == workItem.Tags.ElementAt(0).StringId); item1.Type.Should().Be("workTags"); - item1.Attributes["text"].Should().Be(workItem.WorkItemTags.ElementAt(0).Tag.Text); - item1.Attributes["isBuiltIn"].Should().Be(workItem.WorkItemTags.ElementAt(0).Tag.IsBuiltIn); - item1.Relationships.Should().BeNull(); + item1.Attributes["text"].Should().Be(workItem.Tags.ElementAt(0).Text); + item1.Attributes["isBuiltIn"].Should().Be(workItem.Tags.ElementAt(0).IsBuiltIn); + item1.Relationships.Should().NotBeEmpty(); - ResourceObject item2 = responseDocument.ManyData.Single(resource => resource.Id == workItem.WorkItemTags.ElementAt(1).Tag.StringId); + ResourceObject item2 = responseDocument.ManyData.Single(resource => resource.Id == workItem.Tags.ElementAt(1).StringId); item2.Type.Should().Be("workTags"); - item2.Attributes["text"].Should().Be(workItem.WorkItemTags.ElementAt(1).Tag.Text); - item2.Attributes["isBuiltIn"].Should().Be(workItem.WorkItemTags.ElementAt(1).Tag.IsBuiltIn); - item2.Relationships.Should().BeNull(); + item2.Attributes["text"].Should().Be(workItem.Tags.ElementAt(1).Text); + item2.Attributes["isBuiltIn"].Should().Be(workItem.Tags.ElementAt(1).IsBuiltIn); + item2.Relationships.Should().NotBeEmpty(); } [Fact] - public async Task Can_get_unknown_secondary_HasManyThrough_resources() + public async Task Can_get_unknown_secondary_ManyToMany_resources() { // Arrange WorkItem workItem = _fakers.WorkItem.Generate(); diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/ReadWriteDbContext.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/ReadWriteDbContext.cs index c5d589cbb8..c696a4ef21 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/ReadWriteDbContext.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/ReadWriteDbContext.cs @@ -10,7 +10,6 @@ public sealed class ReadWriteDbContext : DbContext { public DbSet WorkItems { get; set; } public DbSet WorkTags { get; set; } - public DbSet WorkItemTags { get; set; } public DbSet Groups { get; set; } public DbSet RgbColors { get; set; } public DbSet UserAccounts { get; set; } @@ -35,13 +34,6 @@ protected override void OnModelCreating(ModelBuilder builder) .WithOne(color => color.Group) .HasForeignKey("GroupId"); - builder.Entity() - .HasKey(workItemTag => new - { - workItemTag.ItemId, - workItemTag.TagId - }); - builder.Entity() .HasKey(item => new { diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/AddToToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/AddToToManyRelationshipTests.cs index d6971ad5cc..531d8e569b 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/AddToToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/AddToToManyRelationshipTests.cs @@ -25,7 +25,7 @@ public AddToToManyRelationshipTests(ExampleIntegrationTestContext } [Fact] - public async Task Can_add_to_HasMany_relationship_with_already_assigned_resources() + public async Task Can_add_to_OneToMany_relationship_with_already_assigned_resources() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -116,26 +116,12 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_add_to_HasManyThrough_relationship_with_already_assigned_resources() + public async Task Can_add_to_ManyToMany_relationship_with_already_assigned_resources() { // Arrange List existingWorkItems = _fakers.WorkItem.Generate(2); - - existingWorkItems[0].WorkItemTags = new[] - { - new WorkItemTag - { - Tag = _fakers.WorkTag.Generate() - } - }; - - existingWorkItems[1].WorkItemTags = new[] - { - new WorkItemTag - { - Tag = _fakers.WorkTag.Generate() - } - }; + existingWorkItems[0].Tags = _fakers.WorkTag.Generate(1).ToHashSet(); + existingWorkItems[1].Tags = _fakers.WorkTag.Generate(1).ToHashSet(); await _testContext.RunOnDatabaseAsync(async dbContext => { @@ -150,12 +136,12 @@ await _testContext.RunOnDatabaseAsync(async dbContext => new { type = "workTags", - id = existingWorkItems[0].WorkItemTags.ElementAt(0).Tag.StringId + id = existingWorkItems[0].Tags.ElementAt(0).StringId }, new { type = "workTags", - id = existingWorkItems[1].WorkItemTags.ElementAt(0).Tag.StringId + id = existingWorkItems[1].Tags.ElementAt(0).StringId } } }; @@ -172,30 +158,21 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - List workItemsInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.WorkItemTags) - .ThenInclude(workItemTag => workItemTag.Tag) - .ToListAsync(); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore + List workItemsInDatabase = await dbContext.WorkItems.Include(workItem => workItem.Tags).ToListAsync(); WorkItem workItemInDatabase1 = workItemsInDatabase.Single(workItem => workItem.Id == existingWorkItems[0].Id); - int tagId1 = existingWorkItems[0].WorkItemTags.ElementAt(0).Tag.Id; - int tagId2 = existingWorkItems[1].WorkItemTags.ElementAt(0).Tag.Id; + int tagId1 = existingWorkItems[0].Tags.ElementAt(0).Id; + int tagId2 = existingWorkItems[1].Tags.ElementAt(0).Id; - workItemInDatabase1.WorkItemTags.Should().HaveCount(2); - workItemInDatabase1.WorkItemTags.Should().ContainSingle(workItemTag => workItemTag.Tag.Id == tagId1); - workItemInDatabase1.WorkItemTags.Should().ContainSingle(workItemTag => workItemTag.Tag.Id == tagId2); + workItemInDatabase1.Tags.Should().HaveCount(2); + workItemInDatabase1.Tags.Should().ContainSingle(workTag => workTag.Id == tagId1); + workItemInDatabase1.Tags.Should().ContainSingle(workTag => workTag.Id == tagId2); WorkItem workItemInDatabase2 = workItemsInDatabase.Single(workItem => workItem.Id == existingWorkItems[1].Id); - workItemInDatabase2.WorkItemTags.Should().HaveCount(1); - workItemInDatabase2.WorkItemTags.ElementAt(0).Tag.Id.Should().Be(tagId2); + workItemInDatabase2.Tags.Should().HaveCount(1); + workItemInDatabase2.Tags.ElementAt(0).Id.Should().Be(tagId2); }); } @@ -348,7 +325,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_add_unknown_IDs_to_HasMany_relationship() + public async Task Cannot_add_unknown_IDs_to_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -398,7 +375,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_add_unknown_IDs_to_HasManyThrough_relationship() + public async Task Cannot_add_unknown_IDs_to_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -691,7 +668,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_add_with_null_data_in_HasMany_relationship() + public async Task Cannot_add_with_null_data_in_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -724,7 +701,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_add_with_null_data_in_HasManyThrough_relationship() + public async Task Cannot_add_with_null_data_in_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -757,7 +734,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_add_self_to_cyclic_HasMany_relationship() + public async Task Can_add_self_to_cyclic_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -802,7 +779,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_add_self_to_cyclic_HasManyThrough_relationship() + public async Task Can_add_self_to_cyclic_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/RemoveFromToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/RemoveFromToManyRelationshipTests.cs index 90115fc567..13fd4fd767 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/RemoveFromToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/RemoveFromToManyRelationshipTests.cs @@ -26,7 +26,7 @@ public RemoveFromToManyRelationshipTests(ExampleIntegrationTestContext } [Fact] - public async Task Can_remove_from_HasMany_relationship_with_unassigned_existing_resource() + public async Task Can_remove_from_OneToMany_relationship_with_unassigned_existing_resource() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -118,22 +118,11 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_remove_from_HasManyThrough_relationship_with_unassigned_existing_resource() + public async Task Can_remove_from_ManyToMany_relationship_with_unassigned_existing_resource() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); - - existingWorkItem.WorkItemTags = new[] - { - new WorkItemTag - { - Tag = _fakers.WorkTag.Generate() - }, - new WorkItemTag - { - Tag = _fakers.WorkTag.Generate() - } - }; + existingWorkItem.Tags = _fakers.WorkTag.Generate(2).ToHashSet(); WorkTag existingTag = _fakers.WorkTag.Generate(); @@ -151,7 +140,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => new { type = "workTags", - id = existingWorkItem.WorkItemTags.ElementAt(1).Tag.StringId + id = existingWorkItem.Tags.ElementAt(1).StringId }, new { @@ -173,19 +162,10 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - WorkItem workItemInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.WorkItemTags) - .ThenInclude(workItemTag => workItemTag.Tag) - .FirstWithIdAsync(existingWorkItem.Id); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore + WorkItem workItemInDatabase = await dbContext.WorkItems.Include(workItem => workItem.Tags).FirstWithIdAsync(existingWorkItem.Id); - workItemInDatabase.WorkItemTags.Should().HaveCount(1); - workItemInDatabase.WorkItemTags.Single().Tag.Id.Should().Be(existingWorkItem.WorkItemTags.ElementAt(0).Tag.Id); + workItemInDatabase.Tags.Should().HaveCount(1); + workItemInDatabase.Tags.Single().Id.Should().Be(existingWorkItem.Tags.ElementAt(0).Id); List tagsInDatabase = await dbContext.WorkTags.ToListAsync(); tagsInDatabase.Should().HaveCount(3); @@ -342,7 +322,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_remove_unknown_IDs_from_HasMany_relationship() + public async Task Cannot_remove_unknown_IDs_from_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -392,7 +372,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_remove_unknown_IDs_from_HasManyThrough_relationship() + public async Task Cannot_remove_unknown_IDs_from_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -687,7 +667,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_remove_with_null_data_in_HasMany_relationship() + public async Task Cannot_remove_with_null_data_in_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -720,7 +700,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_remove_with_null_data_in_HasManyThrough_relationship() + public async Task Cannot_remove_with_null_data_in_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -753,7 +733,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_remove_self_from_cyclic_HasMany_relationship() + public async Task Can_remove_self_from_cyclic_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -800,7 +780,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_remove_self_from_cyclic_HasManyThrough_relationship() + public async Task Can_remove_self_from_cyclic_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/ReplaceToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/ReplaceToManyRelationshipTests.cs index 0e6089fddb..6cbcb5d832 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/ReplaceToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/ReplaceToManyRelationshipTests.cs @@ -25,7 +25,7 @@ public ReplaceToManyRelationshipTests(ExampleIntegrationTestContext } [Fact] - public async Task Can_clear_HasManyThrough_relationship() + public async Task Can_clear_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); - - existingWorkItem.WorkItemTags = new[] - { - new WorkItemTag - { - Tag = _fakers.WorkTag.Generate() - } - }; + existingWorkItem.Tags = _fakers.WorkTag.Generate(1).ToHashSet(); await _testContext.RunOnDatabaseAsync(async dbContext => { @@ -97,23 +90,14 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true + WorkItem workItemInDatabase = await dbContext.WorkItems.Include(workItem => workItem.Tags).FirstWithIdAsync(existingWorkItem.Id); - WorkItem workItemInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.WorkItemTags) - .ThenInclude(workItemTag => workItemTag.Tag) - .FirstWithIdAsync(existingWorkItem.Id); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore - - workItemInDatabase.WorkItemTags.Should().BeEmpty(); + workItemInDatabase.Tags.Should().BeEmpty(); }); } [Fact] - public async Task Can_replace_HasMany_relationship_with_already_assigned_resources() + public async Task Can_replace_OneToMany_relationship_with_already_assigned_resources() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -165,22 +149,11 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_replace_HasManyThrough_relationship_with_already_assigned_resources() + public async Task Can_replace_ManyToMany_relationship_with_already_assigned_resources() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); - - existingWorkItem.WorkItemTags = new[] - { - new WorkItemTag - { - Tag = _fakers.WorkTag.Generate() - }, - new WorkItemTag - { - Tag = _fakers.WorkTag.Generate() - } - }; + existingWorkItem.Tags = _fakers.WorkTag.Generate(2).ToHashSet(); List existingTags = _fakers.WorkTag.Generate(2); @@ -198,7 +171,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => new { type = "workTags", - id = existingWorkItem.WorkItemTags.ElementAt(0).Tag.StringId + id = existingWorkItem.Tags.ElementAt(0).StringId }, new { @@ -225,21 +198,12 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - WorkItem workItemInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.WorkItemTags) - .ThenInclude(workItemTag => workItemTag.Tag) - .FirstWithIdAsync(existingWorkItem.Id); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore + WorkItem workItemInDatabase = await dbContext.WorkItems.Include(workItem => workItem.Tags).FirstWithIdAsync(existingWorkItem.Id); - workItemInDatabase.WorkItemTags.Should().HaveCount(3); - workItemInDatabase.WorkItemTags.Should().ContainSingle(workItemTag => workItemTag.Tag.Id == existingWorkItem.WorkItemTags.ElementAt(0).Tag.Id); - workItemInDatabase.WorkItemTags.Should().ContainSingle(workItemTag => workItemTag.Tag.Id == existingTags[0].Id); - workItemInDatabase.WorkItemTags.Should().ContainSingle(workItemTag => workItemTag.Tag.Id == existingTags[1].Id); + workItemInDatabase.Tags.Should().HaveCount(3); + workItemInDatabase.Tags.Should().ContainSingle(workTag => workTag.Id == existingWorkItem.Tags.ElementAt(0).Id); + workItemInDatabase.Tags.Should().ContainSingle(workTag => workTag.Id == existingTags[0].Id); + workItemInDatabase.Tags.Should().ContainSingle(workTag => workTag.Id == existingTags[1].Id); }); } @@ -392,7 +356,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_replace_with_unknown_IDs_in_HasMany_relationship() + public async Task Cannot_replace_with_unknown_IDs_in_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -442,7 +406,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_replace_with_unknown_IDs_in_HasManyThrough_relationship() + public async Task Cannot_replace_with_unknown_IDs_in_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -695,7 +659,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_replace_with_null_data_in_HasMany_relationship() + public async Task Cannot_replace_with_null_data_in_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -728,7 +692,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_replace_with_null_data_in_HasManyThrough_relationship() + public async Task Cannot_replace_with_null_data_in_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -761,7 +725,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_clear_cyclic_HasMany_relationship() + public async Task Can_clear_cyclic_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -803,7 +767,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_clear_cyclic_HasManyThrough_relationship() + public async Task Can_clear_cyclic_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -900,7 +864,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_assign_cyclic_HasManyThrough_relationship() + public async Task Can_assign_cyclic_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/ReplaceToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/ReplaceToManyRelationshipTests.cs index bd71ae8623..fa40f89a19 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/ReplaceToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/ReplaceToManyRelationshipTests.cs @@ -26,7 +26,7 @@ public ReplaceToManyRelationshipTests(ExampleIntegrationTestContext } [Fact] - public async Task Can_clear_HasManyThrough_relationship() + public async Task Can_clear_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); - - existingWorkItem.WorkItemTags = new[] - { - new WorkItemTag - { - Tag = _fakers.WorkTag.Generate() - } - }; + existingWorkItem.Tags = _fakers.WorkTag.Generate(1).ToHashSet(); await _testContext.RunOnDatabaseAsync(async dbContext => { @@ -120,23 +113,14 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true + WorkItem workItemInDatabase = await dbContext.WorkItems.Include(workItem => workItem.Tags).FirstWithIdAsync(existingWorkItem.Id); - WorkItem workItemInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.WorkItemTags) - .ThenInclude(workItemTag => workItemTag.Tag) - .FirstWithIdAsync(existingWorkItem.Id); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore - - workItemInDatabase.WorkItemTags.Should().BeEmpty(); + workItemInDatabase.Tags.Should().BeEmpty(); }); } [Fact] - public async Task Can_replace_HasMany_relationship_with_already_assigned_resources() + public async Task Can_replace_OneToMany_relationship_with_already_assigned_resources() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -199,22 +183,11 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_replace_HasManyThrough_relationship_with_already_assigned_resources() + public async Task Can_replace_ManyToMany_relationship_with_already_assigned_resources() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); - - existingWorkItem.WorkItemTags = new[] - { - new WorkItemTag - { - Tag = _fakers.WorkTag.Generate() - }, - new WorkItemTag - { - Tag = _fakers.WorkTag.Generate() - } - }; + existingWorkItem.Tags = _fakers.WorkTag.Generate(2).ToHashSet(); List existingTags = _fakers.WorkTag.Generate(2); @@ -240,7 +213,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => new { type = "workTags", - id = existingWorkItem.WorkItemTags.ElementAt(0).Tag.StringId + id = existingWorkItem.Tags.ElementAt(0).StringId }, new { @@ -270,26 +243,17 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true + WorkItem workItemInDatabase = await dbContext.WorkItems.Include(workItem => workItem.Tags).FirstWithIdAsync(existingWorkItem.Id); - WorkItem workItemInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.WorkItemTags) - .ThenInclude(workItemTag => workItemTag.Tag) - .FirstWithIdAsync(existingWorkItem.Id); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore - - workItemInDatabase.WorkItemTags.Should().HaveCount(3); - workItemInDatabase.WorkItemTags.Should().ContainSingle(workItemTag => workItemTag.Tag.Id == existingWorkItem.WorkItemTags.ElementAt(0).Tag.Id); - workItemInDatabase.WorkItemTags.Should().ContainSingle(workItemTag => workItemTag.Tag.Id == existingTags[0].Id); - workItemInDatabase.WorkItemTags.Should().ContainSingle(workItemTag => workItemTag.Tag.Id == existingTags[1].Id); + workItemInDatabase.Tags.Should().HaveCount(3); + workItemInDatabase.Tags.Should().ContainSingle(workTag => workTag.Id == existingWorkItem.Tags.ElementAt(0).Id); + workItemInDatabase.Tags.Should().ContainSingle(workTag => workTag.Id == existingTags[0].Id); + workItemInDatabase.Tags.Should().ContainSingle(workTag => workTag.Id == existingTags[1].Id); }); } [Fact] - public async Task Can_replace_HasMany_relationship_with_include() + public async Task Can_replace_OneToMany_relationship_with_include() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -355,7 +319,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_replace_HasManyThrough_relationship_with_include_and_fieldsets() + public async Task Can_replace_ManyToMany_relationship_with_include_and_fieldsets() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -418,19 +382,10 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - WorkItem workItemInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.WorkItemTags) - .ThenInclude(workItemTag => workItemTag.Tag) - .FirstWithIdAsync(newWorkItemId); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore + WorkItem workItemInDatabase = await dbContext.WorkItems.Include(workItem => workItem.Tags).FirstWithIdAsync(newWorkItemId); - workItemInDatabase.WorkItemTags.Should().HaveCount(1); - workItemInDatabase.WorkItemTags.Single().Tag.Id.Should().Be(existingTag.Id); + workItemInDatabase.Tags.Should().HaveCount(1); + workItemInDatabase.Tags.Single().Id.Should().Be(existingTag.Id); }); } @@ -786,7 +741,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_replace_with_null_data_in_HasMany_relationship() + public async Task Cannot_replace_with_null_data_in_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -830,7 +785,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_replace_with_null_data_in_HasManyThrough_relationship() + public async Task Cannot_replace_with_null_data_in_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -874,7 +829,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_clear_cyclic_HasMany_relationship() + public async Task Can_clear_cyclic_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -923,7 +878,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_clear_cyclic_HasManyThrough_relationship() + public async Task Can_clear_cyclic_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -988,7 +943,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_assign_cyclic_HasMany_relationship() + public async Task Can_assign_cyclic_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -1042,7 +997,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_assign_cyclic_HasManyThrough_relationship() + public async Task Can_assign_cyclic_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs index b1a353183b..bfe096f245 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs @@ -423,14 +423,7 @@ public async Task Can_update_resource_with_side_effects_with_include_and_fieldse { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); - - existingWorkItem.WorkItemTags = new[] - { - new WorkItemTag - { - Tag = _fakers.WorkTag.Generate() - } - }; + existingWorkItem.Tags = _fakers.WorkTag.Generate(1).ToHashSet(); string newDescription = _fakers.WorkItem.Generate().Description; @@ -470,13 +463,13 @@ await _testContext.RunOnDatabaseAsync(async dbContext => responseDocument.SingleData.Attributes["priority"].Should().Be(existingWorkItem.Priority.ToString("G")); responseDocument.SingleData.Relationships.Should().HaveCount(1); responseDocument.SingleData.Relationships["tags"].ManyData.Should().HaveCount(1); - responseDocument.SingleData.Relationships["tags"].ManyData[0].Id.Should().Be(existingWorkItem.WorkItemTags.Single().Tag.StringId); + responseDocument.SingleData.Relationships["tags"].ManyData[0].Id.Should().Be(existingWorkItem.Tags.Single().StringId); responseDocument.Included.Should().HaveCount(1); responseDocument.Included[0].Type.Should().Be("workTags"); - responseDocument.Included[0].Id.Should().Be(existingWorkItem.WorkItemTags.Single().Tag.StringId); + responseDocument.Included[0].Id.Should().Be(existingWorkItem.Tags.Single().StringId); responseDocument.Included[0].Attributes.Should().HaveCount(1); - responseDocument.Included[0].Attributes["text"].Should().Be(existingWorkItem.WorkItemTags.Single().Tag.Text); + responseDocument.Included[0].Attributes["text"].Should().Be(existingWorkItem.Tags.Single().Text); responseDocument.Included[0].Relationships.Should().BeNull(); await _testContext.RunOnDatabaseAsync(async dbContext => @@ -1005,14 +998,7 @@ public async Task Can_update_resource_with_attributes_and_multiple_relationship_ WorkItem existingWorkItem = _fakers.WorkItem.Generate(); existingWorkItem.Assignee = _fakers.UserAccount.Generate(); existingWorkItem.Subscribers = _fakers.UserAccount.Generate(1).ToHashSet(); - - existingWorkItem.WorkItemTags = new List - { - new() - { - Tag = _fakers.WorkTag.Generate() - } - }; + existingWorkItem.Tags = _fakers.WorkTag.Generate(1).ToHashSet(); List existingUserAccounts = _fakers.UserAccount.Generate(2); WorkTag existingTag = _fakers.WorkTag.Generate(); @@ -1092,8 +1078,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => WorkItem workItemInDatabase = await dbContext.WorkItems .Include(workItem => workItem.Assignee) .Include(workItem => workItem.Subscribers) - .Include(workItem => workItem.WorkItemTags) - .ThenInclude(workItemTag => workItemTag.Tag) + .Include(workItem => workItem.Tags) .FirstWithIdAsync(existingWorkItem.Id); // @formatter:keep_existing_linebreaks restore @@ -1107,8 +1092,8 @@ await _testContext.RunOnDatabaseAsync(async dbContext => workItemInDatabase.Subscribers.Should().HaveCount(1); workItemInDatabase.Subscribers.Single().Id.Should().Be(existingUserAccounts[1].Id); - workItemInDatabase.WorkItemTags.Should().HaveCount(1); - workItemInDatabase.WorkItemTags.Single().Tag.Id.Should().Be(existingTag.Id); + workItemInDatabase.Tags.Should().HaveCount(1); + workItemInDatabase.Tags.Single().Id.Should().Be(existingTag.Id); }); } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItem.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItem.cs index a328f07c41..861dc02d48 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItem.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItem.cs @@ -33,12 +33,9 @@ public Guid ConcurrencyToken [HasMany] public ISet Subscribers { get; set; } - [NotMapped] - [HasManyThrough(nameof(WorkItemTags))] + [HasMany] public ISet Tags { get; set; } - public ICollection WorkItemTags { get; set; } - [HasOne] public WorkItem Parent { get; set; } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItemTag.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItemTag.cs deleted file mode 100644 index bf17fd2a3e..0000000000 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItemTag.cs +++ /dev/null @@ -1,14 +0,0 @@ -using JetBrains.Annotations; - -namespace JsonApiDotNetCoreExampleTests.IntegrationTests.ReadWrite -{ - [UsedImplicitly(ImplicitUseTargetFlags.Members)] - public sealed class WorkItemTag - { - public WorkItem Item { get; set; } - public int ItemId { get; set; } - - public WorkTag Tag { get; set; } - public int TagId { get; set; } - } -} diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkTag.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkTag.cs index 290a0285c5..f82b3e183e 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkTag.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkTag.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using JetBrains.Annotations; using JsonApiDotNetCore.Resources; using JsonApiDotNetCore.Resources.Annotations; @@ -12,5 +13,8 @@ public sealed class WorkTag : Identifiable [Attr] public bool IsBuiltIn { get; set; } + + [HasMany] + public ISet WorkItems { get; set; } } } From d058594bd3e9988d772fd68657f90eb74fce94ae Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Fri, 23 Jul 2021 16:08:12 +0200 Subject: [PATCH 04/15] Updated WorkItem.RelatedTo/RelatedFrom cyclic relationship in IntegrationTests to use native many-to-many --- .../ReadWrite/ReadWriteDbContext.cs | 30 +++++++++--------- .../AddToToManyRelationshipTests.cs | 23 +++++--------- .../RemoveFromToManyRelationshipTests.cs | 25 +++++---------- .../ReplaceToManyRelationshipTests.cs | 31 +++++++++---------- .../ReplaceToManyRelationshipTests.cs | 28 +++++++---------- .../Updating/Resources/UpdateResourceTests.cs | 20 +++++------- .../IntegrationTests/ReadWrite/WorkItem.cs | 11 ++----- .../ReadWrite/WorkItemToWorkItem.cs | 3 -- 8 files changed, 66 insertions(+), 105 deletions(-) diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/ReadWriteDbContext.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/ReadWriteDbContext.cs index c696a4ef21..a149fa9850 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/ReadWriteDbContext.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/ReadWriteDbContext.cs @@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore; // @formatter:wrap_chained_method_calls chop_always +// @formatter:keep_existing_linebreaks true namespace JsonApiDotNetCoreExampleTests.IntegrationTests.ReadWrite { @@ -34,22 +35,19 @@ protected override void OnModelCreating(ModelBuilder builder) .WithOne(color => color.Group) .HasForeignKey("GroupId"); - builder.Entity() - .HasKey(item => new - { - item.FromItemId, - item.ToItemId - }); - - builder.Entity() - .HasOne(workItemToWorkItem => workItemToWorkItem.FromItem) - .WithMany(workItem => workItem.RelatedToItems) - .HasForeignKey(workItemToWorkItem => workItemToWorkItem.FromItemId); - - builder.Entity() - .HasOne(workItemToWorkItem => workItemToWorkItem.ToItem) - .WithMany(workItem => workItem.RelatedFromItems) - .HasForeignKey(workItemToWorkItem => workItemToWorkItem.ToItemId); + builder.Entity() + .HasOne(workItem => workItem.Parent) + .WithMany(workItem => workItem.Children); + + builder.Entity() + .HasMany(workItem => workItem.RelatedFrom) + .WithMany(workItem => workItem.RelatedTo) + .UsingEntity(right => right + .HasOne(joinEntity => joinEntity.FromItem) + .WithMany(), + left => left + .HasOne(joinEntity => joinEntity.ToItem) + .WithMany()); } } } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/AddToToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/AddToToManyRelationshipTests.cs index 531d8e569b..2b97784b48 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/AddToToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/AddToToManyRelationshipTests.cs @@ -783,14 +783,7 @@ public async Task Can_add_self_to_cyclic_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); - - existingWorkItem.RelatedToItems = new List - { - new() - { - ToItem = _fakers.WorkItem.Generate() - } - }; + existingWorkItem.RelatedTo = _fakers.WorkItem.Generate(1); await _testContext.RunOnDatabaseAsync(async dbContext => { @@ -826,19 +819,19 @@ await _testContext.RunOnDatabaseAsync(async dbContext => // @formatter:keep_existing_linebreaks true WorkItem workItemInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.RelatedToItems) - .ThenInclude(workItemToWorkItem => workItemToWorkItem.ToItem) + .Include(workItem => workItem.RelatedFrom) + .Include(workItem => workItem.RelatedTo) .FirstWithIdAsync(existingWorkItem.Id); // @formatter:keep_existing_linebreaks restore // @formatter:wrap_chained_method_calls restore - int toItemId = existingWorkItem.RelatedToItems[0].ToItem.Id; + workItemInDatabase.RelatedFrom.Should().HaveCount(1); + workItemInDatabase.RelatedFrom.Should().OnlyContain(workItem => workItem.Id == existingWorkItem.Id); - workItemInDatabase.RelatedToItems.Should().HaveCount(2); - workItemInDatabase.RelatedToItems.Should().OnlyContain(workItemToWorkItem => workItemToWorkItem.FromItem.Id == existingWorkItem.Id); - workItemInDatabase.RelatedToItems.Should().ContainSingle(workItemToWorkItem => workItemToWorkItem.ToItem.Id == existingWorkItem.Id); - workItemInDatabase.RelatedToItems.Should().ContainSingle(workItemToWorkItem => workItemToWorkItem.ToItem.Id == toItemId); + workItemInDatabase.RelatedTo.Should().HaveCount(2); + workItemInDatabase.RelatedTo.Should().ContainSingle(workItem => workItem.Id == existingWorkItem.Id); + workItemInDatabase.RelatedTo.Should().ContainSingle(workItem => workItem.Id == existingWorkItem.RelatedTo[0].Id); }); } } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/RemoveFromToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/RemoveFromToManyRelationshipTests.cs index 13fd4fd767..7d36261871 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/RemoveFromToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/RemoveFromToManyRelationshipTests.cs @@ -784,25 +784,14 @@ public async Task Can_remove_self_from_cyclic_ManyToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); - - existingWorkItem.RelatedFromItems = new List - { - new() - { - FromItem = _fakers.WorkItem.Generate() - } - }; + existingWorkItem.RelatedFrom = _fakers.WorkItem.Generate(1); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.WorkItems.Add(existingWorkItem); await dbContext.SaveChangesAsync(); - existingWorkItem.RelatedFromItems.Add(new WorkItemToWorkItem - { - FromItem = existingWorkItem - }); - + existingWorkItem.RelatedFrom.Add(existingWorkItem); await dbContext.SaveChangesAsync(); }); @@ -834,15 +823,17 @@ await _testContext.RunOnDatabaseAsync(async dbContext => // @formatter:keep_existing_linebreaks true WorkItem workItemInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.RelatedFromItems) - .ThenInclude(workItemToWorkItem => workItemToWorkItem.FromItem) + .Include(workItem => workItem.RelatedFrom) + .Include(workItem => workItem.RelatedTo) .FirstWithIdAsync(existingWorkItem.Id); // @formatter:keep_existing_linebreaks restore // @formatter:wrap_chained_method_calls restore - workItemInDatabase.RelatedFromItems.Should().HaveCount(1); - workItemInDatabase.RelatedFromItems[0].FromItem.Id.Should().Be(existingWorkItem.RelatedFromItems[0].FromItem.Id); + workItemInDatabase.RelatedFrom.Should().HaveCount(1); + workItemInDatabase.RelatedFrom[0].Id.Should().Be(existingWorkItem.RelatedFrom[0].Id); + + workItemInDatabase.RelatedTo.Should().BeEmpty(); }); } } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/ReplaceToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/ReplaceToManyRelationshipTests.cs index 6cbcb5d832..c4653f2244 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/ReplaceToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Relationships/ReplaceToManyRelationshipTests.cs @@ -4,6 +4,7 @@ using System.Net.Http; using System.Threading.Tasks; using FluentAssertions; +using JsonApiDotNetCore; using JsonApiDotNetCore.Serialization.Objects; using JsonApiDotNetCoreExampleTests.Startups; using Microsoft.EntityFrameworkCore; @@ -777,14 +778,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => dbContext.WorkItems.Add(existingWorkItem); await dbContext.SaveChangesAsync(); - existingWorkItem.RelatedFromItems = new List - { - new() - { - FromItem = existingWorkItem - } - }; - + existingWorkItem.RelatedFrom = ArrayFactory.Create(existingWorkItem); await dbContext.SaveChangesAsync(); }); @@ -809,19 +803,20 @@ await _testContext.RunOnDatabaseAsync(async dbContext => // @formatter:keep_existing_linebreaks true WorkItem workItemInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.RelatedFromItems) - .ThenInclude(workItemToWorkItem => workItemToWorkItem.FromItem) + .Include(workItem => workItem.RelatedFrom) + .Include(workItem => workItem.RelatedTo) .FirstWithIdAsync(existingWorkItem.Id); // @formatter:keep_existing_linebreaks restore // @formatter:wrap_chained_method_calls restore - workItemInDatabase.RelatedFromItems.Should().BeEmpty(); + workItemInDatabase.RelatedFrom.Should().BeEmpty(); + workItemInDatabase.RelatedTo.Should().BeEmpty(); }); } [Fact] - public async Task Can_assign_cyclic_HasMany_relationship() + public async Task Can_assign_cyclic_OneToMany_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); @@ -903,16 +898,18 @@ await _testContext.RunOnDatabaseAsync(async dbContext => // @formatter:keep_existing_linebreaks true WorkItem workItemInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.RelatedToItems) - .ThenInclude(workItemToWorkItem => workItemToWorkItem.ToItem) + .Include(workItem => workItem.RelatedFrom) + .Include(workItem => workItem.RelatedTo) .FirstWithIdAsync(existingWorkItem.Id); // @formatter:keep_existing_linebreaks restore // @formatter:wrap_chained_method_calls restore - workItemInDatabase.RelatedToItems.Should().HaveCount(1); - workItemInDatabase.RelatedToItems[0].FromItem.Id.Should().Be(existingWorkItem.Id); - workItemInDatabase.RelatedToItems[0].ToItem.Id.Should().Be(existingWorkItem.Id); + workItemInDatabase.RelatedFrom.Should().HaveCount(1); + workItemInDatabase.RelatedFrom[0].Id.Should().Be(existingWorkItem.Id); + + workItemInDatabase.RelatedTo.Should().HaveCount(1); + workItemInDatabase.RelatedTo[0].Id.Should().Be(existingWorkItem.Id); }); } } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/ReplaceToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/ReplaceToManyRelationshipTests.cs index fa40f89a19..f9ffae837a 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/ReplaceToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/ReplaceToManyRelationshipTests.cs @@ -888,14 +888,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => dbContext.WorkItems.Add(existingWorkItem); await dbContext.SaveChangesAsync(); - existingWorkItem.RelatedFromItems = new List - { - new() - { - FromItem = existingWorkItem - } - }; - + existingWorkItem.RelatedFrom = ArrayFactory.Create(existingWorkItem); await dbContext.SaveChangesAsync(); }); @@ -931,14 +924,15 @@ await _testContext.RunOnDatabaseAsync(async dbContext => // @formatter:keep_existing_linebreaks true WorkItem workItemInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.RelatedFromItems) - .ThenInclude(workItemToWorkItem => workItemToWorkItem.FromItem) + .Include(workItem => workItem.RelatedFrom) + .Include(workItem => workItem.RelatedTo) .FirstWithIdAsync(existingWorkItem.Id); // @formatter:keep_existing_linebreaks restore // @formatter:wrap_chained_method_calls restore - workItemInDatabase.RelatedFromItems.Should().BeEmpty(); + workItemInDatabase.RelatedFrom.Should().BeEmpty(); + workItemInDatabase.RelatedTo.Should().BeEmpty(); }); } @@ -1047,16 +1041,18 @@ await _testContext.RunOnDatabaseAsync(async dbContext => // @formatter:keep_existing_linebreaks true WorkItem workItemInDatabase = await dbContext.WorkItems - .Include(workItem => workItem.RelatedToItems) - .ThenInclude(workItemToWorkItem => workItemToWorkItem.ToItem) + .Include(workItem => workItem.RelatedFrom) + .Include(workItem => workItem.RelatedTo) .FirstWithIdAsync(existingWorkItem.Id); // @formatter:keep_existing_linebreaks restore // @formatter:wrap_chained_method_calls restore - workItemInDatabase.RelatedToItems.Should().HaveCount(1); - workItemInDatabase.RelatedToItems[0].FromItem.Id.Should().Be(existingWorkItem.Id); - workItemInDatabase.RelatedToItems[0].ToItem.Id.Should().Be(existingWorkItem.Id); + workItemInDatabase.RelatedFrom.Should().HaveCount(1); + workItemInDatabase.RelatedFrom[0].Id.Should().Be(existingWorkItem.Id); + + workItemInDatabase.RelatedTo.Should().HaveCount(1); + workItemInDatabase.RelatedTo[0].Id.Should().Be(existingWorkItem.Id); }); } } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs index bfe096f245..93ae540392 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/Updating/Resources/UpdateResourceTests.cs @@ -1104,14 +1104,7 @@ public async Task Can_update_resource_with_multiple_cyclic_relationship_types() WorkItem existingWorkItem = _fakers.WorkItem.Generate(); existingWorkItem.Parent = _fakers.WorkItem.Generate(); existingWorkItem.Children = _fakers.WorkItem.Generate(1); - - existingWorkItem.RelatedToItems = new List - { - new() - { - ToItem = _fakers.WorkItem.Generate() - } - }; + existingWorkItem.RelatedTo = _fakers.WorkItem.Generate(1); await _testContext.RunOnDatabaseAsync(async dbContext => { @@ -1179,8 +1172,8 @@ await _testContext.RunOnDatabaseAsync(async dbContext => WorkItem workItemInDatabase = await dbContext.WorkItems .Include(workItem => workItem.Parent) .Include(workItem => workItem.Children) - .Include(workItem => workItem.RelatedToItems) - .ThenInclude(workItemToWorkItem => workItemToWorkItem.ToItem) + .Include(workItem => workItem.RelatedFrom) + .Include(workItem => workItem.RelatedTo) .FirstWithIdAsync(existingWorkItem.Id); // @formatter:keep_existing_linebreaks restore @@ -1192,8 +1185,11 @@ await _testContext.RunOnDatabaseAsync(async dbContext => workItemInDatabase.Children.Should().HaveCount(1); workItemInDatabase.Children.Single().Id.Should().Be(existingWorkItem.Id); - workItemInDatabase.RelatedToItems.Should().HaveCount(1); - workItemInDatabase.RelatedToItems.Single().ToItem.Id.Should().Be(existingWorkItem.Id); + workItemInDatabase.RelatedFrom.Should().HaveCount(1); + workItemInDatabase.RelatedFrom.Single().Id.Should().Be(existingWorkItem.Id); + + workItemInDatabase.RelatedTo.Should().HaveCount(1); + workItemInDatabase.RelatedTo.Single().Id.Should().Be(existingWorkItem.Id); }); } } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItem.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItem.cs index 861dc02d48..747ec55721 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItem.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItem.cs @@ -42,19 +42,12 @@ public Guid ConcurrencyToken [HasMany] public IList Children { get; set; } - [NotMapped] - [HasManyThrough(nameof(RelatedFromItems), LeftPropertyName = nameof(WorkItemToWorkItem.ToItem), - RightPropertyName = nameof(WorkItemToWorkItem.FromItem))] + [HasMany] public IList RelatedFrom { get; set; } - public IList RelatedFromItems { get; set; } - - [NotMapped] - [HasManyThrough(nameof(RelatedToItems), LeftPropertyName = nameof(WorkItemToWorkItem.FromItem), RightPropertyName = nameof(WorkItemToWorkItem.ToItem))] + [HasMany] public IList RelatedTo { get; set; } - public IList RelatedToItems { get; set; } - [HasOne] public WorkItemGroup Group { get; set; } } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItemToWorkItem.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItemToWorkItem.cs index 92fa943645..1074c44182 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItemToWorkItem.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/ReadWrite/WorkItemToWorkItem.cs @@ -6,9 +6,6 @@ namespace JsonApiDotNetCoreExampleTests.IntegrationTests.ReadWrite public sealed class WorkItemToWorkItem { public WorkItem FromItem { get; set; } - public int FromItemId { get; set; } - public WorkItem ToItem { get; set; } - public int ToItemId { get; set; } } } From e589a1352db33322c5bcf00550392b71acf38c10 Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Fri, 23 Jul 2021 16:57:56 +0200 Subject: [PATCH 05/15] Updated Playlist.Tracks relationship in IntegrationTests to use native many-to-many --- ...eateResourceWithToManyRelationshipTests.cs | 27 ++--- .../Deleting/AtomicDeleteResourceTests.cs | 22 ++-- .../LocalIds/AtomicLocalIdTests.cs | 104 ++++-------------- .../AtomicModelStateValidationTests.cs | 49 ++------- .../AtomicOperations/MusicTrack.cs | 3 + .../AtomicOperations/OperationsDbContext.cs | 12 +- .../AtomicOperations/Playlist.cs | 5 +- .../AtomicOperations/PlaylistMusicTrack.cs | 15 --- .../AtomicAddToToManyRelationshipTests.cs | 36 ++---- ...AtomicRemoveFromToManyRelationshipTests.cs | 43 ++------ .../AtomicReplaceToManyRelationshipTests.cs | 62 +++-------- .../AtomicReplaceToManyRelationshipTests.cs | 62 +++-------- 12 files changed, 108 insertions(+), 332 deletions(-) delete mode 100644 test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/PlaylistMusicTrack.cs diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithToManyRelationshipTests.cs index 4273f2e10e..28de3cd6f2 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Creating/AtomicCreateResourceWithToManyRelationshipTests.cs @@ -32,7 +32,7 @@ public AtomicCreateResourceWithToManyRelationshipTests( } [Fact] - public async Task Can_create_HasMany_relationship() + public async Task Can_create_OneToMany_relationship() { // Arrange List existingPerformers = _fakers.Performer.Generate(2); @@ -110,7 +110,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_create_HasManyThrough_relationship() + public async Task Can_create_ManyToMany_relationship() { // Arrange List existingTracks = _fakers.MusicTrack.Generate(3); @@ -184,21 +184,12 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(newPlaylistId); - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(newPlaylistId); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore - - playlistInDatabase.PlaylistMusicTracks.Should().HaveCount(3); - playlistInDatabase.PlaylistMusicTracks.Should().ContainSingle(playlistMusicTrack => playlistMusicTrack.MusicTrack.Id == existingTracks[0].Id); - playlistInDatabase.PlaylistMusicTracks.Should().ContainSingle(playlistMusicTrack => playlistMusicTrack.MusicTrack.Id == existingTracks[1].Id); - playlistInDatabase.PlaylistMusicTracks.Should().ContainSingle(playlistMusicTrack => playlistMusicTrack.MusicTrack.Id == existingTracks[2].Id); + playlistInDatabase.Tracks.Should().HaveCount(3); + playlistInDatabase.Tracks.Should().ContainSingle(musicTrack => musicTrack.Id == existingTracks[0].Id); + playlistInDatabase.Tracks.Should().ContainSingle(musicTrack => musicTrack.Id == existingTracks[1].Id); + playlistInDatabase.Tracks.Should().ContainSingle(musicTrack => musicTrack.Id == existingTracks[2].Id); }); } @@ -545,7 +536,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Cannot_create_with_null_data_in_HasMany_relationship() + public async Task Cannot_create_with_null_data_in_OneToMany_relationship() { // Arrange var requestBody = new @@ -588,7 +579,7 @@ public async Task Cannot_create_with_null_data_in_HasMany_relationship() } [Fact] - public async Task Cannot_create_with_null_data_in_HasManyThrough_relationship() + public async Task Cannot_create_with_null_data_in_ManyToMany_relationship() { // Arrange var requestBody = new diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Deleting/AtomicDeleteResourceTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Deleting/AtomicDeleteResourceTests.cs index 116d8491fb..a8c6442063 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Deleting/AtomicDeleteResourceTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Deleting/AtomicDeleteResourceTests.cs @@ -228,7 +228,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_delete_existing_resource_with_HasMany_relationship() + public async Task Can_delete_existing_resource_with_OneToMany_relationship() { // Arrange MusicTrack existingTrack = _fakers.MusicTrack.Generate(); @@ -280,18 +280,15 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_delete_existing_resource_with_HasManyThrough_relationship() + public async Task Can_delete_existing_resource_with_ManyToMany_relationship() { // Arrange - var existingPlaylistMusicTrack = new PlaylistMusicTrack - { - Playlist = _fakers.Playlist.Generate(), - MusicTrack = _fakers.MusicTrack.Generate() - }; + Playlist existingPlaylist = _fakers.Playlist.Generate(); + existingPlaylist.Tracks = _fakers.MusicTrack.Generate(1); await _testContext.RunOnDatabaseAsync(async dbContext => { - dbContext.PlaylistMusicTracks.Add(existingPlaylistMusicTrack); + dbContext.Playlists.Add(existingPlaylist); await dbContext.SaveChangesAsync(); }); @@ -305,7 +302,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => @ref = new { type = "playlists", - id = existingPlaylistMusicTrack.Playlist.StringId + id = existingPlaylist.StringId } } } @@ -323,14 +320,13 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - Playlist playlistInDatabase = await dbContext.Playlists.FirstWithIdOrDefaultAsync(existingPlaylistMusicTrack.Playlist.Id); + Playlist playlistInDatabase = await dbContext.Playlists.FirstWithIdOrDefaultAsync(existingPlaylist.Id); playlistInDatabase.Should().BeNull(); - PlaylistMusicTrack playlistTracksInDatabase = await dbContext.PlaylistMusicTracks.FirstOrDefaultAsync(playlistMusicTrack => - playlistMusicTrack.Playlist.Id == existingPlaylistMusicTrack.Playlist.Id); + MusicTrack trackInDatabase = await dbContext.MusicTracks.FirstWithIdOrDefaultAsync(existingPlaylist.Tracks[0].Id); - playlistTracksInDatabase.Should().BeNull(); + trackInDatabase.Should().NotBeNull(); }); } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/LocalIds/AtomicLocalIdTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/LocalIds/AtomicLocalIdTests.cs index 8d44db11eb..415fa2d36c 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/LocalIds/AtomicLocalIdTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/LocalIds/AtomicLocalIdTests.cs @@ -26,7 +26,7 @@ public AtomicLocalIdTests(ExampleIntegrationTestContext { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(newPlaylistId); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(newPlaylistId); playlistInDatabase.Name.Should().Be(newPlaylistName); - playlistInDatabase.PlaylistMusicTracks.Should().HaveCount(1); - playlistInDatabase.PlaylistMusicTracks[0].MusicTrack.Id.Should().Be(newTrackId); - playlistInDatabase.PlaylistMusicTracks[0].MusicTrack.Title.Should().Be(newTrackTitle); + playlistInDatabase.Tracks.Should().HaveCount(1); + playlistInDatabase.Tracks[0].Id.Should().Be(newTrackId); + playlistInDatabase.Tracks[0].Title.Should().Be(newTrackTitle); }); } @@ -653,7 +644,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_create_ToOne_relationship_using_local_ID() + public async Task Can_create_ManyToOne_relationship_using_local_ID() { // Arrange string newTrackTitle = _fakers.MusicTrack.Generate().Title; @@ -936,22 +927,13 @@ public async Task Can_create_ManyToMany_relationship_using_local_ID() await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(newPlaylistId); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(newPlaylistId); playlistInDatabase.Name.Should().Be(newPlaylistName); - playlistInDatabase.PlaylistMusicTracks.Should().HaveCount(1); - playlistInDatabase.PlaylistMusicTracks[0].MusicTrack.Id.Should().Be(newTrackId); - playlistInDatabase.PlaylistMusicTracks[0].MusicTrack.Title.Should().Be(newTrackTitle); + playlistInDatabase.Tracks.Should().HaveCount(1); + playlistInDatabase.Tracks[0].Id.Should().Be(newTrackId); + playlistInDatabase.Tracks[0].Title.Should().Be(newTrackTitle); }); } @@ -1187,22 +1169,13 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(newPlaylistId); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(newPlaylistId); playlistInDatabase.Name.Should().Be(newPlaylistName); - playlistInDatabase.PlaylistMusicTracks.Should().HaveCount(1); - playlistInDatabase.PlaylistMusicTracks[0].MusicTrack.Id.Should().Be(newTrackId); - playlistInDatabase.PlaylistMusicTracks[0].MusicTrack.Title.Should().Be(newTrackTitle); + playlistInDatabase.Tracks.Should().HaveCount(1); + playlistInDatabase.Tracks[0].Id.Should().Be(newTrackId); + playlistInDatabase.Tracks[0].Title.Should().Be(newTrackTitle); }); } @@ -1462,23 +1435,14 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(newPlaylistId); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(newPlaylistId); playlistInDatabase.Name.Should().Be(newPlaylistName); - playlistInDatabase.PlaylistMusicTracks.Should().HaveCount(3); - playlistInDatabase.PlaylistMusicTracks.Should().ContainSingle(playlistMusicTrack => playlistMusicTrack.MusicTrack.Id == existingTracks[0].Id); - playlistInDatabase.PlaylistMusicTracks.Should().ContainSingle(playlistMusicTrack => playlistMusicTrack.MusicTrack.Id == existingTracks[1].Id); - playlistInDatabase.PlaylistMusicTracks.Should().ContainSingle(playlistMusicTrack => playlistMusicTrack.MusicTrack.Id == newTrackId); + playlistInDatabase.Tracks.Should().HaveCount(3); + playlistInDatabase.Tracks.Should().ContainSingle(musicTrack => musicTrack.Id == existingTracks[0].Id); + playlistInDatabase.Tracks.Should().ContainSingle(musicTrack => musicTrack.Id == existingTracks[1].Id); + playlistInDatabase.Tracks.Should().ContainSingle(musicTrack => musicTrack.Id == newTrackId); }); } @@ -1642,18 +1606,7 @@ public async Task Can_remove_from_ManyToMany_relationship_using_local_ID() { // Arrange Playlist existingPlaylist = _fakers.Playlist.Generate(); - - existingPlaylist.PlaylistMusicTracks = new[] - { - new PlaylistMusicTrack - { - MusicTrack = _fakers.MusicTrack.Generate() - }, - new PlaylistMusicTrack - { - MusicTrack = _fakers.MusicTrack.Generate() - } - }; + existingPlaylist.Tracks = _fakers.MusicTrack.Generate(2); string newTrackTitle = _fakers.MusicTrack.Generate().Title; @@ -1714,7 +1667,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => new { type = "musicTracks", - id = existingPlaylist.PlaylistMusicTracks[1].MusicTrack.StringId + id = existingPlaylist.Tracks[1].StringId } } }, @@ -1763,19 +1716,10 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(existingPlaylist.Id); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(existingPlaylist.Id); - playlistInDatabase.PlaylistMusicTracks.Should().HaveCount(1); - playlistInDatabase.PlaylistMusicTracks[0].MusicTrack.Id.Should().Be(existingPlaylist.PlaylistMusicTracks[0].MusicTrack.Id); + playlistInDatabase.Tracks.Should().HaveCount(1); + playlistInDatabase.Tracks[0].Id.Should().Be(existingPlaylist.Tracks[0].Id); }); } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/ModelStateValidation/AtomicModelStateValidationTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/ModelStateValidation/AtomicModelStateValidationTests.cs index e24be429e1..64c964a432 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/ModelStateValidation/AtomicModelStateValidationTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/ModelStateValidation/AtomicModelStateValidationTests.cs @@ -131,19 +131,10 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(newPlaylistId); - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(newPlaylistId); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore - - playlistInDatabase.PlaylistMusicTracks.Should().HaveCount(1); - playlistInDatabase.PlaylistMusicTracks[0].MusicTrack.Id.Should().Be(existingTrack.Id); + playlistInDatabase.Tracks.Should().HaveCount(1); + playlistInDatabase.Tracks[0].Id.Should().Be(existingTrack.Id); }); } @@ -310,24 +301,15 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(existingPlaylist.Id); + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(existingPlaylist.Id); - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore - - playlistInDatabase.PlaylistMusicTracks.Should().HaveCount(1); - playlistInDatabase.PlaylistMusicTracks[0].MusicTrack.Id.Should().Be(existingTrack.Id); + playlistInDatabase.Tracks.Should().HaveCount(1); + playlistInDatabase.Tracks[0].Id.Should().Be(existingTrack.Id); }); } [Fact] - public async Task Can_update_ToOne_relationship() + public async Task Can_update_ManyToOne_relationship() { // Arrange MusicTrack existingTrack = _fakers.MusicTrack.Generate(); @@ -381,7 +363,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_update_ToMany_relationship() + public async Task Can_update_ManyToMany_relationship() { // Arrange Playlist existingPlaylist = _fakers.Playlist.Generate(); @@ -430,19 +412,10 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(existingPlaylist.Id); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(existingPlaylist.Id); - playlistInDatabase.PlaylistMusicTracks.Should().HaveCount(1); - playlistInDatabase.PlaylistMusicTracks[0].MusicTrack.Id.Should().Be(existingTrack.Id); + playlistInDatabase.Tracks.Should().HaveCount(1); + playlistInDatabase.Tracks[0].Id.Should().Be(existingTrack.Id); }); } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/MusicTrack.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/MusicTrack.cs index 94733028d9..8c8dcd498f 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/MusicTrack.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/MusicTrack.cs @@ -35,5 +35,8 @@ public sealed class MusicTrack : Identifiable [HasMany] public IList Performers { get; set; } + + [HasMany] + public IList OccursIn { get; set; } } } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/OperationsDbContext.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/OperationsDbContext.cs index ad45e3bb85..d09892953b 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/OperationsDbContext.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/OperationsDbContext.cs @@ -10,7 +10,6 @@ public sealed class OperationsDbContext : DbContext { public DbSet Playlists { get; set; } public DbSet MusicTracks { get; set; } - public DbSet PlaylistMusicTracks { get; set; } public DbSet Lyrics { get; set; } public DbSet TextLanguages { get; set; } public DbSet Performers { get; set; } @@ -23,17 +22,14 @@ public OperationsDbContext(DbContextOptions options) protected override void OnModelCreating(ModelBuilder builder) { - builder.Entity() - .HasKey(playlistMusicTrack => new - { - playlistMusicTrack.PlaylistId, - playlistMusicTrack.MusicTrackId - }); - builder.Entity() .HasOne(musicTrack => musicTrack.Lyric) .WithOne(lyric => lyric.Track) .HasForeignKey("LyricId"); + + builder.Entity() + .HasMany(musicTrack => musicTrack.OccursIn) + .WithMany(playlist => playlist.Tracks); } } } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Playlist.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Playlist.cs index 5b0713c45b..51e5bc07d0 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Playlist.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Playlist.cs @@ -18,10 +18,7 @@ public sealed class Playlist : Identifiable [Attr] public bool IsArchived => false; - [NotMapped] - [HasManyThrough(nameof(PlaylistMusicTracks))] + [HasMany] public IList Tracks { get; set; } - - public IList PlaylistMusicTracks { get; set; } } } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/PlaylistMusicTrack.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/PlaylistMusicTrack.cs deleted file mode 100644 index 47540cafdf..0000000000 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/PlaylistMusicTrack.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using JetBrains.Annotations; - -namespace JsonApiDotNetCoreExampleTests.IntegrationTests.AtomicOperations -{ - [UsedImplicitly(ImplicitUseTargetFlags.Members)] - public sealed class PlaylistMusicTrack - { - public long PlaylistId { get; set; } - public Playlist Playlist { get; set; } - - public Guid MusicTrackId { get; set; } - public MusicTrack MusicTrack { get; set; } - } -} diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicAddToToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicAddToToManyRelationshipTests.cs index 1ee2823561..901d6bde71 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicAddToToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicAddToToManyRelationshipTests.cs @@ -28,7 +28,7 @@ public AtomicAddToToManyRelationshipTests(ExampleIntegrationTestContext } [Fact] - public async Task Can_add_to_HasMany_relationship() + public async Task Can_add_to_OneToMany_relationship() { // Arrange MusicTrack existingTrack = _fakers.MusicTrack.Generate(); @@ -159,18 +159,11 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_add_to_HasManyThrough_relationship() + public async Task Can_add_to_ManyToMany_relationship() { // Arrange Playlist existingPlaylist = _fakers.Playlist.Generate(); - - existingPlaylist.PlaylistMusicTracks = new List - { - new() - { - MusicTrack = _fakers.MusicTrack.Generate() - } - }; + existingPlaylist.Tracks = _fakers.MusicTrack.Generate(1); List existingTracks = _fakers.MusicTrack.Generate(2); @@ -236,23 +229,12 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(existingPlaylist.Id); - - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore - - Guid initialTrackId = existingPlaylist.PlaylistMusicTracks[0].MusicTrack.Id; + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(existingPlaylist.Id); - playlistInDatabase.PlaylistMusicTracks.Should().HaveCount(3); - playlistInDatabase.PlaylistMusicTracks.Should().ContainSingle(playlistMusicTrack => playlistMusicTrack.MusicTrack.Id == initialTrackId); - playlistInDatabase.PlaylistMusicTracks.Should().ContainSingle(playlistMusicTrack => playlistMusicTrack.MusicTrack.Id == existingTracks[0].Id); - playlistInDatabase.PlaylistMusicTracks.Should().ContainSingle(playlistMusicTrack => playlistMusicTrack.MusicTrack.Id == existingTracks[1].Id); + playlistInDatabase.Tracks.Should().HaveCount(3); + playlistInDatabase.Tracks.Should().ContainSingle(musicTrack => musicTrack.Id == existingPlaylist.Tracks[0].Id); + playlistInDatabase.Tracks.Should().ContainSingle(musicTrack => musicTrack.Id == existingTracks[0].Id); + playlistInDatabase.Tracks.Should().ContainSingle(musicTrack => musicTrack.Id == existingTracks[1].Id); }); } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicRemoveFromToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicRemoveFromToManyRelationshipTests.cs index 9fddd90b69..57d0239f02 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicRemoveFromToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicRemoveFromToManyRelationshipTests.cs @@ -28,7 +28,7 @@ public AtomicRemoveFromToManyRelationshipTests(ExampleIntegrationTestContext } [Fact] - public async Task Can_remove_from_HasMany_relationship() + public async Task Can_remove_from_OneToMany_relationship() { // Arrange MusicTrack existingTrack = _fakers.MusicTrack.Generate(); @@ -158,26 +158,11 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_remove_from_HasManyThrough_relationship() + public async Task Can_remove_from_ManyToMany_relationship() { // Arrange Playlist existingPlaylist = _fakers.Playlist.Generate(); - - existingPlaylist.PlaylistMusicTracks = new List - { - new() - { - MusicTrack = _fakers.MusicTrack.Generate() - }, - new() - { - MusicTrack = _fakers.MusicTrack.Generate() - }, - new() - { - MusicTrack = _fakers.MusicTrack.Generate() - } - }; + existingPlaylist.Tracks = _fakers.MusicTrack.Generate(3); await _testContext.RunOnDatabaseAsync(async dbContext => { @@ -204,7 +189,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => new { type = "musicTracks", - id = existingPlaylist.PlaylistMusicTracks[0].MusicTrack.StringId + id = existingPlaylist.Tracks[0].StringId } } }, @@ -222,7 +207,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext => new { type = "musicTracks", - id = existingPlaylist.PlaylistMusicTracks[2].MusicTrack.StringId + id = existingPlaylist.Tracks[2].StringId } } } @@ -241,21 +226,13 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(existingPlaylist.Id); + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(existingPlaylist.Id); - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore - - playlistInDatabase.PlaylistMusicTracks.Should().HaveCount(1); - playlistInDatabase.PlaylistMusicTracks[0].MusicTrack.Id.Should().Be(existingPlaylist.PlaylistMusicTracks[1].MusicTrack.Id); + playlistInDatabase.Tracks.Should().HaveCount(1); + playlistInDatabase.Tracks[0].Id.Should().Be(existingPlaylist.Tracks[1].Id); List tracksInDatabase = await dbContext.MusicTracks.ToListAsync(); + tracksInDatabase.Should().HaveCount(3); }); } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicReplaceToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicReplaceToManyRelationshipTests.cs index a4fab39fd5..29074f742c 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicReplaceToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Relationships/AtomicReplaceToManyRelationshipTests.cs @@ -28,7 +28,7 @@ public AtomicReplaceToManyRelationshipTests(ExampleIntegrationTestContext } [Fact] - public async Task Can_clear_HasManyThrough_relationship() + public async Task Can_clear_ManyToMany_relationship() { // Arrange Playlist existingPlaylist = _fakers.Playlist.Generate(); - - existingPlaylist.PlaylistMusicTracks = new List - { - new() - { - MusicTrack = _fakers.MusicTrack.Generate() - }, - new() - { - MusicTrack = _fakers.MusicTrack.Generate() - } - }; + existingPlaylist.Tracks = _fakers.MusicTrack.Generate(2); await _testContext.RunOnDatabaseAsync(async dbContext => { @@ -135,26 +124,18 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(existingPlaylist.Id); + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(existingPlaylist.Id); - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore - - playlistInDatabase.PlaylistMusicTracks.Should().BeEmpty(); + playlistInDatabase.Tracks.Should().BeEmpty(); List tracksInDatabase = await dbContext.MusicTracks.ToListAsync(); + tracksInDatabase.Should().HaveCount(2); }); } [Fact] - public async Task Can_replace_HasMany_relationship() + public async Task Can_replace_OneToMany_relationship() { // Arrange MusicTrack existingTrack = _fakers.MusicTrack.Generate(); @@ -224,18 +205,11 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_replace_HasManyThrough_relationship() + public async Task Can_replace_ManyToMany_relationship() { // Arrange Playlist existingPlaylist = _fakers.Playlist.Generate(); - - existingPlaylist.PlaylistMusicTracks = new List - { - new() - { - MusicTrack = _fakers.MusicTrack.Generate() - } - }; + existingPlaylist.Tracks = _fakers.MusicTrack.Generate(1); List existingTracks = _fakers.MusicTrack.Generate(2); @@ -289,22 +263,14 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(existingPlaylist.Id); + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(existingPlaylist.Id); - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore - - playlistInDatabase.PlaylistMusicTracks.Should().HaveCount(2); - playlistInDatabase.PlaylistMusicTracks.Should().ContainSingle(playlistMusicTrack => playlistMusicTrack.MusicTrack.Id == existingTracks[0].Id); - playlistInDatabase.PlaylistMusicTracks.Should().ContainSingle(playlistMusicTrack => playlistMusicTrack.MusicTrack.Id == existingTracks[1].Id); + playlistInDatabase.Tracks.Should().HaveCount(2); + playlistInDatabase.Tracks.Should().ContainSingle(musicTrack => musicTrack.Id == existingTracks[0].Id); + playlistInDatabase.Tracks.Should().ContainSingle(musicTrack => musicTrack.Id == existingTracks[1].Id); List tracksInDatabase = await dbContext.MusicTracks.ToListAsync(); + tracksInDatabase.Should().HaveCount(3); }); } diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicReplaceToManyRelationshipTests.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicReplaceToManyRelationshipTests.cs index a2f7b4c0ba..c1331532fe 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicReplaceToManyRelationshipTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Updating/Resources/AtomicReplaceToManyRelationshipTests.cs @@ -28,7 +28,7 @@ public AtomicReplaceToManyRelationshipTests(ExampleIntegrationTestContext } [Fact] - public async Task Can_clear_HasManyThrough_relationship() + public async Task Can_clear_ManyToMany_relationship() { // Arrange Playlist existingPlaylist = _fakers.Playlist.Generate(); - - existingPlaylist.PlaylistMusicTracks = new List - { - new() - { - MusicTrack = _fakers.MusicTrack.Generate() - }, - new() - { - MusicTrack = _fakers.MusicTrack.Generate() - } - }; + existingPlaylist.Tracks = _fakers.MusicTrack.Generate(2); await _testContext.RunOnDatabaseAsync(async dbContext => { @@ -145,26 +134,18 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(existingPlaylist.Id); + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(existingPlaylist.Id); - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore - - playlistInDatabase.PlaylistMusicTracks.Should().BeEmpty(); + playlistInDatabase.Tracks.Should().BeEmpty(); List tracksInDatabase = await dbContext.MusicTracks.ToListAsync(); + tracksInDatabase.Should().HaveCount(2); }); } [Fact] - public async Task Can_replace_HasMany_relationship() + public async Task Can_replace_OneToMany_relationship() { // Arrange MusicTrack existingTrack = _fakers.MusicTrack.Generate(); @@ -239,18 +220,11 @@ await _testContext.RunOnDatabaseAsync(async dbContext => } [Fact] - public async Task Can_replace_HasManyThrough_relationship() + public async Task Can_replace_ManyToMany_relationship() { // Arrange Playlist existingPlaylist = _fakers.Playlist.Generate(); - - existingPlaylist.PlaylistMusicTracks = new List - { - new() - { - MusicTrack = _fakers.MusicTrack.Generate() - } - }; + existingPlaylist.Tracks = _fakers.MusicTrack.Generate(1); List existingTracks = _fakers.MusicTrack.Generate(2); @@ -309,22 +283,14 @@ await _testContext.RunOnDatabaseAsync(async dbContext => await _testContext.RunOnDatabaseAsync(async dbContext => { - // @formatter:wrap_chained_method_calls chop_always - // @formatter:keep_existing_linebreaks true - - Playlist playlistInDatabase = await dbContext.Playlists - .Include(playlist => playlist.PlaylistMusicTracks) - .ThenInclude(playlistMusicTrack => playlistMusicTrack.MusicTrack) - .FirstWithIdAsync(existingPlaylist.Id); + Playlist playlistInDatabase = await dbContext.Playlists.Include(playlist => playlist.Tracks).FirstWithIdAsync(existingPlaylist.Id); - // @formatter:keep_existing_linebreaks restore - // @formatter:wrap_chained_method_calls restore - - playlistInDatabase.PlaylistMusicTracks.Should().HaveCount(2); - playlistInDatabase.PlaylistMusicTracks.Should().ContainSingle(playlistMusicTrack => playlistMusicTrack.MusicTrack.Id == existingTracks[0].Id); - playlistInDatabase.PlaylistMusicTracks.Should().ContainSingle(playlistMusicTrack => playlistMusicTrack.MusicTrack.Id == existingTracks[1].Id); + playlistInDatabase.Tracks.Should().HaveCount(2); + playlistInDatabase.Tracks.Should().ContainSingle(musicTrack => musicTrack.Id == existingTracks[0].Id); + playlistInDatabase.Tracks.Should().ContainSingle(musicTrack => musicTrack.Id == existingTracks[1].Id); List tracksInDatabase = await dbContext.MusicTracks.ToListAsync(); + tracksInDatabase.Should().HaveCount(3); }); } From 20bef559f79470cef12aa8e1aced7ee5baa57a12 Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Fri, 23 Jul 2021 17:37:59 +0200 Subject: [PATCH 06/15] Updated BlogPost.Labels relationship in IntegrationTests to use native many-to-many --- .../IntegrationTests/QueryStrings/BlogPost.cs | 6 +- .../QueryStrings/BlogPostLabel.cs | 14 ---- .../Filtering/FilterDepthTests.cs | 65 +++++----------- .../QueryStrings/Includes/IncludeTests.cs | 38 +++------- .../IntegrationTests/QueryStrings/Label.cs | 6 +- .../PaginationWithTotalCountTests.cs | 61 ++++----------- .../QueryStrings/QueryStringDbContext.cs | 7 -- .../QueryStrings/Sorting/SortTests.cs | 74 +++++-------------- .../SparseFieldSets/SparseFieldSetTests.cs | 28 +++---- 9 files changed, 77 insertions(+), 222 deletions(-) delete mode 100644 test/JsonApiDotNetCoreExampleTests/IntegrationTests/QueryStrings/BlogPostLabel.cs diff --git a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/QueryStrings/BlogPost.cs b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/QueryStrings/BlogPost.cs index 8805bda98a..7254233f80 100644 --- a/test/JsonApiDotNetCoreExampleTests/IntegrationTests/QueryStrings/BlogPost.cs +++ b/test/JsonApiDotNetCoreExampleTests/IntegrationTests/QueryStrings/BlogPost.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; using JetBrains.Annotations; using JsonApiDotNetCore.Resources; using JsonApiDotNetCore.Resources.Annotations; @@ -21,12 +20,9 @@ public sealed class BlogPost : Identifiable [HasOne] public WebAccount Reviewer { get; set; } - [NotMapped] - [HasManyThrough(nameof(BlogPostLabels))] + [HasMany] public ISet