HasQueryFilter cannot translate query including mapped entity - entity-framework

Adding a query filter to the Tag entity to filter for a given tenant raises an error. I have provided some snippets below, which indicates most of the logic regarding the issue. The entity is mapped and the database reflects the entities correctly (with a foreign key on the Tag entity to Tenant).
DbContext
public string TenantName { get; } = "TenantName"
public DbSet<Tenant> Tenants { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Tag>().HasQueryFilter(t => t.Tenant.Name == TenantName);
}
Tag
public class Tag
{
public static string[] DefaultTags { get; } = { "Preparation" };
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[MaxLength(30)]
public string Value { get; set; }
[Required]
public bool IsReadonly { get; set; }
[Required]
public Tenant Tenant { get; }
public List<DrillVideo> DrillVideos { get; set; } = new List<DrillVideo>();
public Tag() { }
public Tag(Tenant tenant, string value, bool isReadonly = false)
{
Tenant = tenant;
Value = value;
IsReadonly = isReadonly;
}
Tenant
public class Tenant
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
[MaxLength(500)]
public string? WelcomeText { get; set; }
[MaxLength(280)]
public string? PracticalInformation { get; set; }
[MaxLength(254)]
public string? ContactEmail { get; set; }
[MaxLength(35)]
public string? ContactPhoneNumber { get; set; }
public List<User> Users { get; set; } = new List<User>();
public List<Tag> Tags { get; set; } = new List<Tag>();
public Tenant() { }
public Tenant(string name, string? welcomeText = null, int? id = null, string? practicalInformation = null, string? contactEmail = null, string? contactPhoneNumber = null)
: this()
{
Name = name;
if (id != null)
Id = (int)id;
WelcomeText = welcomeText;
PracticalInformation = practicalInformation;
ContactEmail = contactEmail;
ContactPhoneNumber = contactPhoneNumber;
}
}
I Get the following error:
System.InvalidOperationException: The LINQ expression 'DbSet<Tag>()
.Where(t => t.Tenant.Name == "localhost")' could not be translated. Additional information: Translation of member 'Tenant' on entity type 'Tag' failed. This commonly occurs when the specified member is unmapped.
Translation of member 'Tenant' on entity type 'Tag' failed. This commonly occurs when the specified member is unmapped. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.<VisitMethodCall>g__CheckTranslated|15_0(ShapedQueryExpression translated, <>c__DisplayClass15_0& )
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at InstructrApi.Services.DrillVideoService.AddAsync(String vimeoLink, IEnumerable`1 tags) in C:\GitRepos\backend\InstructrApi\Services\DrillVideoService.cs:line 54
at InstructrApi.Controllers.DrillVideoController.AddNewDrillVideo(AddDrillVideoDto dto) in C:\GitRepos\backend\InstructrApi\Controllers\DrillVideoController.cs:line 37
at lambda_method135(Closure , Object )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
HEADERS
=======
Accept: application/json, text/plain, */*
Host: localhost:5001
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1
:method: POST
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjVkMzQwZGRiYzNjNWJhY2M0Y2VlMWZiOWQxNmU5ODM3ZWM2MTYzZWIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vaW5zdHJ1Y3RyLWRldiIsImF1ZCI6Imluc3RydWN0ci1kZXYiLCJhdXRoX3RpbWUiOjE2NjYwMDc1MjksInVzZXJfaWQiOiJOQXdsMUU5a1RNV3lFYnJJNFl3UUNoY2lxenYyIiwic3ViIjoiTkF3bDFFOWtUTVd5RWJySTRZd1FDaGNpcXp2MiIsImlhdCI6MTY2NjAxMTEyMSwiZXhwIjoxNjY2MDE0NzIxLCJlbWFpbCI6ImFkbWluQGxvY2FsLmRrIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJmaXJlYmFzZSI6eyJpZGVudGl0aWVzIjp7ImVtYWlsIjpbImFkbWluQGxvY2FsLmRrIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.2wiTVyEf869sSmhLBoMYNalwMzfImCmc6_B94SdXurT7VFKDPVM3wvfDZ117MDF83CPMSUFRvGWYLQRx03ChRBhGU6oxJ8yLHrQLcDeLoknmdp_xUTDfhUI54DZ39NIVn1WBHzr63AwprvQMfJA8buN0u9mGCgPktP1vgT19iPbgmlHIaqI-gONPjI7WjW16c1Wz12wKRHWqBVLOJ0vDfGvvS4zY-KLIVXJXLORrVN8sNWAKOaM8a3g1P5qAHCBKxA3-rmNcueJ3jVev3UMefXO642AH464Nu-N6OHykyvXCGrIBJ3B7qzLrzbxdOd_HiT7ElE04GdfBJED8m8263Q
Content-Type: application/json
Origin: http://localhost:3000
Referer: http://localhost:3000/
Content-Length: 27
sec-gpc: 1
sec-fetch-site: cross-site
sec-fetch-mode: cors
sec-fetch-dest: empty
The entity is mapped. Why do I get the error anyways?

The problem is that there is no setter for the Tenant property on the Tag entity.
Adding a setter to the Tenant property on the Tag entity fixed the issue.
Before:
public class Tag
{
...
public Tenant Tenant { get; }
...
}
After
public class Tag
{
...
public Tenant Tenant { get; set; }
...
}

Related

Many to Many Relation with EF 6 CRUD

I'm New to EntityFrame work, and I'm Just trying to get experience by working on projects, I searched a lot on the web but unfortunately there is no much example about this for EF6.
I have 2 tables Movie and Actor with many to many relationship as below:
Actor Model:
public class Actor
{
public int Id { get; set; }
[StringLength(50)]
public string Name { get; set; }
[StringLength(50)]
public string Nationality { get; set; }
public DateTime BOD { get; set; }
// RelationShip
public virtual ICollection<Movie> Movies { get; set; }
}
Movie Model:
public class Movie
{
public int Id { get; set; }
[StringLength(50)]
public string Title { get; set; }
[StringLength(250)]
public string Description { get; set; }
public GenresEnum Genre { get; set; }
public int ReleasedYear { get; set; }
public string PosterUrl { get; set; }
// RelationShip
public virtual ICollection<Actor> Actors { get; set; }
}
I'm trying to add data to the Movie and I need to add the movie data and multiple actor (each movie have more than one actor) so I created a DTO called MovieRequestDto
public class MovieRequestDto
{
public string Title { get; set; }
public string Description { get; set; }
public GenresEnum Genre { get; set; }
public int ReleasedYear { get; set; }
public string PosterUrl { get; set; }
//// RelationShip
public List<int> ActorsId { get; set; }
}
What I'm thinking of is to insert the data to Movie then get the list of ActorId from the dto and insert the data to join table MovieActor , I tried doing it by also creating Movie_Actor Model and add it to AppDBContext also mapping it using fluent API as Bellow:
AppDbContext:
using Microsoft.EntityFrameworkCore;
using MovieApp.Core.Models;
namespace MovieApp.EF.Data
{
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Movie_Actor>()
.HasOne(m => m.Movie)
.WithMany(ma => ma.Movie_Actors)
.HasForeignKey(m => m.MovieId);
modelBuilder.Entity<Movie_Actor>()
.HasOne(a => a.Actor)
.WithMany(am => am.Movie_Actors)
.HasForeignKey(a => a.ActorId);
}
public DbSet<Movie> Movies { get; set; }
public DbSet<Actor> Actors { get; set; }
public DbSet<Movie_Actor> movie_Actors { get; set; }
}
}
Movie_Actor Model:
public class Movie_Actor
{
public int Id { get; set; }
public int MovieId { get; set; }
public Movie Movie { get; set; }
public int ActorId { get; set; }
public Actor Actor { get; set; }
}
And this is the POST :
[HttpPost]
public async Task<IActionResult> Post(MovieRequestDto dto)
{
var movie = new Movie();
movie.Title = dto.Title;
movie.Description = dto.Description;
movie.Genre = dto.Genre;
movie.ReleasedYear = dto.ReleasedYear;
movie.PosterUrl = dto.PosterUrl;
movie.ProducerId = dto.ProducerId;
await _context.Movies.AddAsync(movie);
await _context.SaveChangesAsync();
foreach (var ActorId in dto.ActorsId)
{
var movie_actor = new Movie_Actor();
movie_actor.MovieId = movie.Id;
movie_actor.ActorId = ActorId;
await _context.movie_Actors.AddAsync(movie_actor);
}
await _context.SaveChangesAsync();
return Ok();
}
This way is not working, And I think I don't need to use this way because the EF6 can handle the mapping by it self without doing it manually, So what is the best way to do the CRUD for one to many relation with the latest EF 6.
I'm Getting this Error:
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
---> Microsoft.Data.SqlClient.SqlException (0x80131904): Invalid object name 'movie_Actors'.
at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__188_0(Task`1 result)
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
ClientConnectionId:c6f722d2-d86e-453b-8855-da3c87fe20ed
Error Number:208,State:1,Class:16
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at MovieApp.API.Controllers.MoviesController.Post(MovieRequestDto dto) in C:\Users\AppiaTech-RQab\source\repos\MovieApp\MovieApp.API\Controllers\MoviesController.cs:line 90
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Host: localhost:7050
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36
:method: POST
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Content-Type: application/json
Origin: https://localhost:7050
Referer: https://localhost:7050/swagger/index.html
Content-Length: 158
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
sec-fetch-site: same-origin
sec-fetch-mode: cors
sec-fetch-dest: empty
it is better to do everytnig in one transaction, otherwise your data integrity can be damaged. Try this
var movie = new Movie();
movie.Title = dto.Title;
movie.Description = dto.Description;
movie.Genre = dto.Genre;
movie.ReleasedYear = dto.ReleasedYear;
movie.PosterUrl = dto.PosterUrl;
movie.ProducerId = dto.ProducerId;
foreach (var ActorId in dto.ActorsId)
{
var movie_actor = new Movie_Actor();
movie_actor.Movie = movie;
movie_actor.ActorId = ActorId;
_context.movie_Actors.Add(movie_actor);
}
await _context.SaveChangesAsync();
UPDATE
according to your error message you have to map movie_Actors class to a db table too, since apparently they have different names.

IndexOutOfRangeException when retrieving models from repository

I'm getting this exception:
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at lambda_method(Closure , ValueBuffer )
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalMixedEntityEntry..ctor(IStateManager stateManager, IEntityType entityType, Object entity, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryFactory.NewInternalEntityEntry(IStateManager stateManager, IEntityType entityType, Object entity, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTrackingFromQuery(IEntityType baseEntityType, Object entity, ValueBuffer& valueBuffer, ISet`1 handledForeignKeys)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityTrackingInfo.StartTracking(IStateManager stateManager, Object entity, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.StartTracking(Object entity, EntityTrackingInfo entityTrackingInfo)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.<>c__DisplayClass18_0`2.<_TrackEntities>b__0(TOut result)
at System.Linq.AsyncEnumerable.SelectEnumerableAsyncIterator`2.MoveNextCore(CancellationToken cancellationToken) in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\Select.cs:line 109
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 Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteSingletonAsyncQuery[TResult](QueryContext queryContext, Func`2 compiledQuery, IDiagnosticsLogger`1 logger, Type contextType)
at SuperChrono.Api.Controllers.UpdateController.GetAsync(Int32 id) in C:\Users\Albert\source\repos\Superchrono 2.0-v2\SuperChrono.Api\Controllers\UpdateController.cs:line 31
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.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIIndexMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Here's how UpdateController.GetAsync() looks like:
public async Task<IActionResult> GetAsync(int id)
{
var update = await _updateRepository.GetAsync(id); // 31st line
if (update == null)
return NotFound();
return Ok(new Responses.UpdateResponse { Update = update });
}
Here's the repository GetAsync():
public Task<Update> GetAsync(int id)
{
return _db.Updates.FirstOrDefaultAsync(u => u.Id == id);
}
...where _db is my DbContext. That's how it looks:
public class SuperChronoContext : DbContext
{
// (...)
public DbSet<Update> Updates { get; set; }
public SuperChronoContext(DbContextOptions options)
: base(options)
{
Database.EnsureCreated();
}
protected override void OnModelCreating(ModelBuilder builder)
{
// (...)
builder.Entity<Update>()
.Property<int>("ProjectId")
.HasColumnName("id_ProjectNode");
builder.Entity<Update>()
.Property<int>("UserId")
.HasColumnName("id_User");
builder.Entity<Update>()
.Property<int>("TypeId")
.HasColumnName("id_UpdateType");
}
}
That's how the model looks like:
public class Update
{
[Column("id_Update")]
public int Id { get; set; }
[Column("description")]
public string Description { get; set; }
/// <summary>
/// Duration of work on update in minutes.
/// </summary>
[Column("usedTime"), Required]
public int Time { get; set; }
/// <summary>
/// Additional duration of work on update in minutes.
/// </summary>
[Column("additionalTime"), Required]
public int AdditionalTime { get; set; }
[Column("updateDate", TypeName = "smalldatetime"), Required]
public DateTime Date { get; set; }
[Column("creationDate", TypeName = "smalldatetime"), Required]
public DateTime CreatedAt { get; set; }
[Column("id_ProjectNode"), Required]
public int ProjectId { get; set; }
//public virtual Project Project { get;set; }
[Column("id_User"), Required]
public int OwnerId { get; set; }
public virtual User Owner { get; set; }
[Column("id_UpdateType"), Required]
public int TypeId { get; set; }
//public virtual ProjectType Type { get; set; }
}
And finally, here's how my table looks like:
And I don't know where is my problem. I tried solutions I found on the Internet, but they just didn't help.
I have other models in my code and they work just fine. All code fetching those models from database throws me this error, not only GetAsync(int id) but also some other that does _db.Updates.ToListAsync().
Unit tests using an InMemoryDatabase pass just fine.
I'm struggling with this for the second day now.
In your OnModelCreating you declare :
builder.Entity<Update>()
.Property<int>("UserId")
.HasColumnName("id_User");
But in your Update class you have:
[Column("id_User"), Required]
public int OwnerId { get; set; }
UserId is not a property of your model.
A good way to avoid this kind of problems in the future is to use .Property(u => u.OwnerId) instead.

Webapi exception when Entity Framework has bidirectional associations

I've created entity framework 6 boilerplate code from a database using code first and I can retrieve my data fine and see all my tables in list objects just fine, so I know retrieval is fine and any lazy loading is working.
However when returning the list from a webapi rest service it only works for my simple class (BikeStation below) which has no associated lists, when I try my classes which have references to other objects, it generates an exception to do with data contracts and seems to be linked to circular references
Here are my classes:
public partial class BikeStation
{
public int Id { get; set; }
public string CentreName { get; set; }
public string StationName { get; set; }
}
public partial class Bike
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Bike()
{
BikeStats = new HashSet<BikeStat>();
}
public string ShortBikeName { get; set; }
public bool Active { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<BikeStat> BikeStats { get; set; }
}
public partial class BikeStat
{
public int Id { get; set; }
public DateTime StatDate { get; set; }
public virtual Bike Bike { get; set; }
}
This works:
public IEnumerable<BikeStation> Get()
{
using (var db = new BikesContext())
{
var a = db.BikeStations.ToList();
return a;
}
}
However, changing to either of the other two gets the list fine but then fails to serialise the data:
public IEnumerable<Bike> Get()
{
using (var db = new BikesContext())
{
var a = db.Bikes.ToList();
return a;
}
}
If I remove the reference to the bike or bikestats in either of my other classes, it works just fine.
The error is this, and I don't really understand why it's trying to serialise as XML either. Any help would be appreciated.
<Error><Message>An error has occurred.</Message><ExceptionMessage>The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.</ExceptionMessage><ExceptionType>System.InvalidOperationException</ExceptionType><StackTrace /><InnerException><Message>An error has occurred.</Message><ExceptionMessage>Type 'System.Data.Entity.DynamicProxies.Bike_16DB1847327CF3674DCB6407C4CCB0E41EA43002E17C91F35F5B4716F57DAD1D' with data contract name 'Bike_16DB1847327CF3674DCB6407C4CCB0E41EA43002E17C91F35F5B4716F57DAD1D:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.</ExceptionMessage><ExceptionType>System.Runtime.Serialization.SerializationException</ExceptionType><StackTrace> at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
at WriteArrayOfBikeToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , CollectionDataContract )
at System.Runtime.Serialization.CollectionDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType)
at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph)
at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content)
at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()</StackTrace></InnerException></Error>
I then changed my code to explicitly convert the code using a custom class, which works but isn't ideal:
var newData = d.Select(x => new Bike()
{
Active = x.Active,
ShortBikeName = x.ShortBikeName,
BikeStats = (x.BikeStats.Select(item => new BikeStat()
{
Id = item.Id,
StatDate = item.StatDate
}).ToList() as ICollection<BikeStat>)
}).ToList();
This works, but is a bit pants. So I changed the serialisation to this:
var d = db.Bikes.Include("BikeStats").ToList();
string s = JsonConvert.SerializeObject(d,
Formatting.Indented,
new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, PreserveReferencesHandling=PreserveReferencesHandling.Objects });
return s;
Which works, but it doesn't. It adds "\r\n" as a string to the response, turns all quote marks into \", puts '$' in front of some values and Chrome still thinks it's XML.
I changed the class to have this and it all magically works. Why? and is there a better way so that I can still access Bike from BikeStat?
[JsonIgnore]
public Bike Bike { get; set; }
Try Changing your code to look like this
public class BikeStation
{
public int Id { get; set; }
public string CentreName { get; set; }
public string StationName { get; set; }
}
public class Bike
{
public string ShortBikeName { get; set; }
public bool Active { get; set; }
public IEnumerable<BikeStat> BikeStats { get; set; }
}
public class BikeStat
{
public int Id { get; set; }
public DateTime StatDate { get; set; }
public Bike Bike { get; set; }
}

System.ArgumentNullException when using IncludeThen

I have an Code First model: I am attempting to use Include() and IncludeThen() and get a System.ArgumentNullException .
Here are the entities (let me know if you'd like more of the model):
public class Area
{
public Area()
{
Geocode = new List<Geocode>();
}
public int AreaId { get; set; }
public int InfoId { get; set; }
public string AreaDescription { get; set; }
public string Polygon { get; set; }
public string Circle { get; set; }
public List<Geocode> Geocode { get; set; }
public string Altitude { get; set; }
public string Ceiling { get; set; }
}
public class Geocode
{
public Geocode(string valueName, string value
)
{
ValueName = valueName;
Value = value;
}
public int GeocodeId { get; set; }
public int AreaId { get; set; }
public string ValueName { get; set; }
public string Value { get; set; }
}
Here is the calling code:
context.Alerts.Include(f => f.Infos)
.ThenInclude(f => f.Areas)
.ThenInclude(f => f.Geocode);// When I comment out this line it does not error, just doesn't load the Geocode navigation property.
Here is a stack trace:
at System.Linq.Expressions.Expression.New(ConstructorInfo constructor, IEnumerable1 arguments)
at Microsoft.Data.Entity.Metadata.Internal.EntityMaterializerSource.CreateMaterializeExpression(IEntityType entityType, Expression valueBufferExpression, Int32[] indexMap)
at Microsoft.Data.Entity.Query.ExpressionVisitors.Internal.MaterializerFactory.CreateMaterializer(IEntityType entityType, SelectExpression selectExpression, Func3 projectionAdder, IQuerySource querySource)
at Microsoft.Data.Entity.Query.ExpressionVisitors.Internal.IncludeExpressionVisitor.d__13.MoveNext()
at System.Collections.Generic.List1..ctor(IEnumerable1 collection)
at System.Dynamic.Utils.CollectionExtensions.ToReadOnly[T](IEnumerable1 enumerable)
at System.Linq.Expressions.Expression.NewArrayInit(Type type, IEnumerable1 initializers)
at Microsoft.Data.Entity.Query.ExpressionVisitors.Internal.IncludeExpressionVisitor.VisitMethodCall(MethodCallExpression expression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at Microsoft.Data.Entity.Query.ExpressionVisitors.ExpressionVisitorBase.Visit(Expression expression)
at Microsoft.Data.Entity.Query.RelationalQueryModelVisitor.IncludeNavigations(IncludeSpecification includeSpecification, Type resultType, LambdaExpression accessorLambda, Boolean querySourceRequiresTracking)
at Microsoft.Data.Entity.Query.EntityQueryModelVisitor.IncludeNavigations(QueryModel queryModel, IReadOnlyCollection1 includeSpecifications)
at Microsoft.Data.Entity.Query.RelationalQueryModelVisitor.IncludeNavigations(QueryModel queryModel, IReadOnlyCollection1 includeSpecifications)
at Microsoft.Data.Entity.Query.EntityQueryModelVisitor.IncludeNavigations(QueryModel queryModel)
at Microsoft.Data.Entity.Query.EntityQueryModelVisitor.CreateQueryExecutor[TResult](QueryModel queryModel)
at Microsoft.Data.Entity.Storage.Database.CompileQuery[TResult](QueryModel queryModel)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Data.Entity.Query.Internal.QueryCompiler.<>c__DisplayClass18_01.<CompileQuery>b__0()
at Microsoft.Data.Entity.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func1 compiler)
at Microsoft.Data.Entity.Query.Internal.QueryCompiler.CompileQuery[TResult](Expression query)
at Microsoft.Data.Entity.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at Microsoft.Data.Entity.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
at Remotion.Linq.QueryableBase1.GetEnumerator()
at Microsoft.Data.Entity.EntityFrameworkQueryableExtensions.IncludableQueryable2.GetEnumerator()
at WeatherMonitoringConsole.Program.<>c__DisplayClass0_0.<b__0>d.MoveNext() in C:\Users\ehasson\Source\Workspaces\Marketing\WeatherMonitoring\WeatherMonitoringConsole\Program.cs:line 32
The problem was I needed a default constructor on each entity.

Code First: Entity accessible in tests, but "not set to an instance of an object" outside of tests

I created an EF Code First Entity for a view in my database. I setup a test, and the access code works in my test, but when I run the code outside of the test, it throws "Object Reference not set to an instance of an object". I am stuck, as I cannot understand what could be causing the issue. Any ideas on why it's throwing an error?
Here is my entity class:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace PhoenixData.Models.DB
{
public partial class VW_ICD10MappingWithUsage
{
[Key]
[Column(Order = 0)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ProviderID { get; set; }
[StringLength(20)]
public string DxKey { get; set; }
[StringLength(100)]
public string Icd9Description { get; set; }
[StringLength(10)]
public string Code { get; set; }
[StringLength(2000)]
public string Description { get; set; }
public int? USAGE { get; set; }
[Key]
[Column(Order = 1)]
[StringLength(20)]
public string Region { get; set; }
public long? ProviderCodeCount { get; set; }
[NotMapped]
public IList<CodeProviderUsage> ChildUsages { get; set; }
public VW_ICD10MappingWithUsage()
{
ChildUsages = new List<CodeProviderUsage>();
}
}
}
Here is access code that throws the error:
using (var dbContext = new MyDatabase(_config.ConnectionString))
{
res = dbContext.VW_ICD10MappingWithUsage
.Where(x => x.ProviderID == providerId)
.OrderBy(x => x.DxKey)
.Take(pageSize)
.ToList();
}
And here is the stack trace:
at System.Object.GetType()
at System.Data.Entity.Core.EntityKey.ValidateTypeOfKeyValue(MetadataWorkspace workspace, EdmMember keyMember, Object keyValue, Boolean isArgumentException, String argumentName)
at System.Data.Entity.Core.EntityKey.ValidateEntityKey(MetadataWorkspace workspace, EntitySet entitySet, Boolean isArgumentException, String argumentName)
at System.Data.Entity.Core.Objects.ObjectStateManager.CheckKeyMatchesEntity(IEntityWrapper wrappedEntity, EntityKey entityKey, EntitySet entitySetForType, Boolean forAttach)
at System.Data.Entity.Core.Objects.ObjectStateManager.AddEntry(IEntityWrapper wrappedObject, EntityKey passedKey, EntitySet entitySet, String argumentName, Boolean isAdded)
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet)
at lambda_method(Closure , Shaper )
at System.Data.Entity.Core.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at PhoenixData.Core.ICD10.ICD10MappingRepository.SearchIcd10MappingWithUsages(Int32 pageSize, Int32 pageNumber, Int32 providerId, String orderByColumnName, String direction, String searchTerm, String searchColumns) in C:\Dev\PhoenixDriveServices\PhoenixData\Core\ICD10\ICD10MappingRepository.cs:line 149
The answer accepted by the OP is:
Is it possible then that one specific record causes the issue upon materialization? For example, one of your columns is not nullable in the model but it is nullable in the database and the actual value is null which confuses the materialization? In other words, try to narrow the issue to a specific row in the database.
It looks like that was it. One of the rows had null for one of composite key columns.