WCF, OData, DbContext, and Joins



我想通过单个 WCF 服务将简单实体和联接作为 OData 公开。 给定艺术家及其专辑列表的域,我知道我可以有一个这样的 DbContext:

   public class PickContext: DbContext {
      public DbSet<Album> Albums { get; set; }
      public DbSet<Artist> Artists { get; set; }
      public DbSet<List> Lists { get; set; }

由此我可以制作这样的 OData 服务:

   public class PickDataService : DataService<PickContext> {
      public static void InitializeService(DataServiceConfiguration config) {
         config.SetEntitySetAccessRule("Lists", EntitySetRights.AllRead);
         config.SetEntitySetAccessRule("Artists", EntitySetRights.AllRead);
         config.SetEntitySetAccessRule("Albums", EntitySetRights.AllRead);

我也知道我可以引入一个类来将列表、艺术家和专辑展平化为联接,如下所示:

   public class PickContainer {
      private PickContext pickContext=new PickContext();
      public IQueryable<Foo> Foos { get; private set; }
      public PickContainer() {
         Foos=from a in pickContext.Albums
               select new Foo {
                  ID=a.ID, Title=a.Title, Rating=a.Rating, Newness=a.Newness, Chance=a.Chance,
                  LastChosen=a.LastChosen, Acquired=a.Acquired, Media=a.Media, ArtistID=a.ArtistID,
                  ArtistName=a.Artist.Name, ListID=a.Artist.ListID };
      }
   }

然后,我可以创建第二个服务来托管此联接实体:

   public class PickService : DataService<PickContainer> {
      public static void InitializeService(DataServiceConfiguration config) {
         config.SetEntitySetAccessRule("Foos", EntitySetRights.AllRead);

但我无法弄清楚的是,是否有办法将两组实体放在一个容器中,更重要的是,在一个服务中。 这可能吗? 我已经玩过 $expand=Artist,但是如果我在客户端上使用扁平模型,我的生活会更轻松。 当我尝试在 PickContext 中包含 Foos 并将其添加到 PickDataService 时,我收到异常"在实体集中找不到给定名称'Foos'"。

WCF 使用实体框架的特定数据服务提供程序。您可以在此处了解更多信息。每个服务仅使用一个提供程序。不能在一个服务中混合使用多个提供程序。

您尝试在同一服务中混合使用实体框架提供程序 (PickContext) 和反射提供程序 (PickContainer),但 WCF 数据服务不支持此功能,因为您只能为一个服务提供一个提供程序。

但是,您可以通过 Web API 将其存档。

请考虑设置以下控制器:

public class AlbumsController : ODataController
{
    [Queryable]
    public IQueryable<Album> Get()
    {
        return new PickContext().Albums;
    }
}
public class FoosController : ODataController
{
    [Queryable]
    public IQueryable<Foo> Get()
    {
        var Foos = from a in new PickContext().Albums
                   select new Foo
                   {
                       ID = a.ID,
                   };
        return Foos;
    }
}

并在路由配置部分添加以下内容:

  ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
  builder.EntitySet<Album>("Albums");
  builder.EntitySet<Foo>("Foos");
  IEdmModel model = builder.GetEdmModel();
  config.Routes.MapODataRoute(
      routeName:"odata",
      routePrefix:"odata",
      model: model
  );

然后,您可以在同一服务根目录下访问两者:

http://host/odata/Albums
http://host/odata/Foos

最新更新