C# 使用所需外键在OData中插入实体
EDIT-2:经过数小时的研究,谷歌上几乎所有与odata相关的链接都变成紫色,我发现odata规范中存在“深度插入”(deep insert)的概念。所以毕竟,我所做的应该是有效的,即使没有链接。有人知道如何在Microsoft OData客户端上启用此功能吗?有没有其他OData客户支持这个概念 编辑:也许这是错误的方法,所以请告诉我我是否完全错了。不能储蓄真的阻碍了我们的进步 我对OData v3有问题。我有一个classC# 使用所需外键在OData中插入实体,c#,.net,asp.net-web-api,odata,C#,.net,Asp.net Web Api,Odata,EDIT-2:经过数小时的研究,谷歌上几乎所有与odata相关的链接都变成紫色,我发现odata规范中存在“深度插入”(deep insert)的概念。所以毕竟,我所做的应该是有效的,即使没有链接。有人知道如何在Microsoft OData客户端上启用此功能吗?有没有其他OData客户支持这个概念 编辑:也许这是错误的方法,所以请告诉我我是否完全错了。不能储蓄真的阻碍了我们的进步 我对OData v3有问题。我有一个classAssociate,它有一个必需的地址。当我尝试发布一个新的关联时,
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
即使客户端上生成的类具有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);
}
}
因此,从那时起,要发布一个学生,您可以忽略教师字段,只使用TeacherId发布
我还没有对OData客户机进行测试,但我想不出为什么这不起作用。您只需使用Id字段而不是对象。addlink和setlink工作的唯一方法是,如果外键可为空,并且您可以创建一个后输出函数调用create link请参见是否已设置实体框架模型以将AddressId属性正确绑定到地址实体?我经常忘记这样做,这样我的属性就不能正确链接到外键。@thenator地址也是新的,这就是为什么我需要服务器端的物化对象,以便EF可以管理其余的对象(因为它做得很好)。如何从客户端发送JSON POST请求?更确切地说,如何在客户端序列化关联/地址?@nXu我只调用context.SaveChanges(),因此上下文以黑盒方式进行序列化。所以你是说我必须先发布所有新实体?这将非常复杂。我需要找出哪些新实体依赖于其他新实体,然后按顺序将它们发布到服务器,然后取回ID,分配它们,再次更新所有对象,然后在OData上下文上调用save changes。真的是这样吗?似乎我自己也在编写OData上下文,如下所示:/@LueTm否,但很可能您有问题,这将有助于找出问题所在,同时消除可能性。下面是一个示例,说明如何完成此操作(稍微异步一点),我可以添加带有患者(1)/$links/Associate URL的链接。但是我如何让.NET OData客户端做到这一点呢?(我的印象是context.SaveChanges()应该为我做到这一点……)让我们一起来。
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);
}
}