“无法保存更改。”值不能为空。“

时间:2013-01-04 23:49:03

标签: breeze

我有一个我正在尝试保存的实体的客户端图表。当我尝试添加添加实体(如下所述)时,Breeze会报告标题的错误。

我能够按需排除/包含实体,因此能够让Breeze持久保存图表中的所有其他内容,然后最后尝试添加此实体。报告错误一致。

我在控制器的saveBundle中捕获了实体的JSON表示,并且能够手动将其插入到数据库中,这使我可以确保它正确创建。

我对如何进一步调试感到困惑,并希望得到一些指导。

这是代码优先的类(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; }

这是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
  }
}

这是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
)

更新

服务器的事件版本以“System.ArgumentNullException”

开头
Value cannot be null.\r\nParameter name: source

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)

2 个答案:

答案 0 :(得分:3)

我说你更新的问题中的堆栈跟踪确认服务器上发生了异常。

查看EFContextProvider的来源,您处理EF验证错误的EFContextProvider.SaveChangesCore内的foreach似乎会引发您报告的异常(〜第125行)。它正在准备一条关于来自EF saveChanges的实体验证错误的消息,并且(意外地)失败,因为错误实体的密钥没有EntityKeyValues。那不可能(哈)!似乎EF被要求保存没有密钥的实体。

您可以帮我们诊断如下:

  1. 在模型项目中创建一个新的EFContextProvider2
  2. 粘贴EFContextProvider from GitHub source 的副本。
  3. 务必重命名类EFContextProvider2并使项目编译
  4. 在Web API控制器中替换EFContextProvider2
  5. 在第124行设置断点,就在格式化键
  6. 之前
  7. 重新调试调试器下的问题
  8. 检查key.EntityKeyValues。我打赌他们对违规实体来说是空的。那个实体是什么?错误是什么eve.ValidationErrors?如何在您的模型中定义此特定实体?

    当您获得有关错误的更多信息时,我们(嗯,您)将会了解更多信息。

    让我们知道你发现了什么。

    1月9日更新

    现在我已经看到了一些代码,问题对我来说更明显。

    您的服务器端模型表示需要Score.Message和Score.User属性。好吧,它们不会出现在服务器上的EF上下文中,因此您无法通过验证。

    Score.Message和Score.User是导航属性,分别返回相关的Message和User对象。

    保存时,EF会尽职尽责地确认这些相关实体存在。好吧,他们不是。它们并不是因为你(正确地)关闭了延迟加载,这意味着EF无法检索它们。

    根本不重要的是这些实体是否在Breeze客户端的缓存中。 Breeze不会将它们作为保存包的一部分发送到服务器。

    也不应该这样做!您正在保存新的分数。但是你并没有改变乐谱相关的消息或用户。因此,唯一需要保存的实体是分数。这就是为什么它是保存包中唯一的实体。

    EF正在按照你的要求去做:如果没有相关的消息或用户就会尖叫。

    我的问题是:你为什么要求留言或用户?得分有他们的外键。您是否尝试确保这些密钥有效?他们引用数据库中的实际Message和User行?对我而言似乎有点矫枉过正。如果您启用了参照约束,数据库将确保为您服务。如果这些约束关闭,那么这些验证将在分数插入/更新期间保护您;但他们不会阻止某人独立删除消息或用户......从而使分数孤立。

    如果你坚持,你可以通过在BeforeSave ...方法中显式加载这些属性来满足EF。我假设你有EF印章来做到这一点......否则你可以在网上找到它。

    但是,正如我所说,这对我来说似乎有点过分了。

    BTW,在乐谱的消息和用户属性上注释掉[必需]属性,释放EF以保存新分数。由于其他原因(console.debug在我的环境中未定义),该应用程序在客户端上爆炸了,但我会留给您。

    你的模特

    你是如何得到这个模型的。分数看起来像是由某些东西产生的。我不熟悉MVC脚手架,所以请原谅我的无知。但是,当我看到它并且两个部分类的业务时,我知道丑陋,其中一个包含元数据&#34; buddy&#34;上课...现在这很丑陋。许多(如果不是大多数)属性都是多余的。

    我无法想到所有这一切的充分理由。单个简单的POCO-ish类有什么问题,在适当的属性上装饰了验证属性。这样做,您的模型将更容易理解。

    jQuery推迟了什么?

    我意识到它的主题但是我看到你需要付出很多努力才能将Q promises变成jQuery延迟?这是你的选择。但是对于延迟而言你无能为力,你可以用Q做得更好或更好。如果你坚持使用Q,你可以删除许多丑陋的代码。只是说。

答案 1 :(得分:0)

我可能完全不在这里,但我认为这是DateTime字段。如果您可以尝试将字段更改为可以为空的值。

  public DateTime? DateTime { get; private set; }

在EF内部的某处,它不会将“2013-01-04T23:32:01.067Z”识别为有效格式,因此它将其置零。 SQL确实识别它,因此您的insert语句有效。

我通过使用moment.js格式化日期解决了这个问题,因此它以“1/4/2012 23:32:01”或其他类似的方式进入了网络。

我相信你已经知道,但Z使它成为UTC。我有一个问题,提前8小时(我在加州)。将其格式化为文本格式也可以解决这个问题。