我刚刚了解到,使用Contained属性,我可以定义一个包含的集合。这意味着不能再从我的根oData系统访问该集合。好吧,好吧,但这是我的模型:
我有一个用户的地址,该用户有发票,每张发票可以有一个或两个地址从用户。
我应该在哪个集合上添加包含的属性?
发布于 2019-04-15 04:31:55
这个问题的答案完全取决于您的域模型。我给出的建议是谨慎使用OData容器。只有当您标记为包含实体的实体不能存在于父实体的上下文之外时,使用它才真正有意义。由于这个限制,我认为OData包含的用例很少,而且介于两者之间。与单独的控制器相比,它的优势在于,从架构的角度来看,它更有意义。然而,您的控制器变得更加臃肿,维护方法上的ODataRouteAttributes变得更加繁重。使用基于约定的路由时不需要的东西。
the guide to set up OData containment上的示例在一定程度上解释了这一点。它在你为什么要使用它方面有点欠缺。请注意,PaymentInstrument实体没有指向Account的外键。这意味着没有存储PaymentInstrument信息的单独的表。相反,它直接存储在Account记录中。但是仍然被定义为Collection<T>,所以它可能被存储为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。换句话说,如果没有上下文,即为其生成的HttpRequest,HttpResponse类将毫无用处。
在HttpRequest上下文之外没有任何意义的HttpResponse类使其成为OData容器的完美候选者。这两个类甚至可以保存在数据库中的同一记录中。而且因为在不指定HttpResponse所属的HttpRequest的id的情况下无法执行GET/POST/PUT/DELETE,所以HttpResponse类拥有自己的控制器是没有意义的。
现在,回到您的用例。我可以看到两个可能的领域模型。
User、UserAddress、Invoice和InvoiceAddress.在第一个选项中,每个单独的实体都有它们自己的指定地址实体。在这里,使用这样的设计是有意义的,因为地址实体不存在于它们各自的父实体之外。UserAddress始终链接到User,InvoiceAddress始终链接到Invoice。获取单个UserAddress实体意义不大,因为使用此域模型时不应该关心单个地址在哪里。相反,重点更多地放在这个单一User的持久地址是什么上。如果不指定现有的User,也无法创建UserAddress。UserAddress实体完全依赖于User实体。
User、Invoice、TypedAddress和Address.在第二个选项中,Address实体是独立的。它独立于其他实体存在。由于地址归结为这个星球上的唯一位置,因此它只保存一次。然后,其他实体通过TypedAddress实体链接到Address实体,其中它们指定它相对于链接到它的实体的地址类型。使用此域模型获取单个Address非常有意义。通过请求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);https://stackoverflow.com/questions/55163519
复制相似问题