Describe what is not working as expected.
I'm unable to query a nested collection with an IGeometry property, I get a NullReferenceException
If you are seeing an exception, include the full exceptions details (message and stack trace).
Exception message: Object reference not set to an instance of an object
Stack trace: at lambda_method(Closure , InternalEntityEntry )
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.OriginalValues..ctor(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.EnsureOriginalValues()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntrySubscriber.SnapshotAndSubscribe(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTrackingFromQuery(IEntityType baseEntityType, Object entity, ValueBuffer& valueBuffer, ISet`1 handledForeignKeys)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.StartTracking(Object entity, IEntityType entityType)
at lambda_method(Closure , QueryContext , Token , Object[] , CancellationToken )
at Microsoft.EntityFrameworkCore.Query.Internal.IncludeCompiler._IncludeAsync[TEntity](QueryContext queryContext, TEntity entity, Object[] included, Func`5 fixup, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.TaskLiftingExpressionVisitor._ExecuteAsync[T](IReadOnlyList`1 taskFactories, Func`2 selector)
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.AsyncSelectEnumerable`2.AsyncSelectEnumerator.MoveNext(CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.IncludeCollectionAsync[TEntity,TRelated,TElement](Int32 includeId, INavigation navigation, INavigation inverseNavigation, IEntityType targetEntityType, IClrCollectionAccessor clrCollectionAccessor,
IClrPropertySetter inverseClrPropertySetter, Boolean tracking, TEntity entity, Func`1 relatedEntitiesFactory, Func`3 joinPredicate, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.IncludeCompiler._IncludeAsync[TEntity](QueryContext queryContext, TEntity entity, Object[] included, Func`5 fixup, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.TaskLiftingExpressionVisitor._ExecuteAsync[T](IReadOnlyList`1 taskFactories, Func`2 selector)
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.AsyncSelectEnumerable`2.AsyncSelectEnumerator.MoveNext(CancellationToken cancellationToken)
at System.Linq.AsyncEnumerable.SelectEnumerableAsyncIterator`2.MoveNextCore(CancellationToken cancellationToken) in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\Select.cs:line 106
at System.Linq.AsyncEnumerable.AsyncIterator`1.MoveNext(CancellationToken cancellationToken) in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\AsyncIterator.cs:line 98
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext(CancellationToken cancellationToken)
at System.Linq.AsyncEnumerable.Aggregate_[TSource,TAccumulate,TResult](IAsyncEnumerable`1 source, TAccumulate seed, Func`3 accumulator, Func`2 resultSelector, CancellationToken cancellationToken) in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\Aggregate.c
s:line 120
at StandardAction.Campaigns.Services.LayerService.GetLayers(LayerSearchDto search) in B:\Standard Action\Standard Action\Campaigns\Services\LayerService.cs:line 57
at StandardAction.Campaigns.Controllers.LayerController.Get(LayerSearchDto search) in B:\Standard Action\Standard Action\Campaigns\Controllers\LayerController.cs:line 32
at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at System.Threading.Tasks.ValueTask`1.get_Result()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Try to query the type from the database (it is a nested entity). My code below is throwing on the call to ToListAsync(). The Tokens collection in the sample below has an IGeometry property added to it. The code below works correctly without that property.
```c#
var query = _context.Layers
.Include(l => l.Tokens).ThenInclude(t => t.Blob)
.Include(l => l.Tokens).ThenInclude(t => t.Character.ControlledBy)
.Include(l => l.Tokens).ThenInclude(t => t.Players)
.Include(l => l.Tokens).ThenInclude(t => t.Bars).ThenInclude(b => b.TokenBarCharacterAttribute.CharacterAttribute)
.Include(l => l.Tokens).ThenInclude(t => t.Bars).ThenInclude(b => b.StarfinderTokenBarAttribute.StarfinderAttribute)
.OrderBy(l => l.Order)
.AsQueryable();
if (!(await _auth.AuthorizeAsync(_user.User, Policies.AccessAllCampaignData)).Succeeded)
{
query = query.Where(l => l.Page.Chapter.Campaign.Players.Any(p => p.UserId == _user.UserId));
}
if (search.PageId != null)
{
query = query.Where(l => l.PageId == search.PageId);
}
var layers = await query.ToListAsync();
```
EF Core version: 2.2.0-preview2-35157
Database Provider: Microsoft.EntityFrameworkCore.SqlServer 2.2.0-preview2-35157
Operating system: Windows 10
IDE: Jetbrains Rider
Also, it does not crash if I add AsNoTracking to the query, but I need change tracking to stay enabled
@EricBourland I have not been able to reproduce this issue--my code is below. Could you post a runnable project/solution or complete code listing that demonstrates the behavior you are seeing?
```C#
public class Blog
{
public int Id { get; set; }
public ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public IGeometry Location { get; set; }
public Blog Blog { get; set; }
}
public class BloggingContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(
@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0",
b => b.UseNetTopologySuite());
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>();
}
}
public class Program
{
public static void Main()
{
using (var context = new BloggingContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var geometryFactory = new GeometryFactory();
context.Add(new Blog
{
Posts = new List<Post>
{
new Post { Location = geometryFactory.CreatePoint(new Coordinate(1.0, 2.0)) }
}
});
context.SaveChanges();
}
using (var context = new BloggingContext())
{
var blog = context.Set<Blog>().Include(e => e.Posts).ToList();
}
}
}
```
No, I have not been able to reproduce a small example of it either and the project is not open source and too big to post. Sorry, I don't know exactly what is causing it other than it's related to change tracking and it only happens when I add any spatial type (i tried IGeometry, Geometry, Polygon, and LineString)
I am able to repro the same exception and similar stack trace from Add() if I pass an object that has a null IGeometry:
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
at lambda_method(Closure , InternalEntityEntry )
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.OriginalValues..ctor(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.EnsureOriginalValues()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntrySubscriber.SnapshotAndSubscribe(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode node, Boolean force)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode node, TState state, Func`3 handleNode)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode node, TState state, Func`3 handleNode)
at Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState)
at Repro13457.Program.Main() in C:\Users\divega\source\repos\Repro13457\Repro13457\Program.cs:line 61
at Repro13457.Program.<Main>()
Repro code (modified from @ajcvickers's code, repros both with preview 2 and nightly builds, and both with IGeometry and Geometry):
``` c#
using System.Collections.Generic;
using GeoAPI.Geometries;
using Microsoft.EntityFrameworkCore;
using NetTopologySuite.Geometries;
namespace Repro13457
{
public class Blog
{
public int Id { get; set; }
public ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public IGeometry Location { get; set; }
public Blog Blog { get; set; }
}
public class BloggingContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(
@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0",
b => b.UseNetTopologySuite());
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>();
}
}
public class Program
{
public static void Main()
{
using (var context = new BloggingContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var geometryFactory = new GeometryFactory();
context.Add(new Blog
{
Posts = new List<Post>
{
new Post { }
}
});
}
}
}
}
```
Experiencing an issue adding an entity to a table with a nullable (as in db column) Point where it throws an exception at the exact same place in the code. Determined that setting the Point member to Point.Empty solves this, but does not solve the underlying issue of needing to have a null value in the database. I believe that the reason is due to Point not having a parameterless constructor. Can anyone confirm?
I was incorrect. Here's a little more information. Inside SnapshotFactoryFactory.CreateConstructorExpression(), the expression tree created to copy the values in the object for change tracking contains the following:
(NetTopologySuite.Geometries.Point).Call ($entity.GeoLocation).Copy(),
I believe this is where the NRE is occurring. Copy is a member of IGeometry - if the entity's member is null, Copy() would throw a NRE. This can probably be changed by modifying Microsoft.EntityFrameworkCore.ChangeTracking.GeometryValueComparer.GetSnapshotExpression().
@cculver Thanks for the analysis
I got it working by changing GetSnapshotExpression() as well as GetHashCodeExpression() and GetEqualsExpression() to check for nulls.
@cculver Would you consider submitting a pull request to fix this?
Yea...I did something terribly wrong with my PR and unfortunately don't have time to figure it out so I closed the issue. The modification is in there, however. Hopefully you can use that. If you're merging into the version that has GetHashCodeExpression(), the following lines are needed as well:
var checkNull = Expression.ReferenceEqual(instance, Expression.Constant(null));
var returnZero = Expression.Constant(0);
var body = Expression.Call(instance, typeof(object).GetRuntimeMethod("GetHashCode", Type.EmptyTypes));
var conditional = Expression.Condition(checkNull, returnZero, body);
return Expression.Lambda(conditional, instance);
Most helpful comment
I was incorrect. Here's a little more information. Inside SnapshotFactoryFactory.CreateConstructorExpression(), the expression tree created to copy the values in the object for change tracking contains the following:
(NetTopologySuite.Geometries.Point).Call ($entity.GeoLocation).Copy(),
I believe this is where the NRE is occurring. Copy is a member of IGeometry - if the entity's member is null, Copy() would throw a NRE. This can probably be changed by modifying Microsoft.EntityFrameworkCore.ChangeTracking.GeometryValueComparer.GetSnapshotExpression().