【问题标题】:Inserting Entities in OData with required Foreign Keys使用所需外键在 OData 中插入实体
【发布时间】:2015-04-06 13:17:24
【问题描述】:

EDIT-2:经过数小时的研究,几乎每个 google 上与 odata 相关的链接都变成紫色,我发现 OData 中存在“深插入”(link)的概念规格。所以毕竟,我正在做的事情应该可以工作,即使没有链接。有谁知道如何在 Microsoft OData 客户端上启用此功能?是否还有其他支持该概念的 OData 客户端?

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

我对 OData v3 有疑问。我有一个类Associate 有一个必需的Address。当我尝试发布新的 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; }
}

我使用的是微软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 属性,地址也不会传输。

我该如何解决这个问题?

【问题讨论】:

  • 您是否设置了实体框架模型以将 AddressId 属性正确绑定到 Address 实体?我经常忘记这样做,所以我的属性没有正确链接到外键。
  • @TheSenator 地址也是新的,这就是为什么我需要服务器端的物化对象,所以 EF 可以管理其余部分(因为它做得很好)。
  • 如何从客户端发送 JSON POST 请求?更确切地说,您如何在客户端序列化 Associate / Address?
  • @nXu 我只是调用了 context.SaveChanges(),所以 context 以黑盒方式进行序列化。

标签: c# .net asp.net-web-api odata


【解决方案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);
        }
  }

因此,从那时起发布学生,您将忽略教师字段并仅使用教师 ID 发布。

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

【讨论】:

    【解决方案2】:

    基本上在创建对象时

    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();
    

    【讨论】:

    • 所以你是说我必须先发布所有新实体?这将非常复杂。我需要弄清楚哪些新实体依赖于其他新实体,然后按顺序将它们发布到服务器,然后取回 ID,分配它们,再次更新所有对象,然后在 OData 上下文中调用保存更改。真的是这样吗?好像我自己在编写一个 OData 上下文,就像这样:/
    • @LueTm 不,但很可能您遇到了问题,这将有助于在消除可能性的同时找出问题所在。
    • 这是一个如何完成的示例asp.net/web-api/overview/odata-support-in-aspnet-web-api/…(有点异步)
    • 我可以添加带有 Patient(1)/$links/Associate url 的链接。但是如何让 .NET OData 客户端做到这一点? (我的印象是 context.SaveChanges() 应该为我做到这一点......)
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      addlink 和 setlink 工作的唯一方法是,如果外键可以为空,并且您应该创建一个 postput 函数调用创建链接,请参阅 here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-01
        相关资源
        最近更新 更多