Business Logic when Saving in Entity Framework - entity-framework

If I want to perform some action when an entity is saved, I can do something as described here.
However, suppose I retrieve an object from the database. This object has a list of items within it. If I instantiate a new item and add it to this list and then save all changes, the item in the list is not part of the "GetObjectStateEntries".

The problem for my situation, I believe, has been resolved. There appears to be a bug, in my opinion, in the ObjectContext.SaveChanges(SaveOptions) method. Even though this method will call DetectChanges (depending on the saveOptions), the OnSavingChanges method is called FIRST. This, I think, is a problem.
The solution to this is to call ObjectContext.DetectChanges() prior to calling SaveChanges().

Related

Storing a complex detached object graph in EF6

I have the current scenario:
I'm using EF6 Code first, and have created a data-model something like this:
public class MainObject{
..some properties
IList<SubObject> SubObjects{get;set;}
}
public class SubObject{
..some properties
IList<SubSubObject> SubSubObjects{get;set;}
}
public class SubObject{
..some properties
IList<SubObject> SubObjects{get;set;}
}
So basically I have a main object, that has 0 to many subobjects, and there is a many to many relationship between the subobject and the subsubobjects.
I am creating a MVC application, so my normal program flow is that the user request a page that basically uses a MainObject as it's data model. Then the user interacts with the page and changes, adds or removes subobjects and subsubobjects as he wishes, and then clicks save. On save, the objectgraph is sent back to the controller and it looks correct according to the changes done by the user on the client side. Now my problem is the following:
How to store this back into the database in a good fashion.
I need to attach my object back into the context, but I have no clue which objects are new, modified or deleted.
I have written some code that partially works now, but it's getting so ugly that I really don't want to go down that path. Would it be possible somehow to fetch the relevant object graph from the database, and have EF compare the two graphs toward eachother, and then save the relevant changes to the database?
Any help to make this smoother would be greatly appreciated.
I ended up using GraphDiff to solve this for me, and it works just great! This really should be built into EF, but untill it does, this is a great substitute.
To solve the example given in my question above, this will make sure that the detached graph gets saved properly (given I have a MainObject I want to save called main):
context.UpdateGraph(main, map =>map
.AssociatedCollection( m => m.SubObjects, with => with
.AssociatedCollection( s => s.SubSubObjects)
)
);
context.SaveChanges();

How to fix "EntityMemberChanged was called without first calling EntityMemberChanging"

This came up time and again for us. After reading such a message, there's nothing intuitive to do and debug.
What this poorly-documented error is trying to say is that you accidentally set up a system in which tracking changes causes more changes.
When Entity Framework changed a property on one of your entities, such as during SaveChanges with identity ID updates, you ran code that changed other tracked properties.
For example, the property that Entity Framework was setting triggered an event, perhaps INotifyPropertyChanged, which perhaps was subscribed to by a BindingSource or some binding list, whose ListChanged event handler was in the UI and triggered a calculation of some other property, and the change tracker detected the second property change.
The simple diagnosis is to place a breakpoint on the SaveChanges() call and immediately after the SaveChanges call(). When the first breakpoint is hit, place a breakpoint on each event handler that could possibly be triggered. (BindingSources are notorious for multiplying each other's events.) Continue debugging. If any breakpoint is hit other than the point immediately following SaveChanges, you know where the problem is.
The simple solution is to set a flag, such as IsSaving, on each side of the SaveChanges call. Then in each misbehaving event handler, do a simple check and do not modify any entities if the DbContext is in the process of saving. Make sure you use finally in case SaveChanges throws an exception that you catch at a higher level:
IsSaving = true;
try
{
await db.SaveChangesAsync()
}
finally
{
IsSaving = false;
}
(One other possibility is that you were changing the entity from multiple threads — never involve the change tracker in multiple threads!)
I had the exact same issue. I had wired to the INotifyPropertyChanged event that created the possibility for a property to change during the SaveChanges() call. I think it is a better practice to unwire the event handlers of you tracked entities when performing dbContext.SaveChanges(), Remove().
I'll explain my experience with this error, hoping it might help someone. And thanks to jnm2 for beautiful explanation.
I had Invoice and Receipt entities, and InvoiceViewModel.
Thie ViewModel was subscribed to Invoice property changed, inside which it was raising CanExecuteChanged events.
I added Receipt to Invoice navigation property and called SaveChanges(), which raised Invoice.ReceiptID property changed and triggered OnPropertyChanged event handler on the ViewModel, which in turn raised all kinds of CanExecuteChanged events.
The problem was that one of the CanCommandNameExecute methods was calling Context.ChangeTracker.HasChanges() which ultimately threw an exception.
How I fixed it?
I followed jnm2, I flagged VM with IsSaving and checked for the flag inside OnPropertyChanged event handler.
Once again, thanks jnm2, and hope someone finds this helpful as well.

Doctrine 2, Need to execute code pre-persist/post-persist

I am using Doctrine 2 entities. We have some entities which have to update related items when they are saved to the database. For example, when a user record is modified, we save it as a new record, with the "inactive" field set to 'false'. However, we have to set the the 'inactive' field for all previous record for that user to 'true'. This is done to keep an audit history. It is a Legacy database, so changing the structure is not an option.
Since Doctrine saves objects by passing them to a persister object (persist::($thisObj)), rather than the object having a save method ($thisObj->save()), we can't just extend a 'save' method from a parent object. The only option I see here is to try to extend the 'persist' object, but that sounds like a goose gaggle, just waiting to happen.
I found some information on events, but do not see how to add them to make events fire a particular function when a particular entity is persisted.
How do I add pre-save/post-save functionality to some of my entities ?
So, you probably already know http://www.doctrine-project.org/docs/orm/2.1/en/reference/events.html right?
You add an annotation that the entity contains callbacks and then create specific functions (which need to be public) on that entity and also annotate them with #PrePersist or #PostPersist or whatever.
The other way is creating an event subscriber, register that one with the doctrine event manager and implement methods called prePersist, postPersist etc. They get passed an EventArguments object which contains the entity relevant for the occurred event.
I know this is a very general answer to your question, but you need to be a bit more specific where your problem lies.
Please dont exend the entity manager and overwrite the persist method, there are way cleaner methods for doing what you need as far as I can tell.
It's actually quite simple to do what you want to do. It does not require dorking with the event manager, or anything complex like that. You use something called "Lifecycle callbacks". These are functions that Doctrine automatically runs during the "lifecycle" of the entity, ie: prePersist, postPersist, preUpdate, postUpdate, etc. You can find the complete list here: http://www.doctrine-project.org/docs/orm/2.0/en/reference/events.html
The process of adding this functionality to your entities is very simple.
In the Annotations section of your entity, include the following tag: "#HasLifecycleCallbacks". This tells Doctrine that it should search the entity for functions to run upon various events
Write a public function in your entity that you would like to fire upon a specific event.
Put an annotation above the function indicating which event it should be used to handle.
For example, look at the following code:
/** #PostPersist */
public function doSPostPersist() {
$this->tester = 'Value changed by post-persist';
}
I have found that sometimes the events simply refuse to fire, and I don't yet know why. But when they do fire, they will fire reliably.
Don't forget to enable Lifecycle Callbacks in your class annotation :
/**
* Report\MainBundle\Entity\Serveur
* #ORM\HasLifecycleCallbacks
*/
class Serveur {

MVC3: Repository Updates and ObjectStateManager

I have an Update method in my repository which I'm using to update articles on my project. I was initially using this method only to carry out admin edits for articles. It handles that correctly, but I decided I'd like to add a simple mechanism to calculate "most read" articles. In order to do that, I'd like to update TimesRead property each time an article has been viewed. This has been giving me trouble with the updates which seem to revolve around using ObjectStateManager.ChangeObjectState. Here's my Update method:
public void Update(Article article)
{
if (article == null) return;
db.Articles.Attach(article);
db.ObjectStateManager.ChangeObjectState(article, EntityState.Modified);
db.SaveChanges();
}
In my AdminController the following method updates correctly:
[HttpPost]
public ActionResult Edit(AdminEditViewModel viewModel)
{
if (ModelState.IsValid)
{
Article article = Mapper.Map<AdminEditViewModel, Article>(viewModel);
articleRepository.Update(article);
return RedirectToAction("Index");
}
viewModel.Categories = new SelectList(categoryRepository.GetAll(), "CategoryID", "Name", viewModel.CategoryID);
return View(viewModel);
}
However, in the TimesRead scenario, the update will trigger an exception of:
The object cannot be attached because it is already in the object context. An object can only be reattached when it is in an unchanged state.
Relevant code from that controller method:
var model = articleRepository.GetByID(id);
model.TimesRead++;
articleRepository.Update(model);
return View(model);
After having a look around to see what I can do to solve this, I came across the answer to this SO question. So I implemented that answer by replacing my Update method with the code suggested. This also works correctly in my admin scenario but not in the TimesRead scenario. The following exception is thrown:
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
The exceptions are quite clear in their meaning but it does leave me wondering how I am supposed to handle simple updates such as these. I found that I can "fool" the EF into thinking the model is unchanged by setting EntityState.Unchanged and that will update TimesRead but give an exception for admin updates, stating the ObjectStateManager doesn't hold a reference to the object.
It's also clear to me how these scenarios differ. The Edit action is mapping properties from a ViewModel onto a new, unattached Article object, whereas, ArticleController is dealing with an object retrieved directly from the context. That leaves me with the feeling I should refactor one of those controller methods so the steps taken to update are the same. I'm just not really sure how I should even approach that as both approaches seem like they should be able to coexist to me. So my question is, what can I change to get both types of update to work correctly?
Thanks for your time and I'm really sorry for the amount of code posted. I just feel it is all relevant to the problem.
The primary difference between your two methods is that the Admin Edit method creates a new Article from your AdminEditViewModel, then it attaches this newly created Article to your database. This works because it's a new object that has never been attached to a dc.
In the second case, you get an Article from the repository, update that Article, then try and attach it again, this fails because it's not a newly created Article, it's an Article returned from the db Context in the first place so it's already attached. and you are trying to attach it again.

Using different delegates for NSXmlParser

I am trying to figure out the best way to design something. I am writing an iPhone App and for the most part I am using async calls to a web service. This means that I cam setting up a URLConnection, calling start and letting it call me back when the data is available or an exception occurs. This works well and I think is the correct way to handle things.
For example:
I request a list of people from a web service. The resulting list is Xml Person elements which will be translated into an objective-c "Person" object by my XmlDelegate.
When I call the function to get the person, I pass in a "PersonResultDelegate", which is a protocol with a single function called "PersonReceived:(Person *)p". So, each time I get a complete Person object, I call that method and all is well. So, my detail view (or search result view) just receives the elements as they are available.
The problem comes when I need to obtain more then one specific object. In my specific case, I need to get the first and last appointment for a person. So, I need to make two API calls to obtain these two single Appointment objects. Each Appointment object will result in a call to the registered AppointmentResultDelegate, but how will I know which is the first and which is the last? I also need to somehow handle the case when there is no "first" or "last" Appointments and the Delegate will never get called.
What would be the correct way design wise to handle this? Should I add some additional context information to the initial request which is passed back to the handle in the delegate? An opaque piece of data which only makes sense to the person who made the initial call? What are my other options?
Solution
What I actually ended up doing is just passing an opaque piece of data along with the Appointment to the delegate. So, when I request an appointment object I have a method like:
getNextAppointment withDelegate:self withContext:#"next"
getPrevAppointment withDelegate:self withContext:#"prev"
This way when the delegate gets called I know what appointment is being delivered.
"Each Appointment object will result in a call to the registered AppointmentResultDelegate, but how will I know which is the first and which is the last?"
By looking at the order in which you receive these callbacks. Or by looking at some value in that xml data. Like a sequence or data. I don't know your data of course.