Skip to content

Commit 47a73ac

Browse files
committed
test(acceptance): reproduce issue #78
1 parent f196dae commit 47a73ac

File tree

8 files changed

+208
-0
lines changed

8 files changed

+208
-0
lines changed

src/JsonApiDotNetCoreExample/Data/AppDbContext.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,19 @@ public AppDbContext(DbContextOptions<AppDbContext> options)
99
: base(options)
1010
{ }
1111

12+
protected override void OnModelCreating(ModelBuilder modelBuilder)
13+
{
14+
modelBuilder.Entity<TodoItem>()
15+
.HasOne(t => t.Assignee)
16+
.WithMany(p => p.AssignedTodoItems)
17+
.HasForeignKey(t => t.AssigneeId);
18+
19+
modelBuilder.Entity<TodoItem>()
20+
.HasOne(t => t.Owner)
21+
.WithMany(p => p.TodoItems)
22+
.HasForeignKey(t => t.OwnerId);
23+
}
24+
1225
public DbSet<TodoItem> TodoItems { get; set; }
1326
public DbSet<Person> People { get; set; }
1427
public DbSet<TodoItemCollection> TodoItemCollections { get; set; }

src/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.1" />
2929
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.1" />
3030
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.0.0" />
31+
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.0" />
3132
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="1.1.0" />
3233
<PackageReference Include="DotNetCoreDocs" Version="0.4.0" />
3334
</ItemGroup>

src/JsonApiDotNetCoreExample/Migrations/20170330020650_AddAssignedTodoItems.Designer.cs

Lines changed: 100 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Microsoft.EntityFrameworkCore.Migrations;
4+
5+
namespace JsonApiDotNetCoreExample.Migrations
6+
{
7+
public partial class AddAssignedTodoItems : Migration
8+
{
9+
protected override void Up(MigrationBuilder migrationBuilder)
10+
{
11+
migrationBuilder.AddColumn<int>(
12+
name: "AssigneeId",
13+
table: "TodoItems",
14+
nullable: true);
15+
16+
migrationBuilder.CreateIndex(
17+
name: "IX_TodoItems_AssigneeId",
18+
table: "TodoItems",
19+
column: "AssigneeId");
20+
21+
migrationBuilder.AddForeignKey(
22+
name: "FK_TodoItems_People_AssigneeId",
23+
table: "TodoItems",
24+
column: "AssigneeId",
25+
principalTable: "People",
26+
principalColumn: "Id",
27+
onDelete: ReferentialAction.Restrict);
28+
}
29+
30+
protected override void Down(MigrationBuilder migrationBuilder)
31+
{
32+
migrationBuilder.DropForeignKey(
33+
name: "FK_TodoItems_People_AssigneeId",
34+
table: "TodoItems");
35+
36+
migrationBuilder.DropIndex(
37+
name: "IX_TodoItems_AssigneeId",
38+
table: "TodoItems");
39+
40+
migrationBuilder.DropColumn(
41+
name: "AssigneeId",
42+
table: "TodoItems");
43+
}
44+
}
45+
}

src/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ protected override void BuildModel(ModelBuilder modelBuilder)
3535
b.Property<int>("Id")
3636
.ValueGeneratedOnAdd();
3737

38+
b.Property<int?>("AssigneeId");
39+
3840
b.Property<Guid?>("CollectionId");
3941

4042
b.Property<string>("Description");
@@ -45,6 +47,8 @@ protected override void BuildModel(ModelBuilder modelBuilder)
4547

4648
b.HasKey("Id");
4749

50+
b.HasIndex("AssigneeId");
51+
4852
b.HasIndex("CollectionId");
4953

5054
b.HasIndex("OwnerId");
@@ -70,6 +74,10 @@ protected override void BuildModel(ModelBuilder modelBuilder)
7074

7175
modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItem", b =>
7276
{
77+
b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Assignee")
78+
.WithMany("AssignedTodoItems")
79+
.HasForeignKey("AssigneeId");
80+
7381
b.HasOne("JsonApiDotNetCoreExample.Models.TodoItemCollection", "Collection")
7482
.WithMany("TodoItems")
7583
.HasForeignKey("CollectionId");

src/JsonApiDotNetCoreExample/Models/Person.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ public class Person : Identifiable, IHasMeta
1515

1616
[HasMany("todo-items")]
1717
public virtual List<TodoItem> TodoItems { get; set; }
18+
19+
[HasMany("assigned-todo-items")]
20+
public virtual List<TodoItem> AssignedTodoItems { get; set; }
1821

1922
[HasMany("todo-item-collections")]
2023
public virtual List<TodoItemCollection> TodoItemCollections { get; set; }

src/JsonApiDotNetCoreExample/Models/TodoItem.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@ public class TodoItem : Identifiable
1212
public long Ordinal { get; set; }
1313

1414
public int? OwnerId { get; set; }
15+
public int? AssigneeId { get; set; }
1516
public Guid? CollectionId { get; set; }
1617

1718
[HasOne("owner")]
1819
public virtual Person Owner { get; set; }
1920

21+
[HasOne("assignee")]
22+
public virtual Person Assignee { get; set; }
23+
2024
[HasOne("collection")]
2125
public virtual TodoItemCollection Collection { get; set; }
2226
}

test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,40 @@ public async Task GET_Included_Contains_SideloadedData_OneToMany()
134134
Assert.Equal(documents.Data.Count, documents.Included.Count);
135135
}
136136

137+
[Fact]
138+
public async Task GET_Included_DoesNot_Duplicate_Records_ForMultipleRelationshipsOfSameType()
139+
{
140+
// arrange
141+
_context.People.RemoveRange(_context.People); // ensure all people have todo-items
142+
_context.TodoItems.RemoveRange(_context.TodoItems);
143+
var person = _personFaker.Generate();
144+
var todoItem = _todoItemFaker.Generate();
145+
todoItem.Owner = person;
146+
todoItem.Assignee = person;
147+
_context.TodoItems.Add(todoItem);
148+
_context.SaveChanges();
149+
150+
var builder = new WebHostBuilder()
151+
.UseStartup<Startup>();
152+
153+
var httpMethod = new HttpMethod("GET");
154+
var route = $"/api/v1/todo-items/{todoItem.Id}?include=owner&include=assignee";
155+
156+
var server = new TestServer(builder);
157+
var client = server.CreateClient();
158+
var request = new HttpRequestMessage(httpMethod, route);
159+
160+
// act
161+
var response = await client.SendAsync(request);
162+
var documents = JsonConvert.DeserializeObject<Document>(await response.Content.ReadAsStringAsync());
163+
var data = documents.Data;
164+
165+
// assert
166+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
167+
Assert.NotEmpty(documents.Included);
168+
Assert.Equal(1, documents.Included.Count);
169+
}
170+
137171
[Fact]
138172
public async Task GET_ById_Included_Contains_SideloadedData_ForOneToMany()
139173
{

0 commit comments

Comments
 (0)