Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error when setting indexerProperties dictionary #21838

Closed
YeskaNova opened this issue Jul 29, 2020 · 4 comments · Fixed by #22050
Closed

Error when setting indexerProperties dictionary #21838

YeskaNova opened this issue Jul 29, 2020 · 4 comments · Fixed by #22050
Labels
area-model-building closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-bug
Milestone

Comments

@YeskaNova
Copy link

This regression happens if we want to set the dictionary of indexer properties to a tracked entity :

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;

public class User
{
    public int Id { get; set; }
    public Dictionary<string, object> Data { get; set; }
}

public class SqliteDbContext : DbContext
{
    public SqliteDbContext(DbContextOptions options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        var etb = modelBuilder.Entity<User>();
        etb.Property(x => x.Id).UseHiLo("Hilo_User");
        etb.OwnsOne(x => x.Data, x =>
        {
            x.IndexerProperty(typeof(string), "a").IsRequired(false);
            x.IndexerProperty(typeof(string), "b").IsRequired(false);
            x.Property<int>("UserId").UseHiLo("Hilo_User");
        });
    }
}

class Program
{
    static void Main(string[] args)
    {
        var sc = new ServiceCollection();
        var guid = Guid.NewGuid();
        sc.AddDbContext<SqliteDbContext>(op => op.UseSqlServer(@"Server=(localdb)\MSSQLLocalDB;Integrated Security=true;DataBase=" + guid));
        using (var provider = sc.BuildServiceProvider())
        {
            using (var scope = provider.CreateScope())
            using (var dbcontext = scope.ServiceProvider.GetService<SqliteDbContext>())
            {
                dbcontext.Database.EnsureCreated();
            }
            var user = new User();
            using (var scope = provider.CreateScope())
            using (var dbcontext = scope.ServiceProvider.GetService<SqliteDbContext>())
            {
                dbcontext.Set<User>().Add(user);
                dbcontext.SaveChanges();
            }
            using (var scope = provider.CreateScope())
            using (var dbcontext = scope.ServiceProvider.GetService<SqliteDbContext>())
            {
                var u2 = dbcontext.Set<User>().First(x => x.Id == user.Id);
                u2.Data  = new Dictionary<string, object>(){{"a","test"},{"b","test"}};
                dbcontext.SaveChanges();
            }
        }

    }
}

Exception

System.InvalidOperationException: 'The property 'UserId' on entity type 'Dictionary<string, object>' is part of a key and so cannot be modified or marked as modified. To change the principal of an existing entity with an identifying foreign key first delete the dependent and invoke 'SaveChanges' then associate the dependent with the new principal.'

Further technical details

EF Core version: 5.0.0-rc.1.20378.4
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET Core 5.0
Operating system: Windows
IDE: Visual Studio 2019

@AndriySvyryd
Copy link
Member

AndriySvyryd commented Jul 30, 2020

@YeskaNova You need to preserve the key value for UserId on Data

@YeskaNova
Copy link
Author

@AndriySvyryd You say "preserve" but Data is null before I set it:
image

It works If I change the code to

                u2.Data  = new Dictionary<string, object>(){{"UserId", u2.Id}, {"a","test"},{"b","test"}};

but it's a clear regression to me. I think that this should be handled under the hood by EF, we shouldn't handle ( or expose ) internal keys.

@ajcvickers
Copy link
Member

@YeskaNova When you say this is a regression, from which version has the behavior regressed here?

@YeskaNova
Copy link
Author

@ajcvickers It regressed after 5.0.0-rc.1.20372.13 ( it works in that version, but not in the ones after it ).

@ajcvickers ajcvickers added this to the 5.0.0 milestone Jul 31, 2020
AndriySvyryd added a commit that referenced this issue Aug 13, 2020
Implement IEquatable on TypeIdentity and MemberIdentity

Fixes #21838
@AndriySvyryd AndriySvyryd removed their assignment Aug 13, 2020
@AndriySvyryd AndriySvyryd added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Aug 13, 2020
@ghost ghost closed this as completed in #22050 Aug 13, 2020
ghost pushed a commit that referenced this issue Aug 13, 2020
Implement IEquatable on TypeIdentity and MemberIdentity

Fixes #21838
@ajcvickers ajcvickers modified the milestones: 5.0.0, 5.0.0-rc1 Aug 14, 2020
@ajcvickers ajcvickers modified the milestones: 5.0.0-rc1, 5.0.0 Nov 7, 2020
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-model-building closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants