locked
save datagrid changes on db entity framework 6 RRS feed

  • Question

  • hello I'm looking for a way to save the edited data to a datagrid on db.
    prism5 use, codefirst and visual studio 15.
    questions:
    1) visual studio does not generate the propertychange in the model classes that are generated by the db with code from the wizard "import from an existing db" must necessarily be implemented I think for the general operation
    2) how do I reflect changes on db when an entity is changed by the datagrid?
    3) to populate the datagrid using an ObservableCollection
    4) regarding the insertion and deletion of the event propertycollectionchange observable collection is fine
    5) use a repository to add / delete / update an entity with the repository and the repository is a class variable of the my viewmodel
    6) I have seen many examples on google but it seems that there is a bit of confusion on the topic
    7) If I implements the property change on the model how do I know that the entity has changed? I have to respond at what event? according to the MVVM pattern
    8) I think that i respond to the selected change event  of the datagrid, but how?
    9) if the properties are so many I can answer so the change of line, but how do I know that the entity has been changed? maybe I need to register all the changes in a helper class ? I have a bit of confusion in short
    thanks

    10)what is tracking in ef 6?

    Friday, June 10, 2016 11:18 AM

Answers

  • Hi Giuseppe,

    You've asked 10 questions.

    Each thread is supposed to be one question.

    The title is supposed to be the question and the content of the post explanation and code/error.

    Entity framework has this thing called a dbcontext which is an instance class.

    It is effectively a sort of a repository so an extra repository is a bit pointless for small to medium sized applications.

    Hopefully you ( as a beginner ) are not designing and building some hugely complicated massive enterprise system. Because you have problems.

    Code first is a big mistake. Database first is way quicker and simpler. It is very very easy to mess up entity classes in subtle ways and get in a BIG MESS with code first.

    Let's try and go through these questions.

    1) visual studio does not generate the propertychange in the model classes that are generated by the db with code from the wizard "import from an existing db" must necessarily be implemented I think for the general operation

    Dbcontext tracks which entity objects have changes, it doesn't know about new ones. You can see code using this in the sample associated with:

    http://social.technet.microsoft.com/wiki/contents/articles/28209.wpf-entity-framework-mvvm-walk-through-1.aspx

    If you look in CustomersViewModel:

            protected override void CommitUpdates()
            {
                UserMessage msg = new UserMessage();
                var inserted = (from c in Customers
                                 where c.IsNew
                                 select c).ToList();
                if(db.ChangeTracker.HasChanges() || inserted.Count > 0)
                { 
                    foreach (CustomerVM c in inserted)
                    {
                        db.Customers.Add(c.TheCustomer);
                    }
                    try
                    {
                        db.SaveChanges();
                        msg.Message = "Database Updated";
                    }
                    catch (Exception e)
                    {
                        if (System.Diagnostics.Debugger.IsAttached)
                        {
                            ErrorMessage = e.InnerException.GetBaseException().ToString();
                        }
                        msg.Message = "There was a problem updating the database";
                    }
                }
                else
                {
                    msg.Message = "No changes to save";
                }
                Messenger.Default.Send<UserMessage>(msg);
            }


    2) how do I reflect changes on db when an entity is changed by the datagrid?

    You do SaveChanges.

    Don't try and write data back to the database immediately - give the user a commit button or something so they choose to save the data.

    You will find that there are a lot of problems with validation if you edit directly in a datagrid. It is way better to edit separately for that reason.

    You can see an approach for that in this:

    https://gallery.technet.microsoft.com/WPF-Entity-Framework-MVVM-78cdc204

    Where the user is forced to pick a record to edit. They change properties in an overlay.

    That is validated.

    They can save or abort their changes but they must change just one record at a time.

    If you let them, users will treat a datagrid like excel and you will find all sorts of "fun" edge cases where they manage to fail to save data or get several records in an invalid state otherwise. 


    3) to populate the datagrid using an ObservableCollection

    You are best "wrapping" each entity object in a viewmodel (rowvm) and binding to an observablecollection<rowvm>.

    Which you can see in that second sample.

    If you look at CustomersViewModel in that, here it is filling a new observablecollection of CustomerVM with wrapped customer entities, asynchronously:

            protected async override void GetData()
            {
                ThrobberVisible = Visibility.Visible;
                ObservableCollection<CustomerVM> _customers = new ObservableCollection<CustomerVM>();
                var customers = await (from c in db.Customers
                                       orderby c.CustomerName
                                       select c).ToListAsync();
                foreach (Customer cust in customers)
                {
                    _customers.Add(new CustomerVM { IsNew = false, TheEntity = cust });
                }
                Customers = _customers;
                RaisePropertyChanged("Customers");
                ThrobberVisible = Visibility.Collapsed;
            }

    4) regarding the insertion and deletion of the event propertycollectionchange observable collection is fine

    That's a statement rather than a question.

    You should make the user explicitly choose to add or delete an entity.

    In fact, it's only really administrator views where you're adding or deleting an entity. Usually you're raising an order or some such.

    5) use a repository to add / delete / update an entity with the repository and the repository is a class variable of the my viewmodel

    Just use dbcontext.

    There is no sense complicating things unless you have to.

    Mock the dbcontext if you need to automate testing.


    6) I have seen many examples on google but it seems that there is a bit of confusion on the topic

    And in the questions - that's a statement ;^)

    7) If I implements the property change on the model how do I know that the entity has changed? I have to respond at what event? according to the MVVM pattern

    This is rarely a problem since users are usually either changing data or reading it. They rarely do both in practice and any repository would be on their pc.

    The complication comes if you need to know some other user has changed data.

    That's a big subject of itself.

    Options include push notify from a server using signalr, or poll.

    For polling I usually add a table per significant entity which will hold a datetime stamped audit trail. That has time, username, type of change and id of record. Every 5minutes, 1 minute or whatever you can read the changes made since your last read and refresh any data you have in your dbcontext.

    Unless you're editing something, of course.

    8) I think that i respond to the selected change event  of the datagrid, but how?

    You can bind selecteditem and use the pattern here:

    http://social.technet.microsoft.com/wiki/contents/articles/30564.wpf-uneventful-mvvm.aspx#Select_From_List_IndexChanged

    9) if the properties are so many I can answer so the change of line, but how do I know that the entity has been changed? maybe I need to register all the changes in a helper class ? I have a bit of confusion in short

    Change tracking allows you to find which entities associated with a dbcontext have any changes.

    If you want to work disconnected then working out if the user really changed anything is sort of fiddly, but you could use the pattern here:

    http://social.technet.microsoft.com/wiki/contents/articles/30939.wpf-change-tracking.aspx


    thanks

    10)what is tracking in ef 6?

    It tracks changes of entity objects associated with a dbcontext.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Proposed as answer by DotNet Wang Sunday, June 19, 2016 4:09 AM
    • Marked as answer by DotNet Wang Monday, June 20, 2016 9:18 AM
    Friday, June 10, 2016 2:13 PM
  • >>1) visual studio does not generate the propertychange in the model classes that are generated by the db with code from the wizard "import from an existing db" must necessarily be implemented I think for the general operation

    INotifyPropertyChanged is a WPF/XAML specific interface and your entity classes shouldn't implement it. At least not if you intend to use the entity classes across several different layers and/or client applications. In an enterprise application, the model/entity classes is totally unaware of any client applications and they don't implement any client-specific interfaces.

    Instead you could create wrapper classes in your WPF application that wraps an entity class and adds property change notification, e.g.:

    public class WrapperEntity : INotifyPropertyChanged
    {
    private YourEntity type _efEntity;
    public WrapperEntity(YourEntity type efEntity)
    {
    _efEntity = efEntity;
    }
    
    //wrapper properties:
    public string Name
    {
    get{ return _efEntity.Name; }
    set { _efEntity.Name = value; NotifyPropertyChanged(); }
    }
    
    //...
    }
    

    >>2) how do I reflect changes on db when an entity is changed by the datagrid?

    You need to call the SaveChanges method on the context to persist the changes back to the database. WPF doesn't know anything about any database and a DataGrid only modifies the properties of an object in memory. It is your responsibility as a developer to call the SaveChanges method whenever you want to persist the changes: https://social.msdn.microsoft.com/Forums/vstudio/en-US/d62f7ddc-b3fe-4d60-b1f8-25a58c34458b/edit-and-add-records-to-ef-6-from-a-datagrid?forum=wpf

    >>3) to populate the datagrid using an ObservableCollection

    Bind or set the ItemsSource property of the DataGrid to an ObservableCollection: https://social.msdn.microsoft.com/Forums/vstudio/en-US/622794c7-28db-4fa4-9ee1-9b5ddbea5d59/how-to-bind-observable-collection-as-item-source-to-data-grid-in-wpf?forum=wpf

    If your original collection is not an ObservableCollection you could easily create a new ObservableCollection based on an IEnumerable:

    IEnumerable<string> theOrgColl = ...;
    ObservableCollection<string> coll = new ObservableCollection<string>(theOrgColl);

    >>5) use a repository to add / delete / update an entity with the repository and the repository is a class variable of the my viewmodel
    >>6) I have seen many examples on google but it seems that there is a bit of confusion on the topic

    Please refer to my blog post about how to implement a generic data access layer using EF: https://blog.magnusmontin.net/2013/05/30/generic-dal-using-entity-framework/

    >>7) If I implements the property change on the model how do I know that the entity has changed? I have to respond at what event? according to the MVVM pattern

    The setter of the source property is called whenever a property is being set. You could implement your properties to keep track of whether the wrapper class has been modified since the last call to SaveChanges, e.g.:

    public bool IsModified { get; private set; }
    public string Name
    {
    get{ return _efEntity.Name; }
    set { _efEntity.Name = value; IsModified = true; NotifyPropertyChanged(); }
    }

    >>8) I think that i respond to the selected change event  of the datagrid, but how?

    You generally bind the SelectedItem property of the DataGrid to a property of your view model and handle any logic in the setter of the source property.

    >>9) if the properties are so many I can answer so the change of line, but how do I know that the entity has been changed? maybe I need to register all the changes in a helper class ? I have a bit of confusion in short

    Implement logic to keep track of whether an entity/wrapper has changed in the setters of the properties as explained above.

    >>10)what is tracking in ef 6?

    Please ask EF related questions in the EF forum: https://social.msdn.microsoft.com/Forums/en-US/home?forum=adodotnetentityframework. This forum is intended for questions related to WPF only. By the way, if you google or Bing for this subject, I am sure you will find a lot of information that you won't get in a forum reply.

    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    • Proposed as answer by DotNet Wang Sunday, June 19, 2016 4:09 AM
    • Marked as answer by DotNet Wang Monday, June 20, 2016 9:18 AM
    Saturday, June 11, 2016 9:58 AM

All replies

  • Hi Giuseppe,

    You've asked 10 questions.

    Each thread is supposed to be one question.

    The title is supposed to be the question and the content of the post explanation and code/error.

    Entity framework has this thing called a dbcontext which is an instance class.

    It is effectively a sort of a repository so an extra repository is a bit pointless for small to medium sized applications.

    Hopefully you ( as a beginner ) are not designing and building some hugely complicated massive enterprise system. Because you have problems.

    Code first is a big mistake. Database first is way quicker and simpler. It is very very easy to mess up entity classes in subtle ways and get in a BIG MESS with code first.

    Let's try and go through these questions.

    1) visual studio does not generate the propertychange in the model classes that are generated by the db with code from the wizard "import from an existing db" must necessarily be implemented I think for the general operation

    Dbcontext tracks which entity objects have changes, it doesn't know about new ones. You can see code using this in the sample associated with:

    http://social.technet.microsoft.com/wiki/contents/articles/28209.wpf-entity-framework-mvvm-walk-through-1.aspx

    If you look in CustomersViewModel:

            protected override void CommitUpdates()
            {
                UserMessage msg = new UserMessage();
                var inserted = (from c in Customers
                                 where c.IsNew
                                 select c).ToList();
                if(db.ChangeTracker.HasChanges() || inserted.Count > 0)
                { 
                    foreach (CustomerVM c in inserted)
                    {
                        db.Customers.Add(c.TheCustomer);
                    }
                    try
                    {
                        db.SaveChanges();
                        msg.Message = "Database Updated";
                    }
                    catch (Exception e)
                    {
                        if (System.Diagnostics.Debugger.IsAttached)
                        {
                            ErrorMessage = e.InnerException.GetBaseException().ToString();
                        }
                        msg.Message = "There was a problem updating the database";
                    }
                }
                else
                {
                    msg.Message = "No changes to save";
                }
                Messenger.Default.Send<UserMessage>(msg);
            }


    2) how do I reflect changes on db when an entity is changed by the datagrid?

    You do SaveChanges.

    Don't try and write data back to the database immediately - give the user a commit button or something so they choose to save the data.

    You will find that there are a lot of problems with validation if you edit directly in a datagrid. It is way better to edit separately for that reason.

    You can see an approach for that in this:

    https://gallery.technet.microsoft.com/WPF-Entity-Framework-MVVM-78cdc204

    Where the user is forced to pick a record to edit. They change properties in an overlay.

    That is validated.

    They can save or abort their changes but they must change just one record at a time.

    If you let them, users will treat a datagrid like excel and you will find all sorts of "fun" edge cases where they manage to fail to save data or get several records in an invalid state otherwise. 


    3) to populate the datagrid using an ObservableCollection

    You are best "wrapping" each entity object in a viewmodel (rowvm) and binding to an observablecollection<rowvm>.

    Which you can see in that second sample.

    If you look at CustomersViewModel in that, here it is filling a new observablecollection of CustomerVM with wrapped customer entities, asynchronously:

            protected async override void GetData()
            {
                ThrobberVisible = Visibility.Visible;
                ObservableCollection<CustomerVM> _customers = new ObservableCollection<CustomerVM>();
                var customers = await (from c in db.Customers
                                       orderby c.CustomerName
                                       select c).ToListAsync();
                foreach (Customer cust in customers)
                {
                    _customers.Add(new CustomerVM { IsNew = false, TheEntity = cust });
                }
                Customers = _customers;
                RaisePropertyChanged("Customers");
                ThrobberVisible = Visibility.Collapsed;
            }

    4) regarding the insertion and deletion of the event propertycollectionchange observable collection is fine

    That's a statement rather than a question.

    You should make the user explicitly choose to add or delete an entity.

    In fact, it's only really administrator views where you're adding or deleting an entity. Usually you're raising an order or some such.

    5) use a repository to add / delete / update an entity with the repository and the repository is a class variable of the my viewmodel

    Just use dbcontext.

    There is no sense complicating things unless you have to.

    Mock the dbcontext if you need to automate testing.


    6) I have seen many examples on google but it seems that there is a bit of confusion on the topic

    And in the questions - that's a statement ;^)

    7) If I implements the property change on the model how do I know that the entity has changed? I have to respond at what event? according to the MVVM pattern

    This is rarely a problem since users are usually either changing data or reading it. They rarely do both in practice and any repository would be on their pc.

    The complication comes if you need to know some other user has changed data.

    That's a big subject of itself.

    Options include push notify from a server using signalr, or poll.

    For polling I usually add a table per significant entity which will hold a datetime stamped audit trail. That has time, username, type of change and id of record. Every 5minutes, 1 minute or whatever you can read the changes made since your last read and refresh any data you have in your dbcontext.

    Unless you're editing something, of course.

    8) I think that i respond to the selected change event  of the datagrid, but how?

    You can bind selecteditem and use the pattern here:

    http://social.technet.microsoft.com/wiki/contents/articles/30564.wpf-uneventful-mvvm.aspx#Select_From_List_IndexChanged

    9) if the properties are so many I can answer so the change of line, but how do I know that the entity has been changed? maybe I need to register all the changes in a helper class ? I have a bit of confusion in short

    Change tracking allows you to find which entities associated with a dbcontext have any changes.

    If you want to work disconnected then working out if the user really changed anything is sort of fiddly, but you could use the pattern here:

    http://social.technet.microsoft.com/wiki/contents/articles/30939.wpf-change-tracking.aspx


    thanks

    10)what is tracking in ef 6?

    It tracks changes of entity objects associated with a dbcontext.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Proposed as answer by DotNet Wang Sunday, June 19, 2016 4:09 AM
    • Marked as answer by DotNet Wang Monday, June 20, 2016 9:18 AM
    Friday, June 10, 2016 2:13 PM
  • >>1) visual studio does not generate the propertychange in the model classes that are generated by the db with code from the wizard "import from an existing db" must necessarily be implemented I think for the general operation

    INotifyPropertyChanged is a WPF/XAML specific interface and your entity classes shouldn't implement it. At least not if you intend to use the entity classes across several different layers and/or client applications. In an enterprise application, the model/entity classes is totally unaware of any client applications and they don't implement any client-specific interfaces.

    Instead you could create wrapper classes in your WPF application that wraps an entity class and adds property change notification, e.g.:

    public class WrapperEntity : INotifyPropertyChanged
    {
    private YourEntity type _efEntity;
    public WrapperEntity(YourEntity type efEntity)
    {
    _efEntity = efEntity;
    }
    
    //wrapper properties:
    public string Name
    {
    get{ return _efEntity.Name; }
    set { _efEntity.Name = value; NotifyPropertyChanged(); }
    }
    
    //...
    }
    

    >>2) how do I reflect changes on db when an entity is changed by the datagrid?

    You need to call the SaveChanges method on the context to persist the changes back to the database. WPF doesn't know anything about any database and a DataGrid only modifies the properties of an object in memory. It is your responsibility as a developer to call the SaveChanges method whenever you want to persist the changes: https://social.msdn.microsoft.com/Forums/vstudio/en-US/d62f7ddc-b3fe-4d60-b1f8-25a58c34458b/edit-and-add-records-to-ef-6-from-a-datagrid?forum=wpf

    >>3) to populate the datagrid using an ObservableCollection

    Bind or set the ItemsSource property of the DataGrid to an ObservableCollection: https://social.msdn.microsoft.com/Forums/vstudio/en-US/622794c7-28db-4fa4-9ee1-9b5ddbea5d59/how-to-bind-observable-collection-as-item-source-to-data-grid-in-wpf?forum=wpf

    If your original collection is not an ObservableCollection you could easily create a new ObservableCollection based on an IEnumerable:

    IEnumerable<string> theOrgColl = ...;
    ObservableCollection<string> coll = new ObservableCollection<string>(theOrgColl);

    >>5) use a repository to add / delete / update an entity with the repository and the repository is a class variable of the my viewmodel
    >>6) I have seen many examples on google but it seems that there is a bit of confusion on the topic

    Please refer to my blog post about how to implement a generic data access layer using EF: https://blog.magnusmontin.net/2013/05/30/generic-dal-using-entity-framework/

    >>7) If I implements the property change on the model how do I know that the entity has changed? I have to respond at what event? according to the MVVM pattern

    The setter of the source property is called whenever a property is being set. You could implement your properties to keep track of whether the wrapper class has been modified since the last call to SaveChanges, e.g.:

    public bool IsModified { get; private set; }
    public string Name
    {
    get{ return _efEntity.Name; }
    set { _efEntity.Name = value; IsModified = true; NotifyPropertyChanged(); }
    }

    >>8) I think that i respond to the selected change event  of the datagrid, but how?

    You generally bind the SelectedItem property of the DataGrid to a property of your view model and handle any logic in the setter of the source property.

    >>9) if the properties are so many I can answer so the change of line, but how do I know that the entity has been changed? maybe I need to register all the changes in a helper class ? I have a bit of confusion in short

    Implement logic to keep track of whether an entity/wrapper has changed in the setters of the properties as explained above.

    >>10)what is tracking in ef 6?

    Please ask EF related questions in the EF forum: https://social.msdn.microsoft.com/Forums/en-US/home?forum=adodotnetentityframework. This forum is intended for questions related to WPF only. By the way, if you google or Bing for this subject, I am sure you will find a lot of information that you won't get in a forum reply.

    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    • Proposed as answer by DotNet Wang Sunday, June 19, 2016 4:09 AM
    • Marked as answer by DotNet Wang Monday, June 20, 2016 9:18 AM
    Saturday, June 11, 2016 9:58 AM