如何在Web Api OData中使用数据库生成的身份密钥

时间:2013-06-06 09:39:09

标签: asp.net-web-api odata

我按照这里的教程设法创建了许多只读的Web Api OData服务:http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api。因此,我使用ODataConventionModel构建器从一组实体创建模型(顺便来自Telerik ORM)。这一切似乎都运行良好,我可以愉快地发布查询,查看服务上的元数据等。

我现在试着把注意力转向其他CRUD操作 - 首先是创建并且偶然发现了一个问题!也就是说,Post方法正确触发(CreateEntity)但实体参数为null - 通过对ModelState.IsValid进行检查,它显示问题是空ID(键)值。这并不奇怪,因为数据库为ID列使用Database Generated Identity,因此在将实体保存到数据库上下文时将创建ID。

因此,我尝试了将ID列标记为数据库生成的各种方法,但未设法找到任何内容。奇怪的是,我似乎找不到一个人要求这样做的帖子 - 当然我不可能是唯一的一个帖子?!

我注意到在查看EF模型构建器时(例如这里:http://forums.asp.net/t/1848984.aspx/1),似乎有一种方法可以使用.HasDatabaseGeneratedOption属性影响模型构建器,但System.Web中不存在类似的选项。 .Http.OData等价物。

所以问题是:

  1. 是否有改变模型构建器(或其他东西)的方法,以便控制器接受该对象并使用空键值反序列化该实体?
  2. 如果是这样,我该怎么做?
  3. 如果没有,有关其他选项的建议吗?
  4. 我意识到我可能只是用客户端请求中的(在这种情况下)整数值填充对象,但这似乎a)语义错误和b)由于客户端不一定总是可能的可能会使用的工具包。

    感谢所有的帮助!

    非常感谢,

    学家

2 个答案:

答案 0 :(得分:1)

您需要为insert创建一个不包含ID参数的viewmodel。使用Automapper将传入插入模型的属性映射到数据实体。

您遇到的问题是ID是数据模型中的必需属性,因为它是您的PK,但在插入期间,不应指定它。

答案 1 :(得分:0)

就我而言,我的数据库生成的密钥是Guid。

作为一种解决方法,在我的TypeScript客户端代码中,我提交(通过http POST)具有空Guid的对象,如下所示:注意:ErrorId是关键列。

    let elmahEntry: ELMAH_Error = {
        Application: 'PTUnconvCost',
        Host: this.serviceConfig.url,
        Message: message,
        User: that.userService.currentUserEmail,
        AllXml: `<info><![CDATA[\r\n\r\n${JSON.stringify(info || {})}\r\n\r\n]]></info>`,
        Sequence: 1,
        Source: source,
        StatusCode: 0,
        TimeUtc: new Date(Date.now()),
        Type: '',
        ErrorId: '00000000-0000-0000-0000-000000000000'
    };

然后,在我的WebApi OData控制器中,我检查键是否为空guid,如果是,我将其替换为新的Guid,如下所示:

    // POST: odata/ELMAH_Error
    public IHttpActionResult Post(ELMAH_Error eLMAH_Error)
    {
        if (eLMAH_Error.ErrorId == Guid.Empty)
        {
            eLMAH_Error.ErrorId = Guid.NewGuid();
        }

        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        db.ELMAH_Error.Add(eLMAH_Error);

        try
        {
            db.SaveChanges();
        }
        catch (DbUpdateException)
        {
            if (ELMAH_ErrorExists(eLMAH_Error.ErrorId))
            {
                return Conflict();
            }
            else
            {
                throw;
            }
        }

        return Created(eLMAH_Error);
    }