MadBoy
MadBoy

Reputation: 11104

Save changes back to database using entity framework

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();
}            

Upvotes: 4

Views: 9870

Answers (2)

MadBoy
MadBoy

Reputation: 11104

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();
  }

Upvotes: 1

Kirk Broadhurst
Kirk Broadhurst

Reputation: 28698

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
}

Upvotes: 5

Related Questions