Skip to content

Commit 638a603

Browse files
author
Bart Koelman
authored
Fix for building LINQ Select clause on many-to-many includes (#869)
1 parent 9cfd976 commit 638a603

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed

src/Examples/JsonApiDotNetCoreExample/Models/Tag.cs

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Collections.Generic;
2+
using System.ComponentModel.DataAnnotations.Schema;
13
using JsonApiDotNetCore.Resources;
24
using JsonApiDotNetCore.Resources.Annotations;
35

@@ -10,6 +12,11 @@ public class Tag : Identifiable
1012

1113
[Attr]
1214
public TagColor Color { get; set; }
15+
16+
[NotMapped]
17+
[HasManyThrough(nameof(ArticleTags))]
18+
public ISet<Article> Articles { get; set; }
19+
public ISet<ArticleTag> ArticleTags { get; set; }
1320
}
1421

1522
public enum TagColor

src/JsonApiDotNetCore/Queries/Internal/QueryableBuilding/SelectClauseBuilder.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public Expression ApplySelect(IDictionary<ResourceFieldAttribute, QueryLayer> se
6161
private Expression CreateLambdaBodyInitializer(IDictionary<ResourceFieldAttribute, QueryLayer> selectors, ResourceContext resourceContext,
6262
LambdaScope lambdaScope, bool lambdaAccessorRequiresTestForNull)
6363
{
64-
var propertySelectors = ToPropertySelectors(selectors, resourceContext, lambdaScope.Parameter.Type);
64+
var propertySelectors = ToPropertySelectors(selectors, resourceContext, lambdaScope.Accessor.Type);
6565
MemberBinding[] propertyAssignments = propertySelectors.Select(selector => CreatePropertyAssignment(selector, lambdaScope)).Cast<MemberBinding>().ToArray();
6666

6767
NewExpression newExpression = _resourceFactory.CreateNewExpression(lambdaScope.Accessor.Type);

test/JsonApiDotNetCoreExampleTests/IntegrationTests/Includes/IncludeTests.cs

+45
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,51 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
329329
responseDocument.Included[0].Attributes["name"].Should().Be(article.ArticleTags.Single().Tag.Name);
330330
}
331331

332+
[Fact]
333+
public async Task Can_include_HasManyThrough_relationship_in_secondary_resource()
334+
{
335+
// Arrange
336+
var article = new Article
337+
{
338+
Caption = "One",
339+
ArticleTags = new HashSet<ArticleTag>
340+
{
341+
new ArticleTag
342+
{
343+
Tag = new Tag
344+
{
345+
Name = "Hot"
346+
}
347+
}
348+
}
349+
};
350+
351+
await _testContext.RunOnDatabaseAsync(async dbContext =>
352+
{
353+
dbContext.Articles.Add(article);
354+
355+
await dbContext.SaveChangesAsync();
356+
});
357+
358+
var route = $"/api/v1/articles/{article.StringId}/tags?include=articles";
359+
360+
// Act
361+
var (httpResponse, responseDocument) = await _testContext.ExecuteGetAsync<Document>(route);
362+
363+
// Assert
364+
httpResponse.Should().HaveStatusCode(HttpStatusCode.OK);
365+
366+
responseDocument.ManyData.Should().HaveCount(1);
367+
responseDocument.ManyData[0].Type.Should().Be("tags");
368+
responseDocument.ManyData[0].Id.Should().Be(article.ArticleTags.ElementAt(0).Tag.StringId);
369+
responseDocument.ManyData[0].Attributes["name"].Should().Be(article.ArticleTags.Single().Tag.Name);
370+
371+
responseDocument.Included.Should().HaveCount(1);
372+
responseDocument.Included[0].Type.Should().Be("articles");
373+
responseDocument.Included[0].Id.Should().Be(article.StringId);
374+
responseDocument.Included[0].Attributes["caption"].Should().Be(article.Caption);
375+
}
376+
332377
[Fact]
333378
public async Task Can_include_chain_of_HasOne_relationships()
334379
{

0 commit comments

Comments
 (0)