0

I have simple ObjectListView which displays some columns from EntityFramework of objects called Person (to simplify things). I load it with Entity Framework to ObjectListviewand then deatch it from Context. The person has multiple fields (like Name, Surname, File, ...).

Considering that some files are 5mb-50mb I don't want to load/save them to database without need. Now when someone double clicks in ObjectListView the selected Person is loaded into TextBox fields. When editing any of the fields I check if Person Name or SurName changed and if it did I updated the context like in the code below.

    private void test (Person person){
        using (var context = new EntityBazaCRM(Settings.sqlDataConnectionDetailsCRM)) {
            context.Persons.Attach(dokument);
            if (person.Name != nameTextBox.Text) {
                person.Name = nameTextBox.Text;
                context.ObjectStateManager.GetObjectStateEntry(person).SetModifiedProperty("Name");
            }
            if (person.SurName != surNameTextBox.Text) {
                person.SurName = surNameTextBox.Text;
                context.ObjectStateManager.GetObjectStateEntry(person).SetModifiedProperty("SurName");
            }
            context.SaveChanges();
        }

    }

This works.. but what I would like to do is actually not save the changes straight away after users changes it but in the end when he presses BIG button SAVE ALL so then it would go thru all ObjectListView items and update them as needed in database. The problem is I can't update context and do it later since the Context wouldn't be used then but in the end when saving everything.

So what are my options? I was pointed to use INotifyPropertyChanged but as much as I looked at the code I don't think it's good for this type of situation or I simply don't know how to use it.

The other option was to actually create bool value per each Column from the database like

public partial class Person
{
    public bool NameChanged {get;set; }

    public bool SurnameChanged { get; set; }
}

And when saving I would be checking if bool changed and if yes do the ObjectStateManager magic on the context prior to save.

Any other way to do this?

Community
  • 1
  • 1
MadBoy
  • 10,213
  • 18
  • 88
  • 146

2 Answers2

0

I would advise to use a DataSource object in your xaml, and set your list view's data source to be bound to the DataSource object. Also use a pager, (You can get one from here:http://cid-51b2fdd068799d15.office.live.com/self.aspx/.Public/Samples%5E_2010/20100929%5E_DataPagerForWPF.zip) whose data source will also be bound to the DataSource object. That wold achieve 2 things:

  1. The pager will query the data source object ensuring that it loads only x number of data elements (entities) at a time. Do not, however be fooled that if you have 5000000 entities, your data context will eventually store all of these entities in memory after the user has gone to the last page. These entities do get garbage collected.

  2. The data source object contains a global instance of the context which will never go out of scope until the control or window is destroyed and garbage collected.

That being said here are two tips to make your life easier:

  1. Entities by default implement INotifyPropertyChanged.

  2. I do believe that as long as the context exists in the same memory space as the entities being modified, all you need to do is call SaveChanges() on the context to commit the changes to all modified entities. YOU DON'T HAVE TO DETACH the entities so that you can display them, modify them (well your user modifies them), then re-attach the entities to the context, and finally notify the context that the entity has changed.

bleepzter
  • 8,463
  • 11
  • 38
  • 62
  • i forgot to mention it's winforms – MadBoy Feb 17 '12 at 16:40
  • Also I was under impression from my earlier question http://stackoverflow.com/questions/9093863/does-it-make-sense-to-create-new-object-in-entity-framework-before-saving-it-to that detaching it from context and not keeping it up and running for the whole time is better – MadBoy Feb 17 '12 at 16:42
  • No, not really. The context tracks changes that happen to each individual entity in its corresponding entity containers. When you detach you have to explicitly call:`context.ObjectStateManager.GetObjectStateEntry([object]).SetModifiedProperty([property name]); to notify the context that the entity has changed as you have discovered yourself. – bleepzter Feb 17 '12 at 17:33
  • And that I am doing. But I'm looking for a way to "postpone" the call to context when the context will be actually available (because when it is available i will actually have to save entity or keep dragging it over for all the time user is doing anything). – MadBoy Feb 17 '12 at 17:48
  • Like I said earlier, as long as you set the datasource of your grid or list view to the entity container of your context, the context will automatically track changes to the entities that your user has modified given a two way binding between the entities and the edit controls. You don't have to drag anything over... the entities are cached along with their original and modified states in the context's entity container. All you have to do is call SaveChanges() once to update all modified entities in one shot. The SaveChanges() call is done in the event handler of ur one-n-only save button. – bleepzter Feb 17 '12 at 20:12
  • Point being is you don't have to manually remove and add the entities out of the context. I mean you can but that's a waste. Might as well not use the EF or Linq2Sql at all. – bleepzter Feb 17 '12 at 20:14
0

Is using change tracking POCO entities an option for you?

http://msdn.microsoft.com/en-us/library/dd456848.aspx

Erick
  • 478
  • 2
  • 12
  • I was looking at self-tracking entities but people said it can blow in my face. Will your solution work if i detach context after loading stuff from sql with entity framework? – MadBoy Feb 17 '12 at 16:45
  • I used self tracking POCOs over RIA Services which is a little different, but on the server side when POCOs come back from the client they are not attached and you can reattach the POCO and at that time assess the map for changes and decide what changes you want to keep or not keep – Erick Feb 17 '12 at 16:49
  • What I am doing is load entity object, detach context .. do some stuff on object, attach context and save. Considering that I doubt it will work -> http://stackoverflow.com/questions/3902328/ef-4-problems-understanding-detectchanges-when-using-poco-no-self-tracking-obj If i wouldn't detatch context and use DetectChanges then maybe but otherwise it seems to me that I will have to update properties by hand (which is what I am doing now) but the problem I'm having is that I would like to notify context about those changes at later time. – MadBoy Feb 17 '12 at 17:01
  • A delayed notify... I can't think of anything clean if you kept a deep copy of the original POCO's you could check the differences at any time but that's mighty ugly in my opinion – Erick Feb 17 '12 at 18:30