Skip to content

Commit

Permalink
Merge pull request #17 from AinoraZ/AZ/tests/collection-navigation
Browse files Browse the repository at this point in the history
Tests and Documentation for Collection Includes Issue
  • Loading branch information
AinoraZ authored Aug 3, 2022
2 parents 357767b + 2448746 commit f1bb8b0
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 12 deletions.
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Extension library for Entity Framework Core that tries to improve upon the ```In

EFCore.IncludeBuilder allows you to load sibling entities without going up the whole include structure.

```UseIncludeBuilder()``` syntax:
### ```UseIncludeBuilder()``` syntax

```csharp
dbContext.Users
Expand All @@ -26,7 +26,9 @@ dbContext.Users
.Build()
```

```Include(...).ThenInclude(...)``` syntax:
> ⚠️Caution: Autocomplete after List/Collection Includes is currently broken for VS and VSCode due to a bug in Roslyn. This is tracked by issue [#16](https://github.com/AinoraZ/EFCore.IncludeBuilder/issues/16). Regardless of autocomplete, **the code will still fully compile and work**.
### ```Include(...).ThenInclude(...)``` syntax

```csharp
dbContext.Users
Expand All @@ -48,7 +50,7 @@ dbContext.Users

Since IncludeBuilder uses the same ```Include(...)``` method signature for all levels, it is possible to write extension methods without depending on whether the includes are root level ```Include(...)``` on ```IQueryable``` or nested ```ThenInclude(...)``` on ```IIncludableQueryable```.

Extension method:
### Extension method

```csharp
public static TBuilder IncludeBlogChildren<TBase, TBuilder>(this IIncludeBuilder<TBase, Blog, TBuilder> blogBuilder)
Expand All @@ -63,7 +65,7 @@ public static TBuilder IncludeBlogChildren<TBase, TBuilder>(this IIncludeBuilder
}
```

Root level extension usage:
### Root level extension usage

```csharp
dbContext.Blogs
Expand All @@ -72,7 +74,7 @@ dbContext.Blogs
.Build();
```

Nested level extension usage:
### Nested level extension usage

```csharp
dbContext.Users
Expand All @@ -86,7 +88,7 @@ dbContext.Users

## How It Works

EFCore.IncludeBuilder converts the includes you give it back to ```Include(...).ThenInclude(...)``` calls, so it *should* support all the same providers and functionality as the original.
EFCore.IncludeBuilder converts the includes you give it back to ```Include(...).ThenInclude(...)``` calls, so it **_should_** support all the same providers and functionality as the original.

## Performance

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ namespace Ainoraz.EFCore.IncludeBuilder.Tests.Common.Models;
public class Blog
{
public Guid Id { get; set; }
public IEnumerable<Post> Posts { get; set; } = new List<Post>();
public List<Post> Posts { get; set; } = new List<Post>();
public Guid AuthorId { get; set; }
public User Author { get; set; } = null!;
public IEnumerable<User> Followers { get; set; } = new List<User>();
public List<User> Followers { get; set; } = new List<User>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ public class Post
public Blog Blog { get; set; } = null!;
public Guid AuthorId { get; set; }
public User Author { get; set; } = null!;
public IEnumerable<User> Readers { get; set; } = new List<User>();
public List<User> Readers { get; set; } = new List<User>();
public DateTime PostDate { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ public class User
{
public Guid Id { get; set; }

public IEnumerable<Blog> FollowingBlogs { get; set; } = new List<Blog>();
public IEnumerable<Post> ReadHistory { get; set; } = new List<Post>();
public List<Blog> FollowingBlogs { get; set; } = new List<Blog>();
public List<Post> ReadHistory { get; set; } = new List<Post>();
public Blog OwnedBlog { get; set; } = null!;
public IEnumerable<Post> Posts { get; set; } = new List<Post>();
public List<Post> Posts { get; set; } = new List<Post>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -385,4 +385,48 @@ public void DifferentIncludeChain_ShouldNotMatch()

actualQuery.Should().NotBe(expectedQuery).And.NotBeEmpty();
}

[Fact]
public void CollectionIncludeChain_ShouldMatch()
{
var actualQuery = testDbContext.Blogs
.UseIncludeBuilder()
.Include(b => b.Posts, builder => builder
.Include(p => p.Readers, builder => builder
.Include(r => r.Posts)
)
)
.Build()
.ToQueryString();

var expectedQuery = testDbContext.Blogs
.Include(b => b.Posts)
.ThenInclude(p => p.Readers)
.ThenInclude(r => r.Posts)
.ToQueryString();

actualQuery.Should().Be(expectedQuery).And.NotBeEmpty();
}

[Fact]
public void CollectionIncludeWithTypes_ShouldMatch()
{
var actualQuery = testDbContext.Blogs
.UseIncludeBuilder()
.Include((Blog b) => b.Posts, builder => builder
.Include((Post p) => p.Readers, builder => builder
.Include((User r) => r.Posts)
)
)
.Build()
.ToQueryString();

var expectedQuery = testDbContext.Blogs
.Include(b => b.Posts)
.ThenInclude(p => p.Readers)
.ThenInclude(r => r.Posts)
.ToQueryString();

actualQuery.Should().Be(expectedQuery).And.NotBeEmpty();
}
}

0 comments on commit f1bb8b0

Please sign in to comment.