What is the best way to mark some entities DeleteOnSubmit(). Is there a way to check and say to the context that this is for deletion?
Example: I have an Entity which reference an EntitySet<> and i delete from the EntitySet<> 4 of the 8 entities. When submitting changes i want to say DeleteOnSubmit() on those 4! This scenario should play on a single EntityRef<> too.
Of course DataContext lives in another layer so...grabbing, changing, sending back is the job.
Thank you.
This is pretty hard to answer based on the description of your architecture. Just because you're using a layered approach doesn't mean that you can't call DeleteOnSubmit... you'd just call your own method that wraps that I presume.
Unless, of course, you're instantiating your DataContext object in the update routine. in this case you'd have to do something else. Your data layer could expose a method like MarkForDelete() which just adds the entity to a collection, then expose a separate SubmitChanges() that iterates over the collected items for deletion, attaches them to the datacontext and then does the actual DeleteAllOnSubmit() call.
That said I've never really bothered with the whole entity serialization/deserialization/reattach thing as it seems fraught with peril. I usually just collect the primary keys in a list, select out the entities and re-delete them. It's no more work, really.
Take a look at DeleteAllOnSubmit(). You pass this method a list of entities to be deleted.
Related
Excuse me for my broken English.
In my application, all objects in the context have a property called ObsoleteFlag, which basically means if the object should still be used on the frontend. It's some sort of "soft-delete" flag without actually having to delete the data.
Now I want to prevent EF from returning any object where ObsoleteFlag is set to true (1)
If for example I retrieve object X, the navigational list property Y contains all the related objects of type Y, no matter what the ObsoleteFlag is set to.
Is there some general way of preventing EF from doing this? I don't want to check on the ObsoleteFlag property everywhere I access the context, and for every navigational property that may be loaded too.
Thanks and sorry for my broken English.
Two different approaches:
In your repository layer have a GetAllWhatever() that returns IQueryable<Whatever> and uses Where(x => !x.Obsolete) and use this whenever you retrieve objects of this type.
Create a view of Create View ActiveWhatever As Select * from ActiveWhatever Where obsolete = 0 and bind to that rather than the table.
The first is essentially checking the flag every time, but doing so in one place, so you don't have to keep thinking about it.
The second is much the same, but the work is pushed to the database instead of the .NET code. If you are going to modify the entities or add new entities you will have to make it a modifiable view, but just how that is done depends on the database in question (e.g. you can do it with triggers in SQL Server, and triggers or rules in PostgreSQL).
The second can also include having a rule or trigger for DELETE that sets your obsolete property instead of deleting, so that a normal delete as far as Entity Framework is concerned becomes one of your soft-deletes as far as the database is concerned.
I'd go for that approach unless you had a reason to object to a view existing just to help the application's implementation (that is you're heavily into the database being "pure" in being concerned with the data rather than its use). But then, if it's handy for one application it's likely handy for more, given the very meaning of this "obsolete".
I'm having a problem with Entity Framework and filtering architecture.
Let's say that I have a couple of related entities, and I want to do some changes to them, based on a filter.
So, for example I have Orders and Orderlines (to put a simple example)
I have order1, with orderline1, orderline2, orderline3 relationships in the DB
Then I receive an update request for order1 but only for orderline1 and orderline3
I get the data from the db using entity framework, which retrieves an objectgraph of the order and its lines.
Is there a way to filter these entity objects so that I can work with an objectgraph that contains order1 and orderline1 and orderline3, but NOT orderline2 without that being a problem later?
Because if i remove orderline2 from the entitycollection, i get later on concurrency errors (or deleted entities, which is something i don't want)
I hope the question is clear, I know that there could be other ways (iterating and not performing updates on orderline2, so it remains the same and no changes are made) but the way the architecture was made doesn't let me do that right now.
If I could say "don't track any more changes to orderline2, just ignore any changes that I do to this particular object and descendants, just leave it in the DB the way it is", so that I can just remove it from the collection and move forward, that'd be perfect
Thanks!
You can go multiple ways as you already described yourself as well:
Iterating through all orderlines and only modifying those that need to be modified (but that isn't an option as you stated)
The alternative you described to specifically not track changes for orderline2 is not possible in a "normal" EF situation where the ObjectStateManager is responsible for change tracking (as far as I know). In a scenario with Self Tracking Entities it's more easy because every STE has it's own unique ChangeTracker on board which can be easily switched off.
But the most easy option would be to exclude the orderlines you dont want to modify in the "select" statement or the retrieval of the entities. Something like:
private void ModifyOrderLines(int orderID, List<int> orderlineIds)
{
using(Context context = new Context)
{
List<OrderLines> orderlines =
context.OrderLines.
Where(orderLine => orderLine.OrderID == orderID && orderlineIDS.Contains(orderLine.ID))
}
}
Assuming you have set up clean foreign key relationships which were translated into Navigation Properties in EF. So what you do is to get a list of OrderLines which belong to a certain order and have an ID that's in your list of OrderLines that need to be modified.
Afterwards you change the orderlines and apply the changes to the context and call SaveChanges. This is just a basic way of how you could do things. I don't know your exact setup but I hope this helps.
EDIT
Based on your comment I should just go for the easy way and write a loop as you already proposed. Why not? I don't think there are many alternatives, and if there are then they would make things overcomplicated.
So something like this might just work:
ObjectContext.OrderLines.ForEach(o => if(orderlineIds.Contains(o.ID) {o.SomeProperty = SomeValue}));
Or you could just write the loop yourself.
EDIT2
You already mentioned detaching from the ObjectContext in the title of your post. Why don't go that way then? You tell that you have no control over the ObjectContext that you get, that it is passed into several methods and that you get update requests for certain entities. Then detaching those entities that are not needed for the update request can be an option too. Maybe this topic on MSDN might help you decide. Afterwards you might attach the detached objects again for they maybe needed for subsequent "client" calls. But this depends on how you manage the ObjectContext.
Do you keep the ObjectContext "alive" over multiple "client" calls or do you instantiate it over and over again for specific client calls. I do not get the situation totally clear...
Suppose we have class PersonModel, user edits a detail form in the browser and hits the submit button.
How to write a controller logic to create an UPDATE SqlComand (no EF) and update only those of fields from class PersonModel (FirstName, LastName, Age...) which have been changed.
What should be an argument of the /Person/Edit/<id> controller?
You don't do anything special to your MVC code, and you don't add any special URL parameters.
If you only want to update the changed fields, then you have to write a lot of code. You have to get the current record, compare each of your models fields to the records fields, figure out which ones have changed, then you have to construct a SQL statement based on the changed fields, then update it, making sure to use optomistic record locking to insure the field has not changed between when you retrieved it and when you update it.
This is probably going to be a couple hundred lines of code. Or it could be one line of code if you were using an ORM.
Also, keep in mind you need to use parameterized statements as well, to insure against a SQL injection attack (something you get for free in an ORM as well).
Good luck, I certainly am not going to write it.
What I would suggest is that you don't use the generalized PersonModel which I assume is a 1:1 representation of your data model. You should create a watered down view model of with only the fields you care about. Then use something like AutoMapper to map the ViewModel back to your DomainModel.
Here is a reference on how to use AutoMapper for such a scenario.
How to cross map objects using AutoMapper
You may use Linq and let the datacontext do everything for you.
In the Model you just create your data class with the linq queries for the update, retrieve the object, set all the values that have been passed from the view in the object you've retrieved (you'll have to do this anyway, since the pattern decouples the view from the model | Remember too, that MVC implements observer for letting the view to know about changes in the model, so you can't know what was modified in the view from the controller), and then you call the DataContext.SubmitChanges(); method. The data context will do the job in its own. It will know what to change and modify and will make the most performant query.
I am asking in order to know what is the best practice for such cases. I am using EF4.
I have two entities called "Note" and "Product". I have another entity called "Stock".
Note has many Products and each Product can be in one Note only (Product must have a Note).
Whenever I insert, Delete or Update a Product, I have to update the relevant Stock entity according to the Note attached to the Product.
In the InsertProduct() method I insert the Product and then update the relevant Stock. In case the Product will break the Stock rules - I get an exception and the operation will abort as should be.
In the InsertNote() method, I cannot insert the Note because such thing will insert automatically the attached Products and for each Product I need to update the Stock and validate Stock rules (as described above). So before the Note insertion I loop through all the Products and call to InsertProduct(). After that I insert the note.
Until here two questions:
Does the things should be like that? Do I need to manually insert
each Product before I insert the Note? How does this settle with the
fact Product must be attached to exists Note (in the time of
insertion the Products, the Note wasn't inserted)?
Where should I put the InsertNote() and InsertProduct() methods?
each one of them deals with Note, Product and Stock entities. Should I create something like NoteService and ProductService classes or should I put them in one big service class?
In the question I asked here, I got an answer that describe how to create events like OnBeforeInsert(). Is this implementation is fine with my needs to update the Stock after insert Product?
I'm not quite sure I fully grasp what you're trying to do and what it means to validate Stock rules and update stocks. But it seems like you're trying to reuse InsertProduct from InsertNote when you shouldn't be.
It seems like InsertNote should
check all the rules and update Stock accordingly (I'm assuming this means loading the stocks into the context from the database or attaching them if you have them in memory somewhere)
add the new Note to the context (which will add the new products you've put into its collection before)
SaveChanges()
and InsertProduct should
check/update stocks as above
add the Product to the Note's collection of Product
SaveChanges()
In other words, both these methods would reuse just the rule checking part. InsertProduct might be better renamed to UpdateProductsOfNote because it sounds like Note is an aggregate root of your model (In DDD, you do persistence/repository operations against the aggregate).
As to where these methods live, if they are not too complex, adding them to a repository/data access class (that owns the EF context object) would be ok. It does seem like they have quite a few rules associated with them. If so, some sort of domain service would probably be a better choice. It seems like much of the rules aren't simply to support persistence. If you relocate these methods then you may not need to handle ObjectContext events as you asked in the post you referenced.
Can someone tell me how to exclude some entity from context before saving changes.
For Example i have 2 entities Actions and Users and i want to save only users?
I you changed an Action and you don't want to modify it you can either detach it from context or set it as unchanged (that is like hack).
Detaching entity:
context.Detach(action);
Setting state to unchanged:
context.ObjectStateManager.ChangeObjectState(action, EntityState.Unchanged);
Be aware that if you also changed relation between Action and User you will also need to reaset state of the relation by calling ObjectStateManager.ChangeRelationshipState.
Anyway you are doing something wrong because this situation should not happen. You should always modify only entities you want to save. If for any reason you need to modify only part of them your approach with clonning entities and modify them in other context is correct. Context is unit of work. You should modify only entities which are part of the same business transaction.
That's not possible as the SaveChanges method works on context level, not entity level.
Well the best option would be not to modify the entities unless you really mean to change them. However you can change their state. The book Programming Entity Framework has details on this.
I solve this by creating copy of entities Action with all child's (deep copy), and when i changed them i worked on the copy.
You can change the state of the changed objects (of type Action in your case) to "Unchanged" using the ObjectStateManager like so:
context.ObjectStateManager.ChangeObjectState(actionObject, EntityState.Unchanged);
I hope this helps :)
ps: you can get the list of modified objects using this:
var modifiedActions = context.Actions.Where(a=>a.EntityState!=EntityState.Unchanged);