Naografix Naografix - 4 months ago 101
SQL Question

Entity Framework 5 : One to Many with foreignKey Updated/Added/Deleted

When I update my member, I want to update his BankCheck too.

This is my database:

my database


  • My bankCheck can be added, updated or deleted.

  • My member can be updated only (name, surname...)



I choose my member in my datagrid, and select Edit, my wpf app switch to an other page and display my member with Textbox etc.

I click on my button to add/edit/delete his bankCheck and I can edit the first bankCheck.

I delete the last bankCheck and I add an other (for example).

I press OK and I click on "Valid my Edit".

My program re-creates a new Member with his bankCheck and i made this:

private void EditMember(Member updatedMember)
{
try
{
using (var context = new KravMagaEntities())
{
context.Member.Attach(updatedMember);
context.Entry(updatedMember).State = EntityState.Modified;
context.SaveChanges();
}

ResetAllControls();
States.EnumToText(States.StatesEnum.UpdatingSuccess);

Application.Current.Dispatcher.Invoke(() =>
{
_managementService.IsVisibleAddTab(true);
_managementService.IsVisibleEditTab(false);
});
}
catch (Exception exception)
{
States.EnumToText(States.StatesEnum.Error, exception);
}
}


But I have this error:


A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.


I don't know how I can fix this error.

Thank you.

My code:

private void OnEditMemberBtnClicked(object sender, RoutedEventArgs e)
{
try
{
var isValidateCertificat = IsValidDate(BirthDateTxt);
var isValidateBirth = IsValidDate(CertificateDateTxt);
var isValidateAutorisation = IsValidDate(AutorizationDateTxt);
var isValidateReglement = IsValidDate(RuleDateTxt);

if (isValidateBirth && isValidateCertificat && isValidateAutorisation && isValidateReglement)
{
States.EnumToText(States.StatesEnum.Updating);

var typePaiement = BankCheckRadio.IsChecked.Value;
var typePaiementText = typePaiement ? "Chèque" : "Espèce";

var doctor = "";
var dateCertificate = "";

if (BankCheckRadio.IsChecked.Value)
{
doctor = DoctorTxt.Text;
dateCertificate = CertificateDateTxt.Text;
}

var editedMember = new Member
{
id_Member = _idForEdit,
name_Member = UppercaseChar(NameTxt.Text),
surname_Member = UppercaseChar(SurnameTxt.Text),
birthDate_Member = BirthDateTxt.Text,
autorizationDate_Member = AutorizationDateTxt.Text,
address_Member = UppercaseChar(AddressTxt.Text),
postalCode_Member = PostalCodeTxt.Text,
country_Member = UppercaseChar(CountryTxt.Text),
fixPhone_Member = FixPhoneTxt.Text,
mobilePhone_Member = MobilePhoneTxt.Text,
mail_Member = MailTxt.Text,
beginDate_Member = BeginDateCombo.Text,
ruleDate_Member = RuleDateTxt.Text,
subscription_Member = SubscriptionCombo.Text,
typePaiement_Member = typePaiement,
typePaiementText_Member = typePaiementText,
federationNumero_Member = FederationNumeroTxt.Text.ToUpper(),
level_Member = LevelCombo.Text,
certificate_Member = CertificateCheckbox.IsChecked.Value,
doctor_Member = UppercaseChar(doctor),
certificateDate_Member = dateCertificate,
problem_Member = UppercaseChar(ProblemTxt.Text, true),
emergencyName_Member = UppercaseChar(EmergencyNameTxt.Text),
emergencyPhone_Member = EmergencyPhoneTxt.Text,
BankCheck = _bankChecks
};

if (_bankChecks != null)
{
using (var context = new KravMagaEntities())
{
foreach (var bankCheck in _bankChecks)
{
bankCheck.idMember_BankCheck = editedMember.id_Member;
context.Entry(bankCheck).State = EntityState.Added;
}
context.SaveChanges();
}
}

new Task(() => EditMember(editedMember)).Start();
}
}
catch (Exception exception)
{
States.EnumToText(States.StatesEnum.Error, exception);
}
}

Answer

So as I see, you're updating only Member, not all the modified BankAccounts. You're updating navigation property of entities from both sides but calling SaveChanges() only on entity from one side. So your Member starts to refer another BankAccount while your BankAccounts still refer to the old Member. You need to mark all appropriate BankAccounts as modified along with your modified Member in the same place and then call SaveChanges() so everything will be saved (from comment).

To prevent adding a duplicate you can try to set the state of your entities to the State.Modified instead of State.Added.

The reason of that problem was that you were updating only entity from one side. If you have BankAccounts-Members relationship then in case you update the navtigation property for Member you should update a navigation property for BankAccount too and vice versa. If you just update some property (Member.Name or anything) you just set this Member's State to State.Modified without affecting any of other Member's, BankAccount's etc.

If the entity tracking is turned on for you then EF will automatically track entities that were modified and set appropriate states for them. But as I've seen from your issue, it's turned off for you so you have to manually set the state for each object you want to add/update/delete.