Workaround for Entity Framework Context.Refresh bug? - asp.net

I ran into this problem using EF4 and a self-referential table (implementing an adjacency list hierarchy).
NOTE: not a many-to-many reference, just a one-to-many on a single table.
Attempts to resolve an intermittent InvalidOperationException ("...The ObjectContext might be in an inconsistent state...") using Context.Refresh fail due to an apparent bug in EF4.
I saw, from following Shimmy's connect.microsoft.com link, on the aforementioned post, that the bug is still outstanding.
Can anyone recommend a workaround?
What do you do if your database and Entity Framework get out of sync?
EDIT
Some more facts that may help:
When I get the InvalidOperationException and the message says "The changes to the database were committed successfully...", it is not true. They weren't.
I tried to change an object's ParentId from 1 to null (ParentId of type int?).
My object's ParentId attribute is correctly changed to the expected value (null). I call Context.SaveChanges(). Then, the exception is thrown. I check the DB, and the value has not been updated. In this case, ParentId is still 1 in the database.
Inside the catch, if I try to requery the object via myObj = Context.MyObjects.SingleOrDefault(o => o.Id == id), the object's ParentId remains the same. It does not get updated by the (incorrect) database value!
Now I think, Okay, that seems weird, but maybe if I save again the db will be corrected.
Calling a subsequent Context.SaveChanges() from inside the catch still does not update the database. (But this time, an exception is not thrown.)
If I make a new call to my SetParent method,
myObj = Context.MyObjects.SingleOrDefault(o => o.Id == id),
correcly populates the object's ParentId parameter to 1, the value from the database.
Additionally, for giggles, I set the object's ParentId to it's own Id, instead of null, to denote parentlessness. This worked fine and did not cause the InvalidOperationException. But, it's a PITA for other reasons. E.g., the object reports having itself as an extra child.
So, the questions are:
What is it about trying to set my self-referential int? ParentId to null that causes an exception?
Why does the db not get updated before the exception?
And why, inside the catch, can't I resync?!

Requery the object from the database through the context...
EDIT - in response to your update, if you submit changes for an object within a context, an an error happens, using the same context most likely is the problem. Try recreating the context in the catch to requery and reupdate, and see if that works any better.

Related

ASP.NET Entity Framework determine if context saved successfully

I'm having a discussion with a friend about how to check if the context was saved successfully in Entity Framework.
His opinion is that we should check the integer returned by SaveChanges() and compare it to what we expected
Example: Check expected with returned
Mine is that we can assume that SaveChanges() did it's job and everything was saved to the database if no exceptions are thrown.
Example: Catch exception
I found two similar question here, but they don't explain much.
one
two
So which method is better, and why?

Saving changes with Entity Framework causes detached entity duplicate

I'm making a survey program that has a list of questions that are pulled from the database as entities. During the course of the survey the properties of the entity may be edited, but I do not want these changes persisted to the database. So, I detach the questions after they are loaded into the dbcontext and access them via a dictionary.
The problem arises when I attempt to save an answer to the database. Since the answer entity is related to the question entity (that has been detached) a completely new question entity is then added to the database. I'm not sure why this is occurring as the answer entity being added contains the proper ID of the detached entity (when I look at it in the debugger). However, upon saving changes it gets updated to the ID of the newly created duplicate entity.
Is there a way to stop this behavior? Or alternatively, is there a way to make changes to an entity and not have them persist to the database even when SaveChanges is called on the context for writing a answer or a log entry to the database?
Here is the code that loads, then detatches the questions (items):
public FixedLengthBlockElementRuntime(FixedLengthBlock block, RuntimeContext context) : base(block, context)
{
this._items = ((FixedLengthBlock)this.Element).ItemBank.Items.OfType<FixedLengthItem>().ToDictionary(x => x.ItemName, x => x);
foreach(FixedLengthItem fixedLengthItem in this._items.Values)
{
this.Context.DetachEntity(fixedLengthItem);
}
}
And here is the code that adds the duplicate entry:
public void SetResponse(Response response)
{
response.Session = this.Session;
this.DbContext.Responses.AddObject(response);
this.DbContext.SaveChanges();
}
Note that Response has the proper ItemId until the point of Saving Changes.
You can set the MergeOption on your questions DbSet to be OverwriteChanges.
Context.Questions.MergeOption = MergeOption.OverwriteChanges;
You'll need to be sure you set that BEFORE you make the query for the questions for this to work properly however.
More reading on how MergeOptions work

how to find out where a property is called from unmanaged code

I have an MS ReportViewer report that is bound to a datasource, that is requesting a property that it shouldnt. I have checked all of the fields on the report and I cant find anywhere its used.
Putting a break point on the property shows its definately being called, but I cant find out from where as its the ReportViewer is making the call.
****Is there a way to find out where this property is being called from?**
Here is what I have checked so far:
Stack Trace: shows managed code, checked the disassembly but couldn't see anything obvious.
Call hierarchy shows all the places that property is called from - none of which are on the report.
Update:
Tried n8wrl's suggestion of throwing an exception, but the stack is still on unmanaged code.
Update 2
I have also tried adding Xml and Script ignore tags in case the object as being serialized somewhere but that didn't work (unless they are not the correct tags to ignore serialization?)
Ok, I have come up with a solution. I assumed this had something to do with serialization so I passed the datasource in to a System.Web.Script.Serialization.JavaScriptSerializer.
When serializing the object I found all of the properties that were causing the code to bomb out. I added [ScriptIgnore] tags to these properties to stop them begin serialized as they were not used.
System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
serializer.RecursionLimit = int.MaxValue;
object o = serializer.Serialize(base.CurrentOrder);

CTP 5 EF Code First UpdateModel()

I've been struggling with this issue for a few days now and I'm still not able to figure it out. I've created a sample project to hopefully help figure this issue out. The main issue is when I load a user from my context and perform an UpdateModel() on this object it seems to delete my entity references and I get null references in child objects.
Here is the error:
The operation failed: The relationship
could not be changed because one or
more of the foreign-key properties is
non-nullable. When a change is made to
a relationship, the related
foreign-key property is set to a null
value. If the foreign-key does not
support null values, a new
relationship must be defined, the
foreign-key property must be assigned
another non-null value, or the
unrelated object must be deleted
.
Here is the link to the code:
Here (line 42, causes the error to happen)
I figured this question out thanks to Morteza Manavi on the entity framework website. My issue was caused by my ContactInformation model properties, 'contactid' & 'contacttypeid' not being nullable. Once I fixed this everything with UpdateModel() worked correctly. Thank you very much!
Have you used any data annotations on your key values like [Required] or [StringLength], that would explain the error message.

Problem persisting collection of interfaces in JDO/Datanucleus. "unable to assign an object of type.."

I am getting below error whilst trying to persist an object that has a collection of interfaces which I want to hold a couple of different types of objects. Seems to be happening almost randomly. Sometimes after restarting it works ok ( I might be doing something wrong though).
class CommentList {
#Persistent
#Join
ArrayList<IComment> = new ArrayList<IComment>();
}
somewhere else...
CommentList cl = new CommentList();
cl.addComment( new SimpleComment() );
cl.addComment( new SpecialComment() );
repo.persist( cl );
I can see the join table has been created in my DB along with ID fields for each of the Implementation classes of IComment.
SimpleComment and SpecialComment implement IComment. If I just add a SimpleComment it works fine. As soon as I start trying to add other types of objects I start to get the errors.
error im getting
java.lang.ClassCastException: Field "com.myapp.model.CommentList.comments" is a reference field (interface/Object) of type com.myapp.behaviours.IComment but DataNucleus is unable to assign an object of type "com.myapp.model.ShortComment" to this field. You can only assign this field to a type specified by the "implementation-classes" extension attribute.
at org.datanucleus.store.mapped.mapping.MultiMapping.setObject(MultiMapping.java:220)
at org.datanucleus.store.mapped.mapping.ReferenceMapping.setObject(ReferenceMapping.java:526)
at org.datanucleus.store.mapped.mapping.MultiMapping.setObject(MultiMapping.java:200)
at org.datanucleus.store.rdbms.scostore.BackingStoreHelper.populateElementInStatement(BackingStoreHelpe
r.java:135)
at org.datanucleus.store.rdbms.scostore.RDBMSJoinListStoreSpecialization.internalAdd(RDBMSJoinListStore
Specialization.java:443)
at org.datanucleus.store.mapped.scostore.JoinListStore.internalAdd(JoinListStore.java:233)
When it does save, if I restart the server and try to query for a list of the comments, I get null values returned.
I'm using mysql backend - if I switch to db4o it works fine.
Please let me know if any info would be useful.
If you have any idea where I might be going wrong or can provide some sample code for persisting collection of different objects implementing the same interface that would be appreciated.
Thanks for any help.
Tom
When I used interfaces I just enabled dynamicSchemaUpdates (some persistence property with a name like that) and FK's are added when needed. The log gives all SQL I think
I fixed this by specifying
<extension implemention-classes="SimpleComment SpecialComment"/>
for the field cl in my pacakge.jdo.

Resources