从一个odata Web API端点内的两个不同数据库形成的返回实体

时间:2018-10-23 19:11:43

标签: odata asp.net-core-webapi asp.net-core-2.1

我需要2个数据库来支持一个Web API。我想返回一个反映两个数据库中实体的新“实体”。我将这个实体称为“视图”,即使它与数据库中的视图没有关系并且数据来自2个不同的数据库。数据将用于驱动UI页面。

对于另一个需要从单个数据库返回新形状数据的类似问题,我设置了一个新的NotMapped实体调用PeopleHomeView,并向控制器添加了一个Find函数,以便当我访问/PeopleHomeViews/NS.Find(id='...')我返回具有自定义形状的实体。该实体只有原始数据值,没有引用类型。一切都很好。

但是,我需要返回一个结合了两个数据库中数据的实体,这是一个不同的问题。

  • 设置2个DbContext,每个数据库一个。两者都注入到控制器中。
  • 使用返回的数据中所需的属性定义一个.net类。这些属性具有反映两个不同数据库实体模型的对象。因此,在PersonEntityView中,我有一个Person对象和一个Rating对象。人员和评分来自不同的数据库。
  • 创建了一个控件PersonEntityViewsController,并将builder.EntitySet<PersonEntityView>("PersonEntityViews")添加到了EDM模型构建器。我没有其他任何EDM构建器代码。
  • Get([FromODataUri] Guid key)控制器添加了PersonEntityViewsController方法。传递到Get中的键是Person键。然后,我使用linq手动构建需要返回的数据。

    public PersonEntityView Get(
           [FromODataUri] Guid key)
    {
        ...controller code to build up PersonEntityView...
        var x = new PersonEntityView();
        ...
        return x;
    }
    

现在,当我访问/PeopleEntityViews(..guid of person...),构建返回实体并从Get返回时,即使我手动构建了实体内容,例如,我仅获得.net类中的原始数据值。添加人员和等级。它们不会序列化回客户端。 $ metadata正确显示导航属性。使用扩展,例如$expand=Person,不起作用。

我还看到了其他一些SO帖子,但它们与问题无关。例如,文档中描述了返回DTO,但没有从两个不同的数据库中返回。

我不想让我的客户多次要求加载大量参考数据和页面所需的其他数据。我想在一个查询中获取大部分信息,但仍使用odata后端。

有关如何执行此操作的想法?看来odata可能对控制器的返回类型很敏感,所以也许我需要特殊的返回类型,或者我缺少注释。

1 个答案:

答案 0 :(得分:0)

看来,odata格式化程序需要相当严格的返回类型集才能正确激活。不太清楚规则,因此我必须更仔细地阅读odata源代码。为了使其正常工作,我必须从Get返回一个IQueryable,所以我做到了:

public IQueryable<PersonEntityView> Get([FromOdataUri] Guid key) {
  ...
  (new List<PersonEntityView>{v}.AsQueryable();
}

对于我来说,签名并不有意义,因为基于键的get的Get应该只返回单个实体,因此不需要IQueryable。返回的值是“值”属性下数组的成员。如果仅使用不带类型的IQueryable,它将返回一个json对象,但缺少完整的odata响应格式。我仍然需要通过?$expand=ThePropertyToExpand扩展属性,否则扩展不会发生。

我将继续使用它,但这似乎是返回非数据库支持的实体(因此未映射到entityframework中)的最佳方法,这些实体已针对特定UI视图的需求进行了高度定制,并且不仅基于单个对象根。

您还可以使用绑定实体(我在此描述here)来避免使用函数/动作。但是,在某些情况下,该值可能不会与单个根实体整齐地相关。