EDIT-2:经过几个小时的研究,几乎所有与谷歌相关的链接都变成了紫色,我发现了“深插入”的概念' (link)存在于OData规范中。毕竟,即使没有链接,我所做的也应该有效。有谁知道如何在Microsoft OData客户端上启用它?还有其他OData客户支持这个概念吗?
编辑:也许这是错误的做法,所以请告诉我,我是否做错了。无法保存真的阻碍了我们的进步!
我对OData v3有疑问。我有一个Associate
课程,其中包含必需的Address
。当我尝试POST一个新的Associate时,由于Address
属性为null(EF6因外键违反而抛出DbUpdateException)而失败。我的Associate
课程如下:
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; }
}
我使用Microsoft 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"
}
即使客户端上生成的类具有Address
属性,也不会传输地址。
我该如何解决这个问题?
答案 0 :(得分:1)
我也找不到任何关于此的信息 - 这确实是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);
}
}
因此,从那时起发布学生,您将忽略教师字段,只需使用TeacherId发布。
我没有用OData客户端对此进行测试,但我想不出为什么这不起作用。您只需使用Id字段而不是对象。
答案 1 :(得分:0)
基本上在创建对象时
var associate = new Associate { /* ... */ };
它未插入数据库。它是在内存中创建的。当你打电话
context.SaveChanges();
它将保存在数据库中。此时,数据库验证发生并生成密钥。假设您的ID是在数据库中生成的唯一标识符,请注意,为了使其从数据库中获取更新值,您需要将 StoreGeneratedPattern 设置为身份从实体模型视图。
如果不这样做,您的本地上下文和数据库上下文将不再匹配。如果您在哪里使用该对象而引用其他内容则会失败。
我认为这样的事情会奏效:
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();
答案 2 :(得分:0)
没有解决方法。我将使用与web-api一起使用的变更集概念来推广我自己的上下文。当我完成时,我会把它放在github上。
答案 3 :(得分:0)
addlink和setlink工作的唯一方法是,如果外键可以为空,并且你要创建一个postput函数调用create link,请参阅here