使用Web Api OData控制器扩展集合

时间:2014-01-08 14:49:47

标签: asp.net-web-api odata asp.net-web-api-odata

我正在使用OData框架5.0.0和Web API 5.0.0以及EntityFramework 5.0.0。并且在作为集合的导航属性上扩展有问题。我总是得到以下例外:

The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.

The given key was not present in the dictionary.

at System.Web.Http.OData.Query.Expressions.SelectExpandWrapper`1.GetEdmType()
at System.Web.Http.OData.Formatter.Serialization.ODataSerializerContext.GetEdmType(Object instance, Type type)
at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteEntry(Object graph, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteExpandedNavigationProperty(KeyValuePair`2 navigationPropertyToExpand, EntityInstanceContext entityInstanceContext, ODataWriter writer)
at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteExpandedNavigationProperties(IDictionary`2 navigationPropertiesToExpand, EntityInstanceContext entityInstanceContext, ODataWriter writer)
at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteEntry(Object graph, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders)
at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.WebHost.HttpControllerHandler.

展开非收藏导航属性就像魅力一样。

这些是我的EF课程:

public partial class ElementTemplate
{
    public ElementTemplate()
    {
        this.Elements = new HashSet<Element>();
        this.Derived = new HashSet<ElementTemplate>();
        this.TemplateAttributes = new HashSet<ElementTemplateAttribute>();
    }

    public System.Guid ID { get; set; }
    public string InheritancePath { get; set; }
    public string Name { get; set; }
    public short Level { get; set; }
    public string Description { get; set; }
    public string Type { get; set; }
    public bool AllowElementToExtend { get; set; }
    public Nullable<System.Guid> DefaultElementTemplateAttributeID { get; set; }
    public Nullable<System.Guid> BaseElementTemplateID { get; set; }
    public string SecurityDescriptor { get; set; }
    public Nullable<System.DateTime> CheckOutTime { get; set; }
    public string CheckOutUserName { get; set; }
    public string CheckOutMachineName { get; set; }

    public virtual ICollection<Element> Elements { get; set; }
    public virtual ICollection<ElementTemplate> Derived { get; set; }
    public virtual ElementTemplate Base { get; set; }
    public virtual ElementTemplateAttribute DefaultTemplateAttribute { get; set; }
    public virtual ICollection<ElementTemplateAttribute> TemplateAttributes { get; set; }
}

public partial class Element
{
    public Element()
    {
        this.Attributes = new HashSet<ElementAttribute>();
    }

    public System.Guid ID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string Comment { get; set; }
    public int Revision { get; set; }
    public bool HasChildren { get; set; }
    public bool HasMultipleVersions { get; set; }
    public Nullable<System.Guid> ElementTemplateID { get; set; }
    public Nullable<System.Guid> DBReferenceTypeID { get; set; }
    public string SecurityDescriptor { get; set; }
    public System.DateTime Created { get; set; }
    public string CreatedBy { get; set; }
    public System.DateTime Modified { get; set; }
    public string ModifiedBy { get; set; }
    public Nullable<System.DateTime> CheckOutTime { get; set; }
    public string CheckOutUserName { get; set; }
    public string CheckOutMachineName { get; set; }

    public virtual ICollection<ElementAttribute> Attributes { get; set; }
    public virtual ElementTemplate Template { get; set; }
}

ElementTemplate的元数据如下所示:

  <EntityType Name="ElementTemplate">
    <Key>
      <PropertyRef Name="ID" />
    </Key>
    <Property Name="ID" Type="Edm.Guid" Nullable="false" />
    <Property Name="InheritancePath" Type="Edm.String" />
    <Property Name="Name" Type="Edm.String" />
    <Property Name="Level" Type="Edm.Int16" Nullable="false" />
    <Property Name="Description" Type="Edm.String" />
    <Property Name="Type" Type="Edm.String" />
    <Property Name="AllowElementToExtend" Type="Edm.Boolean" Nullable="false" />
    <Property Name="DefaultElementTemplateAttributeID" Type="Edm.Guid" />
    <Property Name="BaseElementTemplateID" Type="Edm.Guid" />
    <Property Name="SecurityDescriptor" Type="Edm.String" />
    <Property Name="CheckOutTime" Type="Edm.DateTime" />
    <Property Name="CheckOutUserName" Type="Edm.String" />
    <Property Name="CheckOutMachineName" Type="Edm.String" />
    <NavigationProperty Name="Elements" Relationship="Entity_EntityModel_ElementTemplate_Elements_EntityModel_Element_ElementsPartner" ToRole="Elements" FromRole="ElementsPartner" />
    <NavigationProperty Name="Derived" Relationship="Entity_EntityModel_ElementTemplate_Derived_Entity_EntityModel_ElementTemplate_DerivedPartner" ToRole="Derived" FromRole="DerivedPartner" />
    <NavigationProperty Name="Base" Relationship="Entity_EntityModel_ElementTemplate_Base_Entity_EntityModel_ElementTemplate_BasePartner" ToRole="Base" FromRole="BasePartner" />
    <NavigationProperty Name="DefaultTemplateAttribute" Relationship="Entity_EntityModel_ElementTemplate_DefaultTemplateAttribute_Entity_EntityModel_ElementTemplateAttribute_DefaultTemplateAttributePartner" ToRole="DefaultTemplateAttribute" FromRole="DefaultTemplateAttributePartner" />
    <NavigationProperty Name="TemplateAttributes" Relationship="Entity_EntityModel_ElementTemplate_TemplateAttributesEntity_EntityModel_ElementTemplateAttribute_TemplateAttributesPartner" ToRole="TemplateAttributes" FromRole="TemplateAttributesPartner" />
  </EntityType>

控制器中的相关方法如下所示:

    // GET odata/ElementTemplates
    [Queryable]
    public IQueryable<ElementTemplate> GetElementTemplates()
    {
        return Db.ElementTemplates;
    }

    // GET odata/ElementTemplates(guid'...')
    [Queryable]
    public SingleResult<ElementTemplate> GetElementTemplate([FromODataUri] Guid key)
    {
        return SingleResult.Create(Db.ElementTemplates.Where(elementtemplate => elementtemplate.ID == key));
    }

    // GET odata/ElementTemplates(guid'...')/Elements
    [Queryable]
    public IQueryable<Element> GetElements([FromODataUri] Guid key)
    {
        return Db.ElementTemplates.Where(m => m.ID == key).SelectMany(m => m.Elements);
    }

以下查询有效:

  

/的OData / ElementTemplates(GUID '...')/片

     

/的OData / ElementTemplates?$扩大=基

     

/的OData / ElementTemplates?$扩大= DefaultTemplateAttribute

但是当访问一个集合时,我得到了上面提到的错误:

  

/的OData / ElementTemplates?$扩大=元素

     

/的OData / ElementTemplates(GUID '...')?$扩大=元素

如果我以预先加载数据的方式更改控制器:

    // GET odata/ElementTemplates
    [Queryable]
    public IQueryable<ElementTemplate> GetElementTemplates()
    {
        return Db.ElementTemplates.ToList().AsQueryable();
    }

    // GET odata/ElementTemplates(guid'...')
    [Queryable]
    public SingleResult<ElementTemplate> GetElementTemplate([FromODataUri] Guid key)
    {
        return SingleResult.Create(Db.ElementTemplates.Where(elementtemplate => elementtemplate.ID == key).ToList().AsQueryable());
    }

然后所有查询都有效,但这显然会影响性能。

这个问题似乎与Expanding collections with EntitySetController in MVC Web Api类似,但是他们说NHAPnate框架中存在问题,我显然没有使用它,所以必须有其他东西,任何想法?

通过WCF DataServices使用相同的EF模型时,我也没遇到这个问题。

谢谢!

1 个答案:

答案 0 :(得分:0)

事实证明,Web API将包含模型ID的CASE表达式添加到查询中。我的代码没有正确评估这个CASE表达式。