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

Temporary Key issue when inserting Many To Many Relationship and Self Reference #10142

Closed
AlexTeixeira opened this issue Oct 23, 2017 · 5 comments
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@AlexTeixeira
Copy link

Configuration

Asp.net core : 2.0.0
EF core : 2.0.0
Npgsql.EntityFrameworkCore.PostgreSQL : 2.0.0
Npgsql.EntityFrameworkCore.PostgreSQL.Design: 2.0.0-preview-1

OS : macOS High Sierra 10.13

Introduction

The first investigation come from this issue : npgsql/efcore.pg#252 (comment)

The code is in a Repository because after multiple exchanges, @ajcvickers was not able to reproduce the issue.

Code

https://github.com/AlexTeixeira/TestEfCoreManyToMany

Step to reproduce

Create the database and run the program from the git repository code.

Error

When the SaveChanges() is called, it throw this error :


System.InvalidOperationException: The property 'UserId' on entity type 'FacebookUsersHobbies' has a temporary value. Either set a permanent value explicitly or ensure that the database is configured to generate values for this property.
   at Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.Validate(ModificationCommand modificationCommand)
   at Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.<BatchCommands>d__8.MoveNext()
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(Tuple`2 parameters)
   at Microsoft.EntityFrameworkCore.Storage.Internal.NpgsqlExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(IReadOnlyList`1 entries)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList`1 entriesToSave)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
 

Workaround

Create the user first and Insert the Id instead of the object.
But for me it's extra code for "nothing"

Additionnal informations

I'm not sure, but it seems that when the project is created is macOs the error raise.
I create a more simple project with Self Referencing & Many to Many Relationship on windows and it works.

@ajcvickers ajcvickers self-assigned this Oct 25, 2017
@ajcvickers ajcvickers added this to the 2.1.0 milestone Oct 25, 2017
@ajcvickers
Copy link
Contributor

Notes for triage: I was able to reproduce this; minimal repro code is:

class Program
{
    public class Hobbie
    {
        public int Id { get; set; }

        public ICollection<FacebookUsersHobbies> FacebookUsers { get; set; }
    }

    public class FacebookUser : User
    {
        public ICollection<FacebookUsersHobbies> Hobbies { get; set; }
    }

    public abstract class User
    {
        public int Id { get; set; }

        [ForeignKey("Parent")]
        public int? ParentId { get; set; }
        public User Parent { get; set; }
        [InverseProperty("Parent")]
        public ICollection<User> Children { get; set; } = new HashSet<User>();
    }

    public class FacebookUsersHobbies
    {
        public int UserId { get; set; }
        public FacebookUser User { get; set; }

        public int HobbieId { get; set; }
        public Hobbie Hobbie { get; set; }
    }

    public class MyContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            => optionsBuilder
                .UseSqlServer(
                    @"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0");

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Hobbie>();
            modelBuilder.Ignore<User>();
            modelBuilder.Entity<FacebookUser>();
            modelBuilder.Entity<FacebookUsersHobbies>()
                .HasKey(uh => new { uh.UserId, uh.HobbieId });
        }
    }

    static void Main(string[] args)
    {
        using (var context = new MyContext())
        {
            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();

            var hobby = context.Add(new Hobbie()).Entity;
            context.SaveChanges();

            var fb = new FacebookUser
            {
                Hobbies = new List<FacebookUsersHobbies>
                {
                    new FacebookUsersHobbies
                    {
                        HobbieId = hobby.Id
                    }
                }
            };

            context.Add(fb);

            context.SaveChanges();
        }
    }
}

There is a very strange construct in this model--namely, the inverse relationship configured on an unmapped base type. If this is commented out:

        //[ForeignKey("Parent")]
        public int? ParentId { get; set; }
        //public User Parent { get; set; }
        //[InverseProperty("Parent")]
        //public ICollection<User> Children { get; set; } = new HashSet<User>();

then the issue no longer repros. The model created in the working case is:

Model: 
  EntityType: FacebookUser
    Properties: 
      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd 0 0 0 -1 0
      ParentId (Nullable<int>) 1 1 -1 -1 -1
    Navigations: 
      Hobbies (<Hobbies>k__BackingField, ICollection<FacebookUsersHobbies>) Collection ToDependent FacebookUsersHobbies Inverse: User 0 -1 1 -1 -1
    Keys: 
      Id PK
  EntityType: FacebookUsersHobbies
    Properties: 
      UserId (int) Required PK FK AfterSave:Throw 0 0 0 -1 0
      HobbieId (int) Required PK FK Index AfterSave:Throw 1 1 1 -1 1
    Navigations: 
      Hobbie (<Hobbie>k__BackingField, Hobbie) ToPrincipal Hobbie Inverse: FacebookUsers 0 -1 2 -1 -1
      User (<User>k__BackingField, FacebookUser) ToPrincipal FacebookUser Inverse: Hobbies 1 -1 3 -1 -1
    Keys: 
      UserId, HobbieId PK
    Foreign keys: 
      FacebookUsersHobbies {'HobbieId'} -> Hobbie {'Id'} ToDependent: FacebookUsers ToPrincipal: Hobbie
      FacebookUsersHobbies {'UserId'} -> FacebookUser {'Id'} ToDependent: Hobbies ToPrincipal: User
  EntityType: Hobbie
    Properties: 
      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd 0 0 0 -1 0
    Navigations: 
      FacebookUsers (<FacebookUsers>k__BackingField, ICollection<FacebookUsersHobbies>) Collection ToDependent FacebookUsersHobbies Inverse: Hobbie 0 -1 1 -1 -1
    Keys: 
      Id PK

While the model created in the error case has a discriminator annotation remaining:

Model: 
  EntityType: FacebookUser
    Properties: 
      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd 0 0 0 -1 0
      ParentId (Nullable<int>) 1 1 -1 -1 -1
    Navigations: 
      Hobbies (<Hobbies>k__BackingField, ICollection<FacebookUsersHobbies>) Collection ToDependent FacebookUsersHobbies Inverse: User 0 -1 1 -1 -1
    Keys: 
      Id PK
    Annotations: 
>      Relational:DiscriminatorValue: FacebookUser
  EntityType: FacebookUsersHobbies
    Properties: 
      UserId (int) Required PK FK AfterSave:Throw 0 0 0 -1 0
      HobbieId (int) Required PK FK Index AfterSave:Throw 1 1 1 -1 1
    Navigations: 
      Hobbie (<Hobbie>k__BackingField, Hobbie) ToPrincipal Hobbie Inverse: FacebookUsers 0 -1 2 -1 -1
      User (<User>k__BackingField, FacebookUser) ToPrincipal FacebookUser Inverse: Hobbies 1 -1 3 -1 -1
    Keys: 
      UserId, HobbieId PK
    Foreign keys: 
      FacebookUsersHobbies {'HobbieId'} -> Hobbie {'Id'} ToDependent: FacebookUsers ToPrincipal: Hobbie
      FacebookUsersHobbies {'UserId'} -> FacebookUser {'Id'} ToDependent: Hobbies ToPrincipal: User
  EntityType: Hobbie
    Properties: 
      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd 0 0 0 -1 0
    Navigations: 
      FacebookUsers (<FacebookUsers>k__BackingField, ICollection<FacebookUsersHobbies>) Collection ToDependent FacebookUsersHobbies Inverse: Hobbie 0 -1 1 -1 -1
    Keys: 
      Id PK

Marking for re-triage.

@smitpatel
Copy link
Contributor

@AndriySvyryd - Would #10842 also removes Discriminator in above case?

@AndriySvyryd
Copy link
Member

AndriySvyryd commented Feb 7, 2018

@smitpatel In this case there's no Discriminator property, only a value. #10842 doesn't remove the value annotation, but it shouldn't impact anything if there's no discriminator. Even if the annotation is removed from the model this issue still reproes.

@denis-souzaa
Copy link

denis-souzaa commented Mar 12, 2019

I have same problem with ef core 2.2

The property 'UserId' on entity type 'UserGroups' has a temporary value. Either set a permanent value explicitly or ensure that the database is configured to generate values for this property.

@ajcvickers
Copy link
Contributor

@SistemasSouza Please file a new issue with a small, runnable project/solution or complete code listing that demonstrates the behavior you are seeing.

@ajcvickers ajcvickers modified the milestones: 2.1.0-preview2, 2.1.0 Nov 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

5 participants