Odata 小田围堵

Odata 小田围堵,odata,asp.net-core-webapi,Odata,Asp.net Core Webapi,我刚刚了解到,通过[Contained]属性,我可以定义一个包含的集合。这意味着无法从我的根oData系统访问该集合。好的,但这是我的模型: 我有一个有地址的用户 用户有发票 每个发票可以有一个或两个来自用户的地址 我应该在哪个集合上添加包含的属性 这个问题的答案完全取决于您的域模型。我的建议是要谨慎使用OData容器。只有当您标记为包含实体的实体不能存在于父实体的上下文之外时,才有意义使用它。由于这个限制,我认为OData包含的用例很少,而且介于两者之间。与单独的控制器相比,它的优势在于,从体

我刚刚了解到,通过[Contained]属性,我可以定义一个包含的集合。这意味着无法从我的根oData系统访问该集合。好的,但这是我的模型:

我有一个有地址的用户 用户有发票 每个发票可以有一个或两个来自用户的地址


我应该在哪个集合上添加包含的属性

这个问题的答案完全取决于您的域模型。我的建议是要谨慎使用OData容器。只有当您标记为包含实体的实体不能存在于父实体的上下文之外时,才有意义使用它。由于这个限制,我认为OData包含的用例很少,而且介于两者之间。与单独的控制器相比,它的优势在于,从体系结构的角度来看,它更有意义。但是,您的控制器变得更加臃肿,维护方法上的
ODataRouteAttributes
需要更多的工作。使用基于约定的路由时不需要的东西

上面的例子多少说明了这一点。它有点不明白你为什么要用它。请注意,
PaymentInstrument
实体没有账户的外键。这意味着没有存储
PaymentInstrument
信息的单独表格。相反,它直接存储在
帐户
记录中。但是它仍然被定义为一个
集合
,因此它可能存储为JSON或跨多个列。可能不一定是这样,但从代码的角度来看,数据库可能是这样的

为了进一步解释OData包含,假设我们有下面的域模型

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

    public DateTime CreatedOn { get; set; }

    public string CreatedBy { get; set; }

    public virtual HttpResponse HttpResponse { get; set; }
}

public class HttpResponse
{
    public string Content { get; set; }

    public DateTime CreatedOn { get; set; }
}
如您所见,
HttpResponse
类没有指向
HttpRequest
的导航属性。因此,调用
GET-odata/HttpResponses
没有任何意义,因为我们将获得所有
HttpResponses
,而不是它们链接到的
HttpRequest
。换句话说,
HttpResponse
类在没有上下文(即生成它的
HttpRequest
的上下文)的情况下是无用的

HttpResponse
类在
HttpRequest
上下文之外没有任何意义,因此它是OData包含的完美候选。这两个类甚至可以保存在数据库中的同一条记录上。而且,由于不指定
HttpResponse
所属的
HttpRequest
的id就无法执行GET/POST/PUT/DELETE,因此
HttpResponse
类拥有自己的控制器是没有意义的

现在,回到您的用例。我可以看到两种可能的域模型

  • 实体
    用户
    用户地址
    发票
    发票地址
  • 在第一个选项中,每个实体都有自己的指定地址实体。OData包含在这里使用这样的设计是有意义的,因为地址实体不存在于它们各自的父实体之外。
    用户地址
    始终链接到
    用户
    发票地址
    始终链接到
    发票
    。获取单个
    UserAddress
    实体的意义不大,因为使用此域模型不应该关心单个地址在哪里。相反,重点更多地放在这个
    用户的持久地址是什么。如果不指定现有的
    用户
    ,也无法创建
    用户地址
    UserAddress
    实体完全依赖于
    User
    实体

  • 实体
    用户
    发票
    类型地址
    地址
  • 在第二个选项中,
    地址
    实体是独立的。它与其他实体分开存在。由于一个地址可以归结为这个星球上唯一的位置,所以它只保存一次。然后,其他实体通过
    类型地址
    实体链接到
    地址
    实体,在该实体中,它们指定与链接到它的实体相关的地址类型。使用此域模型获取单个
    地址
    非常有意义。通过请求
    GET-odata/Addresses
    ,可以轻松检索整个公司的通讯簿。这就是OData遏制的意义所在

    请注意,可以使用ODataConventionModelBuilder配置安全壳。因为您不需要将
    ContainedAttribute
    添加到类中,所以这样做的好处是不会因为对OData库的引用而污染数据层。我建议采用这种方法。在您的情况下,我希望具有以下配置

    var modelBuilder = new ODataConventionModelBuilder();
    modelBuilder
        .EntityType<User>()
        .ContainsMany(user => user.UserAddresses);
    modelBuilder
        .EntityType<Invoice>()
        .ContainsMany(invoice => invoice.InvoiceAddresses);
    
    var modelBuilder=new ODataConventionModelBuilder();
    建模者
    .EntityType()
    .ContainsMany(user=>user.UserAddresses);
    建模者
    .EntityType()
    .ContainsMany(发票=>发票.invoice地址);