Odata 小田围堵
我刚刚了解到,通过[Contained]属性,我可以定义一个包含的集合。这意味着无法从我的根oData系统访问该集合。好的,但这是我的模型: 我有一个有地址的用户 用户有发票 每个发票可以有一个或两个来自用户的地址Odata 小田围堵,odata,asp.net-core-webapi,Odata,Asp.net Core Webapi,我刚刚了解到,通过[Contained]属性,我可以定义一个包含的集合。这意味着无法从我的根oData系统访问该集合。好的,但这是我的模型: 我有一个有地址的用户 用户有发票 每个发票可以有一个或两个来自用户的地址 我应该在哪个集合上添加包含的属性 这个问题的答案完全取决于您的域模型。我的建议是要谨慎使用OData容器。只有当您标记为包含实体的实体不能存在于父实体的上下文之外时,才有意义使用它。由于这个限制,我认为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
类拥有自己的控制器是没有意义的
现在,回到您的用例。我可以看到两种可能的域模型
用户
,用户地址
,发票
和发票地址
用户地址
始终链接到用户
,发票地址
始终链接到发票
。获取单个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地址);