You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
InvalidOperationException thrown when saving changes: 'The value of xxx is unknown when attempting to save changes'. Regresion between 3.1 and 5.0
#23507
Closed
jotatoledo opened this issue
Nov 26, 2020
· 4 comments
The following code worked with Microsoft.EntityFrameworkCore 3.1.10 and Pomelo.EntityFrameworkCore.MySql 3.2.4. After updating to Microsoft.EntityFrameworkCore 5.0.0 and Pomelo.EntityFrameworkCore.MySql 5.0.0-alpha.2 InvalidOperationException is thrown.
// 'model' here is of type ProfileFormvarprofile=new UserProfile
{Id=id};this.dbContext.Add(profile);this.dbContext.Entry(profile).CurrentValues.SetValues(model);varclientCulture=this.GetClientCulture();varsearchintTopics=awaitthis.FindTopicsAsync(model.Searching, clientCulture);varofferingTopics=awaitthis.FindTopicsAsync(model.Offering, clientCulture);
profile.UpdateOfferingForCulture(offeringTopics, clientCulture).UpdateSearchingForCulture(searchintTopics, clientCulture);// saving will throwawaitthis.dbContext.SaveChangesAsync();privateasyncTask<IList<InterestTopic>>FindTopicsAsync(IEnumerable<int>topicIds,CultureInfoclientCulture){varcultureName= clientCulture.Name;varrawResult=awaitthis.dbContext
.InterestTopics
.Where(t => topicIds.Contains(t.Id)).ToListAsync();// NOTE: currently not possible to translate this into SQL syntax, therefore we do it in memory// See https://github.com/dotnet/efcore/issues/10434return rawResult.Where(t => t.SpecificCulture ==null|| t.SpecificCulture ==cultureName).ToList();}publicclassProfileForm{publicboolIsCompart{get;set;}publicList<int> Offering {get;set;}=default!;publicList<int> Searching {get;set;}=default!;publicstring?Company{get;set;}publicstring?Job{get;set;}publicstring?Bio{get;set;}publicstring?LinkedInUrl{get;set;}}
The data model:
publicclassApplicationDbContext:DbContext{publicvirtualDbSet<UserProfile> UserProfiles =>Set<UserProfile>();publicvirtualDbSet<InterestTopic> InterestTopics =>Set<InterestTopic>();publicvirtualDbSet<UserInterestOffering> UserInterestOfferings =>Set<UserInterestOffering>();publicvirtualDbSet<UserInterestSearching> UserInterestSearchings =>Set<UserInterestSearching>();publicApplicationDbContext(DbContextOptionsoptions):base(options){}protectedoverridevoidOnConfiguring(DbContextOptionsBuilderoptionsBuilder){base.OnConfiguring(optionsBuilder);
optionsBuilder.UseLazyLoadingProxies();}protectedoverridevoidOnModelCreating(ModelBuilderbuilder){base.OnModelCreating(builder);
builder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);}}publicclassDataConstants{publicconststringPoidName="Poid";publicconststringCreatedAtStampName="CreatedAt";}publicclassUserProfileEntityTypeConfiguration:IEntityTypeConfiguration<UserProfile>{publicvoidConfigure(EntityTypeBuilder<UserProfile>builder){
builder.Property<int>(DataConstants.PoidName);
builder.Property<DateTime>(DataConstants.CreatedAtStampName).HasColumnType("DATETIME").HasDefaultValueSql("CURRENT_TIMESTAMP");
builder.Property(t => t.Id).IsRequired();
builder.Property(t => t.Company).IsRequired(false).HasMaxLength(120);
builder.Property(t => t.Job).IsRequired(false).HasMaxLength(100);
builder.Property(t => t.Bio).IsRequired(false).HasMaxLength(500);
builder.Property(t => t.IsCompart).IsRequired();
builder.Property(t => t.LinkedInUrl).IsRequired(false).HasMaxLength(50).StoreEmptyAsNull();
builder.HasKey(DataConstants.PoidName);
builder.HasIndex(t => t.Id);}}publicclassUserInterestSearchingEntityTypeConfiguration:IEntityTypeConfiguration<UserInterestSearching>{publicstaticreadonlystringTopicFkName=$"{nameof(InterestTopic)}{nameof(InterestTopic.Id)}";publicstaticreadonlystringUserFkName=$"{nameof(UserProfile)}{DataConstants.PoidName}";publicvoidConfigure(EntityTypeBuilder<UserInterestSearching>builder){
builder.Property<int>(UserFkName);
builder.Property<int>(TopicFkName);
builder.HasOne(t => t.User).WithMany(t => t.Searching).HasForeignKey(UserFkName);
builder.HasOne(t => t.Topic).WithMany(t => t.AsSearch).HasForeignKey(TopicFkName);
builder.HasKey(UserFkName, TopicFkName);}}publicclassUserInterestOfferingEntityTypeConfiguration:IEntityTypeConfiguration<UserInterestOffering>{publicstaticreadonlystringTopicFkName=$"{nameof(InterestTopic)}{nameof(InterestTopic.Id)}";publicstaticreadonlystringUserFkName=$"{nameof(UserProfile)}{DataConstants.PoidName}";publicvoidConfigure(EntityTypeBuilder<UserInterestOffering>builder){
builder.Property<int>(UserFkName);
builder.Property<int>(TopicFkName);
builder.HasOne(t => t.User).WithMany(t => t.Offering).HasForeignKey(UserFkName);
builder.HasOne(t => t.Topic).WithMany(t => t.AsOffer).HasForeignKey(TopicFkName);
builder.HasKey(UserFkName, TopicFkName);}}publicclassInterestTopicEntityTypeConfiguration:IEntityTypeConfiguration<InterestTopic>{publicvoidConfigure(EntityTypeBuilder<InterestTopic>builder){
builder.Property(t => t.Id).IsRequired().ValueGeneratedNever();
builder.Property(t => t.DisplayName).IsRequired().HasMaxLength(100);
builder.Property(t => t.SpecificCulture).IsRequired(false)// BCP-47 language tag seem to be up to 35 chars. Most likely wont be rquired, but better be safe// See https://stackoverflow.com/a/17863380/5394220.HasMaxLength(40);
builder.HasKey(t => t.Id);
builder.HasIndex(t =>new{ t.DisplayName, t.SpecificCulture });}}
The entity types:
publicclassUserInterestOffering{publicvirtualUserProfileUser{get;set;}=default!;publicvirtualInterestTopicTopic{get;set;}=default!;}publicclassUserInterestSearching{publicvirtualUserProfileUser{get;set;}=default!;publicvirtualInterestTopicTopic{get;set;}=default!;}publicclassInterestTopic{publicintId{get;set;}publicstringDisplayName{get;set;}=default!;publicstring?SpecificCulture{get;set;}publicvirtualICollection<UserInterestOffering> AsOffer {get;set;}=default!;publicvirtualICollection<UserInterestSearching> AsSearch {get;set;}=default!;publicboolIsForCulture(CultureInfocultureInfo){returnthis.SpecificCulture ==null||this.SpecificCulture == cultureInfo.Name;}}publicclassUserProfile{publicUserProfile(){this.Offering =newHashSet<UserInterestOffering>();this.Searching =newHashSet<UserInterestSearching>();}publicGuidId{get;set;}publicboolIsCompart{get;set;}publicstring?Company{get;set;}publicstring?Job{get;set;}publicstring?Bio{get;set;}publicstring?LinkedInUrl{get;set;}publicvirtualICollection<UserInterestOffering> Offering {get;set;}publicvirtualICollection<UserInterestSearching> Searching {get;set;}public UserProfile UpdateOfferingForCulture(IEnumerable<InterestTopic>values,CultureInfocultureToUpdate){if(values.Any(v =>!v.IsForCulture(cultureToUpdate))){thrownew InvalidOperationException(string.Format("At least one element in '{0}' is not for '{1}'", nameof(values), cultureToUpdate));}varotherCultureTopics=this.Offering
.Where(s =>!s.Topic.IsForCulture(cultureToUpdate)).ToList();varnewTopics= values
.Select(val =>new UserInterestOffering {Topic=val,User=this}).ToList();this.Offering.Clear();this.Offering = otherCultureTopics.Concat(newTopics).ToList();returnthis;}public UserProfile UpdateSearchingForCulture(IEnumerable<InterestTopic>values,CultureInfocultureToUpdate){if(values.Any(v =>!v.IsForCulture(cultureToUpdate))){thrownew InvalidOperationException(string.Format("At least one element in '{0}' is not for '{1}'", nameof(values), cultureToUpdate));}varotherCultureTopics=this.Searching
.Where(s =>!s.Topic.IsForCulture(cultureToUpdate)).ToList();varnewTopics= values
.Select(val =>new UserInterestSearching {Topic=val,User=this}).ToList();this.Searching.Clear();this.Searching = otherCultureTopics.Concat(newTopics).ToList();returnthis;}}
The full stack trace:
System.InvalidOperationException: The value of 'UserInterestOffering.InterestTopicId' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known.
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.PrepareToSave()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.GetEntriesToSave(Boolean cascadeChanges)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(DbContext _, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.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 SAI.InterestNetwork.Web.Features.Profile.ProfileController.CreateProfileAsync(ProfileForm model) in C:\Users\jtoled\source\repos\SAI.InterestNetwork\SAI.InterestNetwork.Web\Features\Profile\ProfileController.cs:line 98
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|19_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.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
at Serilog.AspNetCore.RequestLoggingMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Environment
EF Core version: 5.0.0
Database provider: Pomelo.EntityFrameworkCore.MySql 5.0.0-alpha.2
Target framework: netcoreapp3.1
Operating system: win10-x64
IDE: Visual Studio 2019 Version 16.8.2
The text was updated successfully, but these errors were encountered:
@jotatoledo Unfortunately, there is too much missing code here for me to be able to run this on my machine in order to reproduce and investigate the issue. Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.
EF Team Triage: Closing this issue as the requested additional details have not been provided and we have been unable to reproduce it.
BTW this is a canned response and may have info or details that do not directly apply to this particular issue. While we'd like to spend the time to uniquely address every incoming issue, we get a lot traffic on the EF projects and that is not practical. To ensure we maximize the time we have to work on fixing bugs, implementing new features, etc. we use canned responses for common triage decisions.
The following code worked with
Microsoft.EntityFrameworkCore
3.1.10 andPomelo.EntityFrameworkCore.MySql
3.2.4. After updating toMicrosoft.EntityFrameworkCore
5.0.0 andPomelo.EntityFrameworkCore.MySql
5.0.0-alpha.2InvalidOperationException
is thrown.Seems related to #20002 and #21206
The data model:
The entity types:
The full stack trace:
Environment
EF Core version: 5.0.0
Database provider: Pomelo.EntityFrameworkCore.MySql 5.0.0-alpha.2
Target framework: netcoreapp3.1
Operating system: win10-x64
IDE: Visual Studio 2019 Version 16.8.2
The text was updated successfully, but these errors were encountered: