Wrong object added to ObjectContext (_addedEntityStore) - asp.net-mvc

I have a wizard in my asp.net MVC application which is built upon this SoG - RESTFUL wizard guide.
In order to understand the problem I will first explain the situation below. For this I will use a dummy situation, we try to create a person with an address. Again, this is just a dummy situation!
The situation
At start, the object (person) to be created and saved using the wizard is created as a blank object (person) and will be filled during the wizard 'stage'. In between the various wizard steps the person object is stored in the SESSION and retrieved with a key. This object has a relation with a sub-object. For example, an address. This address can either be retrieved from a DB using a dropdown-menu in the wizard or can be created in the wizard itself. This means that at creation I will create an empty address-object so we have the following initialization:
Persons p = new Persons();
p.Addressess = new Addressess()
This object is passed to the FormViewModel and used in the Wizard Form. Here I have a drop-down enabling to choose: (1) *create new address for person", which fills the passed empty-address object with data using the usual ways (TryUpdateModel()) and (2) "address x", addresses to select from your DB.
Selecting one of the addresses in the dropdown will, in the controller POST method, retrieve this object from DB and couple it to the person.Addresses. In code:
p.Addresses = repository.GetContactByID(id);
The problem
Everything works fine while running through the wizard pages. The problem occurs when I call the savechanges(). While in a final overview the complete object to be added is shown correctly (person info + address info as selected / passed), also an empty address is saved to the database.
repository.SaveChanges();
This will try to add an empty Addresses to the DB which will introduce a ModelState error since Addresses have some non-nullable's which are not set for the empty object.
** My current idea **
My current thinking is that the empty object created at start for the blank object is somehow placed in added state (objectcontext) when I first couple it to person.Addresses. Can this be the case? What would be the correct way to do what I want? Can I manually delete things from the object context _addedEntityStore ?
Additional Info
Selection of an address in the dropdown will force a form.submit to the POST controller method and consecutively it will reload the form with updated selection info and the input fields for the new address (in case a new one is wanted) set to "disabled" so you only see the info but cannot edit an existing address.
Also, only one objectContext is used which is saved in the SESSION.

Any reason you can't just leave p.Addressess as null when you first create a Persons object and only add a new Address if that's what they select in the wizard?
(And BTW why the odd pluralization? Do they have one address or several?)
The other issue you will encounter is that you will be loading existing addresses in one context and saving them in another (assuming you are using a context per request approach) - you'll need to detach the existing addresses from one context they were loaded in and attach them to the context used to save Person at the end of the wizard.
It might be easier to include a separate AddressNew and an AddressExisting object in the Session state (one or the other is null). At the end, if AddressNew is present, add it to the Person and save changes. If AddressExisting is present, attach it to the context, add it to the Person and save changes.

Although Hightechrider is right about using an object context for every unit of work I post the simple solution I used for now. When you somehow (forced, chosen, whatever) have your object context stored in SESSION you can solve the above problem simply by calling:
repository.Detach(person.Addresses)
Which will detach the old object from the context (not saved yet to DB). And after detaching, attach the new object you want to have it linked to.
person.Addresses = repository.GetAddressByID(id);
// or
person.Addresses = new Addresses();
Though I do recommend rewriting your wizard if you need to do this and have the time and power :).
edit
note that Detach only detaches the object supplied, not its related objects (!).

Related

Cocoa Core Data - best practice to check if object with the same property already exists

I would like to check with you the best practice to solve the following task in Core Data framework. In my model one of the property for one object type must be unique. Let's say I have object Account - the property name must be unique - it is not allowed to have 2 accounts with same name.
There are 2 possibilities:
either I execute validation before I call insert into context -> at this point my new object is still not inserted into context, so I can call fetch from context and check if there is already account with particular name
or I overwrite built in validation methods and put my validation there as mentioned here:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdValidation.html#//apple_ref/doc/uid/TP40004807-SW1 - all these validation methods are called only after context is saved
I personally like second case, because my validation would be in model. But the problem is that at this point the object is already inserted into context and therefore if I call fetch, the validation always fails, because also the name of new object counts (even if is still not saved permanently). There is a solution for this however. I can check solely the permanent saved objects by creating new temporary managed object context and call fetch
Is this the best practice to execute such a validation. Or am I missing something or there is better way to do it ?
BR
Lubos
I would go about it in the following way. In general, it is advisable to avoid the complexities of multiple contexts, although that too is a pattern demoed by Apple.
Create the new managed object, insert it into the context. Check against existing names. If the name is not valid, prompt for a different name. Repeat until the name is valid. If the user breaks off the process or times out, delete the object.
If you can do that before saving, discarding the object could be as simple as calling [context rollback];.
If you do this in a separate controller, you could do it in a child context. If the user terminates the process, you just throw away the context altogether without saving.
If you find a name exists but suspect that it is the name being created you can easily check it it is the same object (you already have a reference to it). You could also do a fetch (or, more efficiently, countForFetchRequest) with a predicate that excludes this particular object.
NSPredicate(format:"name = %# && (not self = %#)", account.name, account)

With Breeze.js, Is There a Way to Create an Uninitialized Entity and Bind It to an "Add New" Form?

So far all of the examples that I have seen for adding a new entity would go through the following steps:
Create a bunch of "new-" variables that get bound to on screen controls.
When user wants to submit the addition, created an uninitialized new entity.
Copy "new-" variables to each member of the new entity one by one.
Push the new entity onto the manager's entity list.
Save changes.
Clear all of the "new-" variables.
This is problematic for many reasons. These "new-" variables have to be maintained in addition to the on screen controls. When server side entities change, they must be changed manually. This is time consuming and error prone.
I would like to be able to create an uninitialized new entity first, and bind it to on screen controls immediately, without using those variables with the "new-" prefix. When user wants to submit the addition, push the new entity onto the manager's entity list, and then save changes. Then bind the on screen controls immediately to a newly created uninitialized entity.
This way, we can avoid dealing with individual entity attributes in the view model, which would produce more robust code, and save a lot of time.
Right now, the metadata for creating a new entity is not available when the document becomes ready. If I download it, I have to deal with asynchronous completion before I can bind a new entity to on screen controls.
So my question is: is there a way to have the metadata downloaded with the initial HTML download so that I can create an uninitialized new entity without waiting, and bind it to on screen HTML controls immediately?
I'm not sure what means uninitialized new entity, but yes - you can create for example a new car like this:
var newCar = manager.metadataStore.getEntityType("Car").createEntity();
manager.addEntity(newCar);
Bind your controls to the newCar. To save the changes call manager.saveChanges();, to cancel call manager.rejectChanges();
To be able to work with entities breeze needs metadata. If you want, you can send metadata with the page itself. You can then use manager.importMetadata() to import it into the manager. The only problem is that you will need to write a small app that will generate the metadata string (during build) so that later it can be passed to importMetadata(). Take a look at MetadataStore Class API for more info.

Entity Framework complaining about required fields when saveChanges even if valid data are setted

I'm using Entity Framework (DbContext with database first) with MVC. When user save from a form, I have a condition in the controller that send the entity to the update of insert method depending of some internal flag of mine.
When sending entity to the update method, I flag it to modified using context.Entry(myEntity).State = EntityState.Modified;, I call saveChanges() and everything work well.
When sending the entity to the insert method, I flag it to added using context.Entry(myEntity).State = EntityState.Added; but when calling saveChanges() I receive error about 2 fields that are required...
The problem is that thoses 2 fields are not empty and they effectively contain valid data just before saving... I have even try to force new values to thoses 2 fields just before saving but same error.
It may be usefull to mention that I'm using Devart DotConnect For PostgreSQL as db provider.
Any idea how to debug this problem?
EDIT:
Here is the error:
Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
When looking for this EntityValidationErrors I receive the 2 following specific errors:
The flg_actif field is required
The user_creation field is required
As mentionned before, those fields are filled with data just before saving so I don't understand what is happening.
I'm using EF v4.0.30319 (system.data.entity=> v4.0 and EntityFramework=> v4.4)
EDIT2:
Just to clarify a little bit more: The entity I'm trying to insert already exist in database. The form show the data of this database row. When saving, I decide if I update the row (this work well) but sometime, I need to insert the edited row as a new register instead of updating it to keep an history of the change in database.
Could you verify if the EntityKey property is set or null on the items you are trying to save?
If it already has a key, the context is already aware of the item, and you should use Attach instead of setting the state to added manually.
EDIT: To summarise the point from below. It looks like what you are doing is inserting a new copy of a row already associated with a context. That is almost certainly your problem. Try creating a fresh object based on your original row (i.e. copy the variable values or use a copy constructor), then add that new object.
Additionally, you should not need to set the state manually on a newly added object. You are trying to force the state here because the context doesn't see that item as a new one.

Entity Framework creating new record instead of modifying existing one

I'm using Entity Framework with an AS.NET MVC application. I need to allow the user to create new records and modify existing ones. I am able to fetch existing records no problem, but when I pass back in the edited entity and try to save it it creates a new one and saves it and leaves the original unmodified.
I am getting the object from EF using the primary key (e.g. ID number for an employee record). I successfully retrieve it, and set the MergeOption like so:
Context.Sector.MergeOption = MergeOption.NoTracking;
I am able to trace that the object has the correct data (using the key of the original record) all the way down to the point where I call:
Context.SaveChanges();
However, after that, the new record is created instead of modifying the existing one.
Is there something obvious I am missing here? I would have thought that retrieving the object and changing some of its values (not the ID) and saving it would just work, but obviously not.
Thanks,
Chris
"NoTracking means that the ObjectStateManager is bypassed and therefore every access to the Entity Objects results in a fetch from the database and the creation of new objects."
-- http://blog.dynatrace.com/2009/03/11/adonet-entity-framework-unexpected-behaviour-with-mergeoptions/
I don't think NoTracking is what you want.
From your comment: "distributed across various tiers and some proprietary libraries"
Are you new()ing up a ObjectContext, closing it or losing the reference to it, and then trying to save your object to a new() or different ObjectContext?
If so your losing all of your change tracking information. If this is the case then you want to call the Attach() method to reattach the entity to the context, ApplyPropertyChanges() and then finally SaveChanges().
Julie Lerman has a pretty good blog post that outlines all the different change tracking options and techniques that are available. You should also check out this MSDN article on the same subject.

Create a New big Object Wizard: ASp.net MVC

Here's my question:
I need to write a wizard, for customers to "create a new" very big objetc, with some other asociated with it: for example, Some images stored in another table (with relationships), some Lat's and Lang's for google earth, etc.
Each of them are stored in diferent tables in the Database, and that's why, i have to first insert to get the first object's Database generated ID to make the relationships with the another Objects. That's the reason I think puttin' Everything on just one View and hide selective DIVs with Jquery is not one of my option.
Session isn't an option because of the bigger object.
And because of the type of website, the wizard MUST be as follows:
Basic details of objetct 1
Images of object 1 (I will need here the ID of the first object)
Geolocations (with google maps, as before)
More details of object 1.
Preview
Publish
The point is, in step 4, user fill some fields that are required by the DB, and I cannot make them nullable as is it part of the customers reqs.
If somebody can a least give Ideas, will be nice...
Thanks in advance
You state that storing your object in Session is not desirable because of the size of the object. An alternative is to serialize that object and store it in the database. As the user progresses through the wizard, that object gets retrieved, updated and stored back in as a blob. Once they publish it, you can insert the appropriate records and remove the serialized object from whatever table you're storing them in.

Resources