4

I have simple query that loads data from two tables into GUI. I'm saving loaded data to widely available object Clients currentlySelectedClient.

using (var context = new EntityBazaCRM()) 
{
   currentlySelectedClient = context.Kliencis.Include("Podmioty").FirstOrDefault(d => d.KlienciID == klientId);
   if (currentlySelectedClient != null) 
   {
      textImie.Text = currentlySelectedClient.Podmioty.PodmiotOsobaImie;
      textNazwisko.Text = currentlySelectedClient.Podmioty.PodmiotOsobaNazwisko;
   } 
   else 
   {
      textNazwa.Text = currentlySelectedClient.Podmioty.PodmiotFirmaNazwa;
   }
}

So now if I would like to:

1) Save changes made by user how do I do it? Will I have to prepare something on database side? How do I handle modifying multiple tables (some data goes here, some there)? My current code seems to write .KlienciHaslo just fine, but it doesn't affect Podmioty at all. I tried different combinations but no luck.

2) Add new client to database (and save information to related tables as well)?

    currentClient.Podmioty.PodmiotOsobaImie = textImie.Text;  // not saved
    currentClient.Podmioty.PodmiotOsobaNazwisko = textNazwisko.Text; // not saved
    currentClient.KlienciHaslo = "TEST111"; // saved

    using (var context = new EntityBazaCRM()) 
    {
        var objectInDB = context.Kliencis.SingleOrDefault(t => t.KlienciID == currentClient.KlienciID);
        if (objectInDB != null) 
        {
           // context.ObjectStateManager.ChangeObjectState(currentClient.Podmioty, EntityState.Modified);
           //context.Podmioties.Attach(currentClient.Podmioty);
           context.Kliencis.ApplyCurrentValues(currentClient); // update current client
           //context.ApplyCurrentValues("Podmioty", currentClient.Podmioty); // update current client
        } 
        else 
        {
           context.Kliencis.AddObject(currentClient);  // save new Client
        }
        context.SaveChanges();
     }

How can I achieve both?

Edit for an answer (doesn't save anything ):

currentClient.Podmioty.PodmiotOsobaImie = textImie.Text; // no save
currentClient.Podmioty.PodmiotOsobaNazwisko = textNazwisko.Text; // no save
currentClient.KlienciHaslo = "TEST1134"; // no save

using (var context = new EntityBazaCRM()) 
{
    if (context.Kliencis.Any(t => t.KlienciID == currentClient.KlienciID)) 
    {
        context.Kliencis.Attach(currentClient); // update current client
    } 
    else 
    {
        context.Kliencis.AddObject(currentClient);  // save new Client
    }
    context.SaveChanges();
}            
2
  • Good question. Does it still not work when you uncomment the line context.Podmioties.Attach(currentClient.Podmioty);? Commented Nov 28, 2011 at 11:42
  • It shoots me some errors. I tried couple of combinations but gave up with errors. Commented Nov 28, 2011 at 12:02

2 Answers 2

5

Apparently ApplyCurrentValues only works with scalar properties.

If you attach the currentClient then associated objects should also attach, which means they'll be updated when you SaveChanges()

But you'll get an Object with the key exists exception because you are already loading the object from the database into the objectInDB variable. The context can only contain one copy of a Entity, and it knows that currentClient is the same as objectInDB so throws an exception.

Try this pattern instead

if (context.Kliencis.Any(t => t.KlienciID == currentClient.KlienciID)) 
{
    context.Kliencis.Attach(currentClient); // update current client
} 
else 
{
    context.Kliencis.AddObject(currentClient);  // save new Client
}

or if you're using an identity as the ID, then

// if the ID is != 0 then it's an existing database record
if (currentClient.KlienciID != 0) 
{
    context.Kliencis.Attach(currentClient); // update current client
} 
else // the ID is 0; it's a new record
{
    context.Kliencis.AddObject(currentClient);  // save new Client
}
Sign up to request clarification or add additional context in comments.

4 Comments

An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key. is an error when I remove my ApplyCurrentValues and put yours attach.
Ah, that's because you're retrieving it first. I've updated my answer.
I tried the 1st proposed solution and it didn't save anything (as per code i've updated the main question with the code I used).
I managed to get the correct solution with your help. I had to use ChangeObjectState for Entity to save changes.
1

After some work and help from Kirk about the ObjectStateManager error that I was getting I managed to fix this. This code allows me to save both changes to both tables.

 currentClient.Podmioty.PodmiotOsobaImie = textImie.Text;
 currentClient.Podmioty.PodmiotOsobaNazwisko = textNazwisko.Text;
 currentClient.KlienciHaslo = "TEST1134";
 using (var context = new EntityBazaCRM()) {
       if (context.Kliencis.Any(t => t.KlienciID == currentClient.KlienciID)) {
           context.Podmioties.Attach(currentClient.Podmioty);
           context.Kliencis.Attach(currentClient);
           context.ObjectStateManager.ChangeObjectState(currentClient.Podmioty, EntityState.Modified);
           context.ObjectStateManager.ChangeObjectState(currentClient, EntityState.Modified);
        } else {
           context.Kliencis.AddObject(currentClient);  // save new Client
        }
        context.SaveChanges();
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.