2016-07-09 1 views
3

Я получаю сообщение об ошибке при использовании $ filter с $ apply = groupby. Похоже, что это происходит только тогда, когда поле фильтра не находится в выражении groupby. Вот сообщение об ошибке: Instance свойство 'DRG_Definition' не определено для типа 'DynamicTypeWrapper'Ошибка OData v4 с использованием фильтра с groupby

Это прекрасно работает: http://localhost:9810/odata/PAYMENTS $ применяются = GroupBy ((Provider_Id, DRG_Definition), заполнитель (Total_Payments с суммой в Total_Payments)) & $ фильтр = (DRG_Definition экв '069 - преходящая ишемия')

Это бросает ошибку (только разница нет поля DRG_Definition в GroupBy): http://localhost:9810/odata/PAYMENTS $ применяются = GroupBy ((Provider_Id), совокупный (Total_Payments с суммой как Total_Payments)) & $ filter = (DRG_Definition eq '069 - TRANSIENT ISCHEMIA')

Обновлены моих пакетов и образцы кода ниже:

<packages> 
    <package id="EntityFramework" version="6.1.3" targetFramework="net452" /> 
    <package id="Microsoft.ApplicationInsights" version="2.1.0" targetFramework="net452" /> 
    <package id="Microsoft.ApplicationInsights.Agent.Intercept" version="1.2.1" targetFramework="net452" /> 
    <package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.1.0" targetFramework="net452" /> 
    <package id="Microsoft.ApplicationInsights.JavaScript" version="0.15.0-build58334" targetFramework="net452" /> 
    <package id="Microsoft.ApplicationInsights.PerfCounterCollector" version="2.1.0" targetFramework="net452" /> 
    <package id="Microsoft.ApplicationInsights.Web" version="2.1.0" targetFramework="net452" /> 
    <package id="Microsoft.ApplicationInsights.WindowsServer" version="2.1.0" targetFramework="net452" /> 
    <package id="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" version="2.1.0" targetFramework="net452" /> 
    <package id="Microsoft.AspNet.OData" version="5.9.1" targetFramework="net452" /> 
    <package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net452" /> 
    <package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net452" /> 
    <package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net452" /> 
    <package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.3" targetFramework="net452" /> 
    <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.1" targetFramework="net452" /> 
    <package id="Microsoft.Net.Compilers" version="1.3.2" targetFramework="net452" developmentDependency="true" /> 
    <package id="Microsoft.OData.Core" version="6.15.0" targetFramework="net452" /> 
    <package id="Microsoft.OData.Edm" version="6.15.0" targetFramework="net452" /> 
    <package id="Microsoft.Spatial" version="6.15.0" targetFramework="net452" /> 
    <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" /> 
    <package id="System.Spatial" version="5.7.0" targetFramework="net452" /> 
</packages> 

Вот что WebApiConfig.cs:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web.Http; 
using System.Web.OData.Builder; 
using System.Web.OData.Extensions; 
using HealthcareWebApp; 

namespace HealthcareWebApp 
{ 
    public static class WebApiConfig 
    { 
     public static void Register(HttpConfiguration config) 
     { 
      // Web API configuration and services 

      // Web API routes 
      config.MapHttpAttributeRoutes(); 

      config.Routes.MapHttpRoute(
       name: "DefaultApi", 
       routeTemplate: "api/{controller}/{id}", 
       defaults: new { id = RouteParameter.Optional } 
      ); 

      //Custom code 
      ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); 
      builder.EntitySet<PAYMENTS>("PAYMENTS"); //.EntityType.HasKey(p => p.PAYMENT_KEY); 
      builder.EntitySet<DATE_DIM>("DATE_DIM"); //.EntityType.HasKey(p => p.Year); 
      builder.EntitySet<PROVIDERS>("PROVIDERS"); //.EntityType.HasKey(p => p.Provider_Id); 
      config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel()); 

     } 
    } 
} 

PAYMENTSController.cs:

using System; 
using System.Collections.Generic; 
using System.Data; 
using System.Data.Entity; 
using System.Data.Entity.Infrastructure; 
using System.Linq; 
using System.Net; 
using System.Net.Http; 
using System.Web.Http; 
using System.Web.ModelBinding; 
using System.Web.OData; 
using System.Web.OData.Query; 
using System.Web.OData.Routing; 
using HealthcareWebApp; 

namespace HealthcareWebApp.Controllers 
{ 
    /* 
    The WebApiConfig class may require additional changes to add a route for this controller. Merge these statements into the Register method of the WebApiConfig class as applicable. Note that OData URLs are case sensitive. 

    using System.Web.OData.Builder; 
    using System.Web.OData.Extensions; 
    using HealthcareWebApp; 
    ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); 
    builder.EntitySet<PAYMENTS>("PAYMENTS"); 
    builder.EntitySet<DATE_DIM>("DATE_DIM"); 
    builder.EntitySet<PROVIDERS>("PROVIDERS"); 
    config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel()); 
    */ 
    public class PAYMENTSController : ODataController 
    { 
     private FlexIT_HealthcareEntities db = new FlexIT_HealthcareEntities(); 

     // GET: odata/PAYMENTS 
     [EnableQuery] 
     public IQueryable<PAYMENTS> GetPAYMENTS() 
     { 
      return db.PAYMENTS; 
     } 

     // GET: odata/PAYMENTS(5) 
     [EnableQuery] 
     public SingleResult<PAYMENTS> GetPAYMENTS([FromODataUri] int key) 
     { 
      return SingleResult.Create(db.PAYMENTS.Where(pAYMENTS => pAYMENTS.PAYMENT_KEY == key)); 
     } 

     // PUT: odata/PAYMENTS(5) 
     public IHttpActionResult Put([FromODataUri] int key, Delta<PAYMENTS> patch) 
     { 
      Validate(patch.GetEntity()); 

      if (!ModelState.IsValid) 
      { 
       return BadRequest(ModelState); 
      } 

      PAYMENTS pAYMENTS = db.PAYMENTS.Find(key); 
      if (pAYMENTS == null) 
      { 
       return NotFound(); 
      } 

      patch.Put(pAYMENTS); 

      try 
      { 
       db.SaveChanges(); 
      } 
      catch (DbUpdateConcurrencyException) 
      { 
       if (!PAYMENTSExists(key)) 
       { 
        return NotFound(); 
       } 
       else 
       { 
        throw; 
       } 
      } 

      return Updated(pAYMENTS); 
     } 

     // POST: odata/PAYMENTS 
     public IHttpActionResult Post(PAYMENTS pAYMENTS) 
     { 
      if (!ModelState.IsValid) 
      { 
       return BadRequest(ModelState); 
      } 

      db.PAYMENTS.Add(pAYMENTS); 
      db.SaveChanges(); 

      return Created(pAYMENTS); 
     } 

     // PATCH: odata/PAYMENTS(5) 
     [AcceptVerbs("PATCH", "MERGE")] 
     public IHttpActionResult Patch([FromODataUri] int key, Delta<PAYMENTS> patch) 
     { 
      Validate(patch.GetEntity()); 

      if (!ModelState.IsValid) 
      { 
       return BadRequest(ModelState); 
      } 

      PAYMENTS pAYMENTS = db.PAYMENTS.Find(key); 
      if (pAYMENTS == null) 
      { 
       return NotFound(); 
      } 

      patch.Patch(pAYMENTS); 

      try 
      { 
       db.SaveChanges(); 
      } 
      catch (DbUpdateConcurrencyException) 
      { 
       if (!PAYMENTSExists(key)) 
       { 
        return NotFound(); 
       } 
       else 
       { 
        throw; 
       } 
      } 

      return Updated(pAYMENTS); 
     } 

     // DELETE: odata/PAYMENTS(5) 
     public IHttpActionResult Delete([FromODataUri] int key) 
     { 
      PAYMENTS pAYMENTS = db.PAYMENTS.Find(key); 
      if (pAYMENTS == null) 
      { 
       return NotFound(); 
      } 

      db.PAYMENTS.Remove(pAYMENTS); 
      db.SaveChanges(); 

      return StatusCode(HttpStatusCode.NoContent); 
     } 

     // GET: odata/PAYMENTS(5)/DATE_DIM 
     [EnableQuery] 
     public SingleResult<DATE_DIM> GetDATE_DIM([FromODataUri] int key) 
     { 
      return SingleResult.Create(db.PAYMENTS.Where(m => m.PAYMENT_KEY == key).Select(m => m.DATE_DIM)); 
     } 

     // GET: odata/PAYMENTS(5)/PROVIDERS 
     [EnableQuery] 
     public SingleResult<PROVIDERS> GetPROVIDERS([FromODataUri] int key) 
     { 
      return SingleResult.Create(db.PAYMENTS.Where(m => m.PAYMENT_KEY == key).Select(m => m.PROVIDERS)); 
     } 

     protected override void Dispose(bool disposing) 
     { 
      if (disposing) 
      { 
       db.Dispose(); 
      } 
      base.Dispose(disposing); 
     } 

     private bool PAYMENTSExists(int key) 
     { 
      return db.PAYMENTS.Count(e => e.PAYMENT_KEY == key) > 0; 
     } 
    } 
} 

Наконец, PAYMENTS.cs модель:

//------------------------------------------------------------------------------ 
// <auto-generated> 
//  This code was generated from a template. 
// 
//  Manual changes to this file may cause unexpected behavior in your application. 
//  Manual changes to this file will be overwritten if the code is regenerated. 
// </auto-generated> 
//------------------------------------------------------------------------------ 

namespace HealthcareWebApp 
{ 
    using System; 
    using System.Collections.Generic; 

    public partial class PAYMENTS 
    { 
     [System.ComponentModel.DataAnnotations.Key] //manually added by ataft 
     public int PAYMENT_KEY { get; set; } 
     public string DRG_Definition { get; set; } 
     public string Provider_Id { get; set; } 
     public string Hospital_Referral_Region_Description { get; set; } 
     public Nullable<decimal> Total_Discharges_ { get; set; } 
     public Nullable<decimal> Covered_Charges { get; set; } 
     public Nullable<decimal> Total_Payments { get; set; } 
     public Nullable<decimal> Medicare_Payments { get; set; } 
     public int Year { get; set; } 

     public virtual DATE_DIM DATE_DIM { get; set; } 
     public virtual PROVIDERS PROVIDERS { get; set; } 
    } 
} 

ответ

9

Это проблема фильтра и groupby, фильтр не может применяться к групповому или агрегированному свойству и разрешать в WebAPI/OData 5.9.1.

https://www.nuget.org/packages/Microsoft.AspNet.OData/5.9.1

И в вашем сценарии, применяются всегда будет выполняться первым, а затем отфильтровывать получить выполняется, поэтому, когда $apply=groupby((Provider_Id),aggregate(Total_Payments with sum as Total_Payments)), результат не будет содержать DRG_Definition, поэтому фильтр не удалось, если вы хотите отфильтровать первый, вам следует использовать фильтр в применении, как $apply=filter(Name eq 'Lowest')/groupby((Name))

FYI спецификации http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/odata-data-aggregation-ext-v4.0.html

+0

Я обновил с пакетами, которые я использую, которые я должен был сделать с самого начала. Я использую Microsoft.AspNet.OData 5.9.1, но также заметил Microsoft.AspNet.WebApi.OData 5.3.1, который говорит, что это для Odata v1-3. Я попытался удалить Microsoft.AspNet.WebApi.OData и обновить его до последней версии, но не работал. Любые другие идеи? – Andrew

+0

обновленный ответ :) –

+0

Awesome, спасибо! Я прошел через спецификации несколько раз, но, возможно, пропустил его в разделе «Последовательности трансформации»: http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/cs02/odata -data-агрегацию доб-v4.0-cs02.html # _Toc435016616. Я не технический писатель, но я мог бы назвать этот раздел «Агрегация с groupby и filter» :) – Andrew