简体   繁体   English

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

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

I'm developing an OData service which exposes a model created with Entity Framework 6. These entities are read only and are quite large to load. 我正在开发一个OData服务,该服务公开了使用Entity Framework 6创建的模型。这些实体是只读的,并且加载非常大。 (Several gigabytes) (几千兆字节)

To accomplish this I'm using Microsoft.OData.EntityFrameworkProvider, (I'm not currently using WebAPI) This is mostly working fine, however I have a new requirement that needs to expose an entity which is actually a union of multiple other entities for convenience to our EndUser / customer. 为了实现这一点,我正在使用Microsoft.OData.EntityFrameworkProvider,(我目前没有使用WebAPI)这大部分工作正常,但是我有一个新的需求,需要公开一个实际上是多个其他实体的联合的实体方便我们的EndUser /客户。

EF Context Snippet 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 })
                );
        }
    }
    ...

I'm unable to expose this IQueryable property through odata as it appears that the EntityFrameworkProvider only exposes DbSets and not any IQueryable object, which makes sense. 我无法通过odata公开这个IQueryable属性,因为看起来EntityFrameworkProvider只暴露DbSets而不是任何IQueryable对象,这是有道理的。

My question is, what is the best approach to accomplish this with OData? 我的问题是,使用OData实现这一目标的最佳方法是什么?

I'd like to avoid loading duplicate data into a third intermediate table as the data can be large, and the time to load that data which is done nightly. 我想避免将重复数据加载到第三个中间表中,因为数据可能很大,加载数据的时间是每晚完成的。 It appears that QueryInterceptor only lets you subfilter data which is already queried so that doesn't seem to work. 似乎QueryInterceptor只允许您对已经查询的数据进行子过滤,这样看似不起作用。

I tried doing crazy things like extend DbSet and make my own DbViewSet which takes both sets in it's constructor, but couldn't find a way to close the loop. 我尝试做一些疯狂的事情,比如扩展DbSet和制作我自己的DbViewSet,它在它的构造函数中接受两个集合,但是找不到关闭循环的方法。

What is the best way to accomplish something analogous to a view with OData and EF6? 使用OData和EF6完成类似于视图的最佳方法是什么?

Thanks! 谢谢!

I create an example with Web API & OData. 我用Web API和OData创建了一个示例。 It looks very simple and can meet your requirement: 它看起来很简单,可以满足您的要求:

First, I define the following CLR classes to mapping your types and needn't create any view: 首先,我定义以下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; }
}

Next, I create an OData EdmModel based on the above CLR types: 接下来,我基于以上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();
}

Next, I create OData controllers to handle the OData URI query: 接下来,我创建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);
     }
 }

Note: In FooBarRec, I create two properties (FooRec and BarRec) and use them to build a relationship between FooBarRec, Foo and Bar. 注意:在FooBarRec中,我创建了两个属性(FooRec和BarRec)并使用它们来构建FooBarRec,Foo和Bar之间的关系。

Now, we can provide any data what the EndUser want. 现在,我们可以提供EndUser想要​​的任何数据。

For example, The EndUser can use the following two URIs to query the single data: 例如,EndUser可以使用以下两个URI来查询单个数据:

  1. ~/odata/Foos 〜/的OData / FOOS
  2. ~/odata/Bars 〜/的OData /酒吧

    Or, He can use the following URI to query the Union data: 或者,他可以使用以下URI来查询Union数据:

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

That's all. 就这样。

As Jodrell stated in the comments. 正如Jodrell在评论中所说。

The only approach to make this work is to make a DbSet to represent a SQL View. 使这项工作的唯一方法是使DbSet表示SQL视图。

The only way I could get Entity Framework to handle the model binding appropriately was to drop the table after it was created and create then create the view. 我可以让Entity Framework正确处理模型绑定的唯一方法是在创建表后删除表,然后创建然后创建视图。

Because it was a unioned view I had to handle this after the model was done initializing because otherwise it will try to force a clustered index on a view which is not possible if the view contains a union. 因为它是一个联合视图,所以我必须在模型完成初始化之后处理它,否则它会尝试在视图上强制聚簇索引,如果视图包含联合,则不可能。

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

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