The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
Problem description
The error quoted above happened to me after I started using AutoMapper on my WCF service for updating my entities. Previously, I had a "manual map" to assing the properties that I received on my data contract to the entity that I got on my context and update it. When we decided to implement AutoMapper on our project, my mapping code started like this:
Mapper.CreateMap<MyDataContract, MyEntity>.IgnoreAllNonExisting();
Since all my properties were named the same on both classes, everything seemed to be easy peasy.
But sadly, I started gotting the error message
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.This message was driving me crazy, because of the text I was thinking that I was making something wrong with the FK relationships on the Database, or in someway the field was being passed null without being null on the contract, or somebody changed the table in someway (yeah sure, blame others :-P). After some deep look on the code (including debugging line by line all the updating process) I found the error.
Since I'm copying the modified values (from DataContract to Entity) when mapping, I'm passing all the values from one instance to the other. This sounds OK, right? I mean, I want all my changes to be persisted on the database.
Well, is not that easy. Since my contract comes from a web application, when saving there I don't have all the navigation properties. When this is the case and I just map all, I'm also mapping and overwriting the values of this navigation properties, that in this case are null on my DataContract. This makes the Entity to update the ForeignKey Columns that belong to that navigation property to be null too. That is why the error says that you're sending null values, because actually you are.
Solution
Since the problem is that we're mapping null navigation properties, and we actually don't need them to be updated on the Entity since they didn't changed on the Contract, we need to ignore them on the mapping definition:ForMember(dest => dest.RefundType, opt => opt.Ignore())
So my code ended up like this
Mapper.CreateMap<MyDataContract, MyEntity> ForMember(dest => dest.NavigationProperty1, opt => opt.Ignore()) ForMember(dest => dest.NavigationProperty2, opt => opt.Ignore()) .IgnoreAllNonExisting();
And voilĂ ! the problem is solved.
Thank you! I was getting that error all over the place due to child relationships combined with AutoMapper. This solution made all of the errors finally go away. Also, I am using the latest pre-release version of AutoMapper and I don't think that it uses the ".IgnoreAllNonExisting()" option anymore. Other than that, this post is extremely helpful.
ReplyDeleteGlad it helped! :)
Delete