使用所需的外键在 OData 中插入实体

Inserting Entities in OData with required Foreign Keys

EDIT-2: 经过数小时的研究和几乎所有与 link 有关 google 变紫的 odata,我发现 google 的概念 'deep-inserts' (link) 存在于 OData 规范中。所以毕竟,即使没有 links,我所做的也应该有效。有谁知道如何在 Microsoft OData 客户端上启用它?是否有其他支持该概念的 OData 客户端?

编辑: 也许这是错误的方法,如果我做的完全错了,请告诉我。无法保存真的阻碍了我们的进步!

我对 OData v3 有疑问。我有一个 class Associate,它有一个必需的 Address。当我尝试 POST 一个新的 Associate 时,由于 Address 属性 为空(EF6 抛出外键违规的 DbUpdateException)而失败。我的 Associate class 看起来像这样:

public class Associate
{
    public int Id { get; set; }

    [Required, StringLength(100)]
    public string Name { get; set; }

    [Required, StringLength(50)]
    public string Role { get; set; }

    public bool IsMailReceiver { get; set; }
    public bool IsLegalRepresentative { get; set; }

    [ForeignKey("AddressId")]
    public virtual Address Address { get; set; }
    public int AddressId { get; set; }
}

我使用微软OData客户端,尝试通过以下方式添加关联:

var associate = new Associate { /* ... */ };
context.AddObject("Associates", associate);
context.AddObject("Addresses", associate.Address);

/* UI fills associate data */

context.SetLink(associate, "Address", associate.Address);
context.UpdateObject(associate);
context.UpdateObject(associate.Address);

/* at this point the associate has the address set! */

context.SaveChanges(); // << Exception

然而,在服务器上,在控制器中,Associate 到达时没有外键。当我使用 Fiddler 检查 POST 请求时,我明白了原因:

{
    "odata.type" : "xxx.Data.Entities.Associate",
    "AddressId" : 0,
    "Id" : 0,
    "IsLegalRepresentative" : false,
    "IsMailReceiver" : false,
    "Name" : "John Doe",
    "Role" : "Father"
}

即使在客户端生成的 class 有一个 Address 属性.

,地址也不会传输

我该如何解决这个问题?

基本上当你创建对象时

var associate = new Associate { /* ... */ };

没有插入数据库。它是在内存中创建的。当你打电话

context.SaveChanges();

它将保存在数据库中。此时发生数据库验证并生成密钥。假设您的 Id 是在数据库中生成的唯一标识符,请注意,为了使其从数据库中获取更新的值,您需要将 StoreGeneratedPattern 设置为 实体模型视图中的 Identity

如果不这样做,您的本地上下文和数据库上下文将不再匹配。如果你在哪里使用那个对象来引用其他东西,它会失败。

我假设这样的事情会起作用:

Address address = new Address{ City = "Tallinn" /*etc*/};
context.SaveChanges();
//At this point Address will be in database context and has Id 
associate = new Associate {  
  name = "Margus",
  role = "Admin",
  receiver = true,
  representative = true,
  AddressId = address.id 
};
context.SaveChanges();

没有解决办法。我将使用适用于 web-api 的更改集概念来滚动我自己的上下文。完成后我会把它放在 github 上。

我也找不到任何关于此的信息 - 这确实是 OData 中的一个问题。这是我设法让它工作的方法。

显式定义外键

class Student {
        public int TeacherId { get; set; }

        [Required, ForeignKey("TeacherId")]
        public virtual Teacher Teacher { get; set; }
}

执行插入时,获取相关记录并修复模型状态:

  public IHttpActionResult Post(Student student)
  {
        student.Teacher = this.db.Teacher.FirstOrDefault(i => i.TeacherId == student.TeacherId);
        if (student.Teacher != null)
        {
            this.ModelState.Remove("student.Teacher");
        }

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

所以从那时起 post 一个学生,你忽略教师字段,只 post 和 TeacherId。

我还没有用 OData 客户端测试过这个,但我想不出为什么这不起作用。您只需要使用 Id 字段而不是对象。

addlink 和 setlink 工作的唯一方法是如果外键可以为 null 并且您可能会创建一个 postput 函数调用 create link 请参阅 here