繁体   English   中英

OData在实体框架中的联合数据的“视图”上

[英]OData over a “View” of unioned data in Entity Framework

我正在开发一个OData服务,该服务公开了使用Entity Framework 6创建的模型。这些实体是只读的,并且加载非常大。 (几千兆字节)

为了实现这一点,我正在使用Microsoft.OData.EntityFrameworkProvider,(我目前没有使用WebAPI)这大部分工作正常,但是我有一个新的需求,需要公开一个实际上是多个其他实体的联合的实体方便我们的EndUser /客户。

EF Context Snippet

    ...
    public DbSet<Foo> FooRecs { get; set; }
    public DbSet<Bar> BarRecs { get; set; }
    public IQueryable<FooBarRec> FooBarRecs
    {
        get
        {
            return FooRecs.Select(f => new FooBarRec() { Id = f.Id, Description =  f.Description })
                .Union(
                BarRecs.Select(b => new FooBarRec() { Id = b.Id, Description = b.Description })
                );
        }
    }
    ...

我无法通过odata公开这个IQueryable属性,因为看起来EntityFrameworkProvider只暴露DbSets而不是任何IQueryable对象,这是有道理的。

我的问题是,使用OData实现这一目标的最佳方法是什么?

我想避免将重复数据加载到第三个中间表中,因为数据可能很大,加载数据的时间是每晚完成的。 似乎QueryInterceptor只允许您对已经查询的数据进行子过滤,这样看似不起作用。

我尝试做一些疯狂的事情,比如扩展DbSet和制作我自己的DbViewSet,它在它的构造函数中接受两个集合,但是找不到关闭循环的方法。

使用OData和EF6完成类似于视图的最佳方法是什么?

谢谢!

我用Web API和OData创建了一个示例。 它看起来很简单,可以满足您的要求:

首先,我定义以下CLR类来映射您的类型,而不需要创建任何视图:

public class FooBarRec
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Foo FooRec { get; set; }
    public Bar BarRec { get; set; }
}

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }
}

public class Bar
{
    public int BarId { get; set; }
    public string BarName { get; set; }
}

接下来,我基于以上CLR类型创建OData EdmModel:

private static IEdmModel GetEdmModel()
{
    ODataModelBuilder builder = new ODataConventionModelBuilder();
    builder.EntitySet<FooBarRec>("FooBarRecs");
    builder.EntitySet<Foo>("Foos");
    builder.EntitySet<Bar>("Bars");
    return builder.GetEdmModel();
}

接下来,我创建OData控制器来处理OData URI查询:

 // Controller
 public class FoosController : ODataController
 {
     public const int Num = 10;
     public static IList<Foo> foos = Enumerable.Range(0, Num).Select(i =>
            new Foo
            {
                FooId = 100 + i,
                FooName = "Foo #" + (100 + i)
            }).ToList();

     [EnableQuery]
     public IHttpActionResult Get()
     {
         return Ok(foos);
     }
 }

 public class BarsController : ODataController
 {
     public const int Num = 10;
     public static IList<Bar> bars = Enumerable.Range(0, Num).Select(i =>
            new Bar
            {
                BarId = 1000 + i,
                BarName = "Bar #" + (1000 + i)
            }).ToList();

    [EnableQuery]
    public IHttpActionResult Get()
    {
        return Ok(bars);
    }
 }

 public class FooBarRecsController : ODataController
 {
     public const int Num = 10;
     public static IList<FooBarRec> fooBarRecs = Enumerable.Range(0, Num).Select(i =>
             new FooBarRec
             {
                   Id = i,
                   Name = "ForBarRec #" + i
              }).ToList();

     static FooBarRecsController()
     {
        for(int i = 0; i < Num; i++)
        {
            fooBarRecs[i].FooRec = FoosController.foos[i];
            fooBarRecs[i].BarRec = BarsController.bars[i];
        }
     }

     [EnableQuery]
     public IHttpActionResult Get()
     {
         return Ok(fooBarRecs);
     }
 }

注意:在FooBarRec中,我创建了两个属性(FooRec和BarRec)并使用它们来构建FooBarRec,Foo和Bar之间的关系。

现在,我们可以提供EndUser想要​​的任何数据。

例如,EndUser可以使用以下两个URI来查询单个数据:

  1. 〜/的OData / FOOS
  2. 〜/的OData /酒吧

    或者,他可以使用以下URI来查询Union数据:

    • 〜/的OData / FooBarRecs?$扩大= FooRec,BarRec

就这样。

正如Jodrell在评论中所说。

使这项工作的唯一方法是使DbSet表示SQL视图。

我可以让Entity Framework正确处理模型绑定的唯一方法是在创建表后删除表,然后创建然后创建视图。

因为它是一个联合视图,所以我必须在模型完成初始化之后处理它,否则它会尝试在视图上强制聚簇索引,如果视图包含联合,则不可能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM