DbUpdateException with objects that do not display foreign key properties

I have an entity model with User and Person objects, so each User must be associated with exactly 1 Person , and each Person can be associated with zero or 1 User .

 User (0..1) <-------> (1) Person 

Communication is matched seamlessly. Initially, I only declared this on the Person side:

 private class PersonOrm : EntityTypeConfiguration<Person> { internal PersonOrm() { ToTable(typeof(Person).Name, DbSchemaName.People); // has zero or one User HasOptional(p => p.User) .WithRequired(d => d.Person) .Map(d => d.MapKey("PersonId")) .WillCascadeOnDelete(false) ; 

Since I ran into this error, I also added the same mapping to the User side:

 private class UserOrm : EntityTypeConfiguration<User> { internal UserOrm() { ToTable(typeof(User).Name, DbSchemaName.Identity); // has exactly 1 Person HasRequired(p => p.Person) .WithOptional(d => d.User) .Map(d => d.MapKey("PersonId")) .WillCascadeOnDelete(false); 

The application has a script in which you can create a new User and associated with an existing Person . At the moment I am having difficulty. EF treats User as the dependent side of the relationship and puts the PersonId (FK, int, not null) column in the User table. I don't find it possible to use a foreign key property for any object to help EF manage the association (is this?).

Here are some unsuccessful codes that try to process the script:

 // find out if Person already exists var person = context.People.SingleOrDefault(p => p.Emails.Any( e => e.Value.Equals(emailAddress, StringComparison.OrdinalIgnoreCase))); // find out if User already exists var user = context.Users.SingleOrDefault( u => u.Name.Equals(emailAddress, StringComparison.OrdinalIgnoreCase)); if (user == null) { user = new User { Name = emailAddress, IsRegistered = isRegistered, Person = person ?? PersonFactory.Create(emailAddress), // ignore the PersonFactory.Create, that part works }; context.Entry(user).State = EntityState.Added; context.SaveChanges(); } 

This code works fine when Person is null (it does not exist in db yet). However, when Person not null (already exists in db) and User is null, the code tries to create a new User and associate it with an existing Person . When calling SaveChanges() I get a DbUpdateException :

An error occurred while saving objects that do not display the property foreign key for their relationships. The EntityEntries property will return null because a single object cannot be identified as the source of the exception. Exception handling during saving can be performed easier by exposing the foreign key properties in its object types. See InnerException for details.

Internal exception:

Relations from the 'User_Person' AssociationSet are in the Deleted State. Given the limitations of multiplicity, the corresponding 'User_Person_Source' must also be in the "Deleted" state.

This makes no sense to me, because I'm not trying to delete anything, and checking the EntityState both User and Person shows that User is in the Added state while Person is in the Unchanged state. I overridden SaveChanges() to demonstrate:

 public override int SaveChanges() { var userChanges = ChangeTracker.Entries<User>().Single(); var personChanges = ChangeTracker.Entries<Person>().Single(); if (userChanges.State == EntityState.Deleted) throw new InvalidOperationException("wtf?"); if (personChanges.State == EntityState.Deleted) throw new InvalidOperationException("wtf?"); return base.SaveChanges(); } 

When this code is executed, no InvalidOperationException is thrown. Again, userChanges is in the Added state, and personChanges is in the Unchanged state.

What am I doing wrong?

+6
source share
2 answers

I feel really dumb right now. After writing this thorough question, it is now obvious.

Person I am testing with an existing one and already has a User association with another User.Name . This is why User approaches zero. Setting the Person.User property to a new User causes the old User be placed in the Deleted state. Doh.

Sorry to waste your time. I will leave the question until he agrees that it would be better to delete it.

+6
source

Make sure you have the relationship defined in your mapping (Entity Type Configuration)

For instance:

this.HasRequired (t => t.QuoteResponse) .WithMany (t => t.QuoteResponseItems) .HasForeignKey (d => d.QuoteResponseID);

0
source

Source: https://habr.com/ru/post/912971/


All Articles