簡體   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