Refresh entity framework collection property - c#

I'm trying to update parts of my entity framework 6 entities, specifically collections with data from the database. Reading the data from the database the first time is fast so it should be possible to read it again quickly.
Disposing the context and creating a new one is fast, but it doesn't work for me, because doing so would lead to losses of information added by the user.
So in this case, I have a class called Evaluation, Evaluation has a many-to-many relationship through the class Amount to Classification. Classification in turn has n-1 relationship to Substance, i.e. one Substance can have multiple Classifications.
Evaluations and Amounts are handled in program A, while Classifications and Substances are handled in program B. The users frequently do updates in program B, which they must be able to see in program A, while a context is already opened.
In my user interface, the user adds Classifications to Evaluations, the user first selects a Substance from a datagrid, a second datagrid then shows the Classifications related to the selected Substance.
The substances are updated as they should, because the wpf binding is to a property that will always read from the database (using a few search parameters), so if I add or remove substances, they are added or removed in the UI as well.)
I managed to refresh Classifications as well, by binding to a property that returns:
_context.Classifications.Where(c => c.SubstanceID == SelectedSubstance.SubstanceID).ToList();
instead of just binding to the navigational property of the Substance.
In this way, additions and removals of Classifications are noticed in the UI. If I change a Classification property (that is shown in the datagrid), that change is not noticed though. And it's not a matter of the UI not updating, the View Model has the old value as well.
I can update the properties by doing:
_context.Entry(Classification).Reload(); // very slow for a single entity!
A Classification also has a n-m relationship to RiskPhrase through the entity ClassificationToRiskPhrase, these riskphrases are shown in the datagrid through a converter. At first, I wasn't able to get either the added or removed ClassificationToRiskPhrases, but doing this:
_context.Entry(Classification).Collection(c => c.ClassificationToRiskPhrases).Query().ToList());
Makes the additions appear, but if I remove a ClassificationToRiskPhrase, this isn't shown.
So my first question is: How do I update an entity so that removals in one of its collection navigational properties is noticed?
My second question is more general: What's a good way to handle partial refreshes in general, does anyone know of literature in any form which covers it? I guess it's common to keep a context alive during the time a user edits a certain entity? I know short lived contexts are prefered, but to keep all changes from being automatically saved, one has to wait before doing context.SaveChanges().

Related

Not able to remove items from database when user deletes a row in data grid

When a user hits the button, I'm executing the following code.
using (Context context = new Context())
{
foreach (Thing thing ViewModel.Things)
context.Things.AddOrUpdate(thing);
context.SaveChanges();
}
The updates are executed except for when the user selected a row and hit delete button. Visually, that post is gone but it's not really being removed from the database because it's not in the view model anymore. Hence, the loppification only ticks for the remaining things and not touching the removees.
I can think of two ways to handle that. One really bad - to remove everything from the context, save it and then recreate based on the view model. It's an idiotic solution so I'm only mentioning it for the reference's sake.
The other is to store each removed post in an array. Then, when the user invokes the code above, I could additionally perform the deletion of the elements in that array. This solution requires me to build the logic for that and I'm having this sense that it should be done automagically for me, if I ask nicely.
Am I right in my expectation and if so, how should I do it? If not, is there a smarter way to achieve my goal than creating this kill squad array?
At the moment, I do a double loop, first adding and updating what's left in the data grid. Then, removing anything that isn't found there. It's going to be painful if the number of elements grows. Also, for some reason I couldn't use Where because I need to rely on Contains and EF didn't let me do that. Not sure why.
using (Context context = new Context())
{
foreach (Thing thing in ViewModel.Things)
context.Things.AddOrUpdate(driver);
foreach (Thing thing in context.Things)
if (!ViewModel.Things.Contains(thing))
context.Things.Remove(thing);
context.SaveChanges();
}
The first thing I want to advice you is you should use the AddOrUpdate extension method only for seeding migrations. The job of AddOrUpdate is to ensure that you don’t create duplicates when you seed data during development.
The best way to achieve what you need you can find it in this link.
First in your ViewModel class you should have an ObservableCollection property of type Thing:
public ObservableCollection<Thing> Things {get;set;}
Then in the ViewModel's constructor (or in another place), you should set the Things property this way:
context.Things.Load();
Things = context.Things.Local;
From the quoted link:
Load is a new extension method on IQueryable that will cause the
results of the query to be iterated, in EF this equates to
materializing the results as objects and adding them to the DbContext
in the Unchanged state
The Local property will give you an ObservableCollection<TEntity> that
contains all Unchanged, Modified and Added objects that are currently
tracked by the DbContext for the given DbSet. As new objects enter the
DbSet (through queries, DbSet.Add/Attach, etc.) they will appear in
the ObservableCollection. When an object is deleted from the DbSet it
will also be removed from the ObservableCollection. Adding or Removing
from the ObservableCollection will also perform the corresponding
Add/Remove on the DbSet. Because WPF natively supports binding to an
ObservableCollection there is no additional code required to have two
way data binding with full support for WPF sorting, filtering etc.
Now to save changes, the only you need to do is create a command in your ViewModel class that call SaveThingsChanges method:
private void SaveThingsChanges()
{
context.SaveChanges();
}

Best way of dealing with dropdown list , item not in use, relational integrity?

this has come up a couple of times and was wondering how you guys would go about this (apologise if its a duplicate, its was tricky knowing what to search for):
So I have a web app that allows the editing of records. One of the properties of this record is a Guid, which is set via a dropdown list of options.
For this particular app, I need administrators to be able to modify the list of available options in the list of items that the dropdown binds to.
So what is the best way of dealing with a scenario where an administrator removes one of the options from the list (either a true database delete , or via an inUse? bool value change), meaning that any records that hold that value have no matching items in the parent list to bind against.Luckily in MVC the #Html.DropDownListFor helper just sets the selected value to null if the matching option isn't there, avoiding any NullRefExceptions, but then that would (in this case at least) make the ModelState invalid, and would mean that the record would not show up in any select queries based on that value.
Do I add a warning on attempt to delete / disable the option that x number of records would be affected, or disable the amend action entirely unless no records would be affected (requiring all records that hold that value to be amended in advance) ?
Thank you for your input in advance.
It depends. Simplistically, if an admin removes the previously set option, the next time the record is updated, the dropdown will be set to the default or empty option. As long as you're validating that something must be picked, then the user will get an error saying that they have to choose an option. It kind of takes care of itself, in a way.
However, relying on users to eventually clean this up is not ideal, to say the least. It's hard to say without specifics about what these options related to, but removing a potential option should not be done on a whim. If there's a valid reason for the removal, then there should also be a replacement in mind. If that's the case, then you can simply run a query to move all the records for the old, no longer available option to the new preferred option. If it's something that is removed and really has no replacement, then the actual foreign key should be nulled out in order to maintain referential integrity. That means the foreign key should be nullable in the first. If there's a business case for it being non-nullable, that should be enforced at the application level in validation, not at the database.
Long and short, after you remove one of the options, your data should be in a consistent state, without the intervention of a user. Then, if the user needs to take some action (because the relationship cannot remain null), you can notify them to come back to the application and select some new option.

How should a one to many relationship be managed in Entity Framework?

I am having trouble understanding at a fundamental level how a one to many relationship should be managed in Entity Framework. In my application I have two tables, DISPLAY_MASTER, and DISPLAY_ITEMS. Their relationship is like so:
DISPLAY_MASTER.DISPLAY_ID 1----->* DISPLAY_ITEMS.DISPLAY_ID
Entity Framework organizes this really intuitively. I am left with a strongly typed DISPLAY_MASTER object that has an ICollection property called DISPLAY_ITEMS.
My confusion lies within how to save the DISPLAY_ITEMS collection back to the database. In my application I am reading in all of the DISPLAY_ITEMS for the particular DISPLAY_MASTER using LINQ into a List<DISPLAY_ITEMS> object called _displayItems. This is then bound to a DataGrid for editing using MVVM. The user can edit existing DISPLAY_ITEMS, delete existing DISPLAY_ITEMS, or add new DISPLAY_ITEMS using the DataGrid. My binding works perfectly and these changes are reflected in _displayItems. Once it comes time to save is where I stop feeling confident in my code. When the user clicks save I am setting the DISPLAY_MASTER's ICollection like so:
_displayMaster.DISPLAY_ITEMS = _displayItems;
Is this the proper way to be working on an Entity Framework collection? Or should I be binding the DataGrid directly to the _displayMaster.DISPLAY_ITEMS object? Or some other method? The reason I am not confident is because if I try to validate the _displayMaster.DISPLAY_ITEMS entity using:
DbEntityValidationResult validationResults = _context.Entry(_displayMaster.DISPLAY_ITEMS).GetValidationResult();
I get an error saying 'List1' is not part of the collection, which obviously doesn't seem right.
Any advice or guidance would be appreciated.
Thanks.
It depends.
If you disconnect the entities from their database context when you bind them to the grid (i.e. if you dispose the context after loading the entities and create a new context when it comes to save the changes) then it's not so easy. You will have to load the master including the old items from the database, merge the changes into that collection based on your new edited collection from the grid and then save the changes. An example how to do that is here.
If you keep the entities attached to the context you have loaded them into while the user is editing it's much easier if you just directly bind _displayMaster.DISPLAY_ITEMS to the grid because EF is then able to track all the changes you are performing on the collection and update the object graph automatically to the database when you call SaveChanges.
Since you tagged the question with WPF you might have the second option (depending on your application's architecture). In web applications for example the second option doesn't exist at all because all editing happens in a browser which is disconnected of course from the context.

Entity Framework Code First POCOs and reasons why / why not setup relationships?

I wasn’t sure how to really word my question and I may change it based on some feedback.
When it is a good idea to have reference relationships (in my POCOs) setup so I can look up a parent record from a child or the reverse? Is it good practice to always have a way to “reverse” lookup an item or collection of items? I know it greatly depends on my application, but I just want to make sure of this before I start molding my application.
So, let’s say I have two tables: States and Countries. States has a relationship with countries (many-to-one) and vice-versa (one-to- many). My class for state would have a property for Country and my Country class would a property for a collection of states. This is pretty standard.
In that example it may make sense to allow a country to lookup the associated states. Can someone think of a time where I may not care about that association so I don’t have the overhead of loading the items for a collection or a single item?
It is more about design decission of your entities. If you are using code first you always need a navigation property on at least one side to create relation in the database. You can start with a simple approach and define property on a side where it make sense and add it to other side only if you need it somewhere.
There are situations where you know that you will never work with child entity without its parent (it leads to theory about aggregation roots whre child entity can't exist without its parent). In such case child doesn't need to have navigation property to parent.
In your scenario do you expect to work with State without Country which it belongs to? If yes it is probable that you would like to know which States a Country contains but in the same time you would probably would like to know which Country a State belongs to so defining navigation property on both sides make sense.

LinqToSQL and auditing changed fields

Here's another one of these LinqToSQL questions where I'm sure I must have missed the boat somewhere, because the behavior of the O/R Designer is very puzzling to me...
I have a base class for my LinqToSQL tables, which I called LinqedTable. I've successfully used reflection to get hold of all the properties of the descendant classes and do other standard stuff.
Now I want to have some automatic auditing of my tables, so that whenever a LinqedTable record is inserted or deleted, or a field value changes, I will insert a record into an audit table, detailing the change type, the field name, and its value pre- and post-save.
I thought I would be able to do it using the PropertyChanging event, keeping track of all the changed properties before a save, then clearing the collection of changes after each SubmitChanges() call. But - the generated code from the O/R designer, for some bizarre reason, doesn't give you the property name in the PropertyChanging event - it sends an empty string! (WHY?!) It does send the property name in the PropertyChanged event, but that's already too late for me to get the original value.
I thought to grab all the original values of all properties using the OnLoaded() partial method - but that is private by definition, and I need access to that method in the base class. Even if I used reflection to get hold of that method, that would mean I would have to implement the other half of the partial method for every one of my tables, which kinda defeats the purpose of having inheritance!
I also can't find any suitable method in the DataContext to use or override.
So what would you recommend to get this audit functionality working?
You can use GetChangeSet on the DataContext to retrieve a list of updates, inserts and deletes that have occurred on all tables within a context. You can use ITable.GetOriginalEntityState to retrieve the original values of a changed entity. However, when you retrieve the original values of a deleted or updated record, the associations will not be available so you will have to rely on foreign key values only in that area if you need to process related entities. You can Use ITable.GetModifiedMembers to help retrieve only values that have changed.
Forgive me for perhaps a stupid answer, but how about doing the audit directly in the SQL Server using triggers (if you are in SQL Server 2005 or 2008 standard) or using the change tracking facilities in SQL server 2008 Enterprise?

Categories

Resources