-
-
Notifications
You must be signed in to change notification settings - Fork 159
Description
DESCRIPTION
Using backing fields, EF Core supports read-only navigation properties (e.g., Children
) as follows (using a variation of the TestResource
class already used in issue #1090 to demonstrate the constructor binding issue):
public class TestResource : Identifiable
{
// Added backing field for navigation property.
private readonly HashSet<TestResource> _children = new();
// Same as before.
[Attr]
public string Name { get; set; }
// Same as before.
public int? ParentId { get; set; }
// Same as before.
[HasOne]
public TestResource Parent { get; set; }
// Changed type, made read-only and return _children.
[HasMany]
public IReadOnlyCollection<TestResource> Children
{
get => _children;
// Setter required by JADNC (but not EF Core per se). Uncomment to fix the issue.
// private init => _children = (HashSet<TestResource>) value;
}
// Added method to add items to _children backing field.
public void Add(TestResource item)
{
_children.Add(item);
item.Parent = this;
item.ParentId = Id;
}
}
Using EF core directly, it is possible to use the Children
navigation property to retrieve the children of a "Root" resource, for example (see also the unit test in #1090):
public class RelationalDbIntegrationTests
{
[Fact]
public async Task TestRelationalDatabaseAsync()
{
await using (var context = new RelationalDbContext())
{
await context.Database.EnsureDeletedAsync().ConfigureAwait(false);
await context.Database.MigrateAsync().ConfigureAwait(false);
// This is the change required for the new API
var root = new TestResource { Name = "Root" };
root.Add(new TestResource { Name = "First" });
root.Add(new TestResource { Name = "Second" });
context.Add(root);
await context.SaveChangesAsync().ConfigureAwait(false);
}
await using (var context = new RelationalDbContext())
{
// Establish that we can read the resource using EF core.
TestResource resource = await context.TestResources
.Include(testResource => testResource.Children)
.SingleAsync(testResource => testResource.Name == "Root");
Assert.NotEmpty(resource.Children);
}
}
}
However, when using JADNC, the following request will not include any children:
https://localhost:5001/TestResources?include=children
When uncommenting private init => _children = (HashSet<TestResource>) value;
as indicated above, everything works as desired (children are returned).
STEPS TO REPRODUCE
- Change the
TestResource
class as indicated above (without uncommenting the setter/initializer). - Run the unit test described above to confirm children are indeed returned by EF Core.
- Issue the above request (
https://localhost:5001/TestResources?include=children
) and note that no children are included. - Uncomment the setter/initializer. Run the unit test to confirm children are still returned by EF Core. Issue the above request again and note that children are now returned as expected.
EXPECTED BEHAVIOR
JADNC supports read-only navigation properties with backing fields.
ACTUAL BEHAVIOR
JADNC supports requires at least a private initializer or setter.
VERSIONS USED
- JsonApiDotNetCore version: 4.2.0
- ASP.NET Core version: 5.0.10
- Entity Framework Core version: 5.0.10
- Database provider: SQL Server Express LocalDb