OData над «представлением» объединенных данных в Entity Framework

c# entity-framework entity-framework-6 odata

Вопрос

Я разрабатываю службу OData, которая предоставляет модель, созданную с Entity Framework 6. Эти объекты доступны только для чтения и достаточно велики для загрузки. (Несколько гигабайт)

Для этого я использую Microsoft.OData.EntityFrameworkProvider (в настоящее время я не использую WebAPI). Это в основном работает нормально, однако у меня есть новое требование, которое должно выставлять объект, который на самом деле является объединением нескольких других объектов для удобство для нашего конечного пользователя / клиента.

Фрагмент контекста EF

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

Я не могу выставить это свойство IQueryable через odata, поскольку кажется, что 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; }
}

Затем я создаю OData EdmModel на основе вышеуказанных типов CLR:

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

Затем я создаю контроллеры OData для обработки запроса URI OData:

 // 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 для запроса данных Союза:

    • ~ / OData / FooBarRecs? $ = Расширение FooRec, BarRec

Это все.



Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему