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

C# 使用所需外键在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,它有一个必需的地址。当我尝试发布一个新的关联时,

EDIT-2:经过数小时的研究,谷歌上几乎所有与odata相关的链接都变成紫色,我发现odata规范中存在“深度插入”(deep insert)的概念。所以毕竟,我所做的应该是有效的,即使没有链接。有人知道如何在Microsoft OData客户端上启用此功能吗?有没有其他OData客户支持这个概念

编辑:也许这是错误的方法,所以请告诉我我是否完全错了。不能储蓄真的阻碍了我们的进步

我对OData v3有问题。我有一个class
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);
        }
  }