I have a client-side graph of entities that I’m trying to save. When I try to add add the entity (described below), Breeze reports the error of the title.
I am able to exclude/include the entity on demand and so have been able to let Breeze persist everything else in the graph and then lastly try to add this entity. The error is reported consistently.
I captured the JSON representation of the entity in the controller’s saveBundle and am able to manually insert it into the database which gives me some assurance that it’s being created correctly.
I’m stuck as to how to debug it further and would appreciate some guidance.
Here’s the code-first class (requireds: DateTime, value, Message, User):
public Guid ID { get; set; }
public Guid MessageID { get; set; }
public Guid UserID { get; set; }
public DateTime DateTime { get; private set; }
public float Value { get; set; }
public virtual Message Message { get; set; }
public virtual User User { get; set; }
public virtual ICollection<PropertyValue> PropertyValues { get; set; }
Here’s the saveBundle:
{
"entities": [
{
"ID": "cdc7a329-1ddc-4535-98f1-fd878af48823",
"MessageID": "57e88bc1-edc2-4905-af74-09df83edeba5",
"UserID": "1269a0ad-1019-471c-bdf9-a6e61aea468c",
"DateTime": "2013-01-04T23:32:01.067Z",
"Value": 0,
"entityAspect": {
"entityTypeName": "Score:#MyProjectName.Repo",
"entityState": "Added",
"originalValuesMap": {},
"autoGeneratedKey": {
"propertyName": "ID",
"autoGeneratedKeyType": "Identity"
}
}
}
],
"saveOptions": {
"allowConcurrentSaves": false
}
}
Here’s the SQL:
insert into Scores (
[MessageID],
[UserID],
[DateTime],
[Value]
) values (
'57e88bc1-edc2-4905-af74-09df83edeba5',
'1269a0ad-1019-471c-bdf9-a6e61aea468c',
'2013-01-04T23:28:18.872Z',
0
)
UPDATE
The server’s version of events begins with a “System.ArgumentNullException”
Value cannot be null.\r\nParameter name: source
and:
at System.Linq.Enumerable.Select[TSource,TResult](IEnumerable`1 source, Func`2 selector)
at Breeze.WebApi.EFContextProvider`1.SaveChangesCore(Dictionary`2 saveMap)
at Breeze.WebApi.ContextProvider.SaveChanges(JObject saveBundle)
at [MyProject].[MyController].SaveChanges(JObject saveBundle) in ..\Controllers\[MyController].cs:line 53
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass13.<GetExecutor>b__c(Object instance, Object[] methodParameters)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.<>c__DisplayClass5.<ExecuteAsync>b__4()
at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)
I’d say that the stack trace in your updated question confirms that the exception occurs on the server.
Looking at source for
EFContextProvider, the exception you’re reporting appears to be thrown inEFContextProvider.SaveChangesCore, within theforeachthat processes EF validation errors (~line 125). It is preparing a message about the entity validation error from EF’ssaveChangesand failing (unexpectedly) because there are noEntityKeyValuesfor the key of the errant entity. That shouldn’t be possible (ha)! It would seem that EF was asked to save an entity with no key.You could help us diagnose as follows:
EFContextProvider2class in your Models projectEFContextProviderfrom GitHub source.EFContextProvider2and make the project compileEFContextProvider2in your Web API controllerInspect the
key.EntityKeyValues. I bet they are null for an offending entity. What entity is that? What is in the error’seve.ValidationErrors? How is this particular entity defined in your model?We (well, YOU) will know a lot more when you’ve got more information about the error.
Let us know what you discover.
Updated Jan 9
Now that I’ve seen a little of the code, the problem is more obvious to me.
Your server-side model says that the Score.Message and Score.User properties are required. Well they aren’t present in the EF context on the server so you are failing validation.
Score.Message and Score.User are navigation properties that return related Message and User objects respectively.
When you save, EF is dutifully validating that those related entities are present. Well they aren’t. They aren’t because you (correctly) turned lazy-loading off which means EF can’t retrieve them.
It matters not at all whether those entities are in cache on your Breeze client. Breeze will not send them up to the server as part of the save bundle.
Nor should it do so! You are saving a new Score. But you didn’t change the Score’s related Message or User. Therefore, the only entity that needs saving is the Score. Which is why it is the one and only entity in your save bundle.
EF is doing exactly what you told it to do: scream if there is no related Message or User.
My question to you is: why are you requiring the Message or User? The Score has their foreign keys. Are you trying to ensure that those keys are valid? That they reference actual Message and User rows in the database? Seems like overkill to me. The database will ensure that for you if you have referential constraints turned on. If those constraints are off, then these validations will protect you during the Score insert/update; but they won’t stop someone from deleting the Message or User independently … thus orphaning the Score.
If you insist, you can satisfy EF by LOADING those properties explicitly in a BeforeSave… method. I’ll assume you have the EF chops to do that … else you can find that out on line.
But, as I said, this seems like overkill to me.
BTW, commenting out the [Required] attributes on the Score’s Message and User properties freed EF to save the new Score. The app blew up back on the client for other reasons (
console.debugwas undefined in my environment) but I’ll leave that to you.Your Model
How did you get this model. Score looks like it was generated from something. I’m not familiar with MVC scaffolding so forgive my ignorance. But I know ugly when I see it and that business of two partial classes, one of which holds the metadata "buddy" class … now that’s ugly. And many (if not most) of the attributes are superfluous.
I can’t think of a good reason for all that cruft. What is wrong with a single, simple POCO-ish class, adorned with validation attributes on the right properties. Do this and your model will be much easier to understand.
What’s with the jQuery deferred?
I realize its off topic but I see you’re going to a lot of effort to turn Q promises into jQuery deferreds? That’s your choice. But there’s nothing you can do with deferreds that you can’t do as well or better with Q. You can cut out a lot of ugly code if you stick with Q. Just saying.