如何定义(可选)导航属性(?$扩大=)的代码?(How does one define an (op

2019-10-21 11:28发布

首先,解释和要点,那么问题。 所以:

比方说,我有一个观点AccountView在EF(6.1.1)数据库第一(EDMX)定义,这样的代码生成的类是

//This class is generated from a view by EF (edmx)...
public partial class AccountView
{
    public System.Guid Id { get; set; }
    public int CompanyId { get; set; }
}

然后,我创建在相同的命名空间(一个局部类Entities ),为

[MetadataType(typeof(AccounViewMetaData))]
public partial class AccounView
{
    //This is added here explicitly. AccountView itself exposes just
    //a naked key, CompanyId.
    public virtual Company Company { get; set; }

    //This is just in case...
    public class AccounViewDomainMetaData
    {
        //This is to add a navigation property to the OData $metadata. How to do this
        //in WebApiConfig? See as follows...
        [ForeignKey("Company")]
        public int CompanyId { get; set; }
    }
}

//This is an EF generated class one from an edmx..-
public partial class Company
{
    public Company()
    {            
    }

    public int CompanyID { get; set; }
    public string Name { get; set; }
}  

然后在WebApiConfig我写,或试图在的OData v4的东西(最新,6.9.0.0系列的WebAPI,最新的也可以)如下

builder.EntitySet<Entities.Company>("Companies");

var accountSet = builder.EntitySet<Entities.AccountView>("Accounts");
accountSet.EntityType.HasKey(i => i.Id); //EF has hard time recognizing primary keys on database first views...

//TODO: How should I define the required binding so that I could "?$expand=Company"
//as such as ``http://example.com/service/Accounts?$expand=Company``
//accountSet.HasRequiredBinding(i => i.CompanyId, typeof(Entities.Company));

得到的$metadata是像

<schema>
    <EntityType Name="Company">
        <Key>
            <PropertyRef Name="CompanyID"/>
        </Key>
        <Property Name="CompanyID" Type="Edm.Int32" Nullable="false"/>
        <Property Name="Name" Type="Edm.String"/>
     </EntityType>

    <EntityType Name="AccountView">
        <Key>
            <PropertyRef Name="Id"/>
        </Key>
        <Property Name="Id" Type="Edm.Guid" Nullable="false"/>
        <Property Name="CompanyId" Type="Edm.Int32" Nullable="false"/>
        <NavigationProperty Name="Company" Type="Entities.Company" Nullable="false"/>
    </EntityType>
</Schema>

问题(S):正如提到TODO评论,我应该如何界定

  • 导航属性,以便我可以打电话给http://example.com/Accounts?$expand=Companyhttp://example.com/Accounts?$Companies

现在,它的工作原理,如果我打电话

  • http://example.com/Accounts
  • http://example.com/Accounts(someId)

然后,如果我这样做

  • http://example.com/Accounts?$expand=Companies
  • http://example.com/Accounts?$expand=Company
  • http://example.com/Accounts(someId)?$expand=Company

我得到HTTP 400($?展开;公司)或HTTP 500打招呼(?$ =扩大公司)。

我成功与创建一个Containment已经关系。 它看起来像,不过,它需要具有通过ID定义的根实体,而我想提供“GET”,以根和可选扩展到“子列表”对象(因此这个问题的呢?$扩大=) 。

现在的情况是有一个非可选expand为一个实体完成的,但我怀疑,我想未来的事情已经是这样一个场景,有实体的名单(或公司在这个具体的例子而言),但我怎么能实现这些场景? 如何修复即使这种情况下扩展到第一总是存在的子对象的?

我的控制器定义如下

public class AccountsController: ODataController
{
    [EnableQuery]
    public IHttpActionResult Get()
    {
        try
        {
            //This context here is a EF entities model (generated from an edmx)...
            return Ok(Context.AccountView);
        }
        catch(Exception ex)
        {
            return InternalServerError(); 
        }
    }

    [EnableQuery]
    public IHttpActionResult Get([FromODataUri]Guid key)
    {
        try
        {
            return Ok(SingleResult.Create(Context.AccountView.Where(a => a.Id == key)));
        }
        catch (Exception ex)            
        {                
            return InternalServerError(ex); 
        }
    }
}

什么我基本上试图做的是先添加一些更多的元数据数据库,EDMX,意见和模拟天生的文章使用$选择,$扩大,并在的ASP.NET Web API的OData 2 $值 。 迄今为止没有成功...

<编辑1:越来越复杂了,可以这么说。 HTTP 500错误来自内部异常(我不得不把打破,以管理框架例外),说

类型的第一次机会异常的“System.NotSupportedException”发生在EntityFramework.dll

附加信息:指定类型构件“公司”不LINQ支撑到实体。 只有初始化,实体成员和实体导航属性都支持。

所以,是的, AccountView是一个视图,它没有直接的外键关系到Company表(这恰好是表,但它可能是一个视图太)。 我怎么可能去增加一个? 我虽然添加元数据的伎俩已经,就是明证$metadata信息。 不只是OData的写INNER JOIN数据库? 我失去了一些东西在这里? ...这似乎与我添加的方式Company参考和EF不喜欢这样。 它看起来我应该去了解它添加到只有OData的模型...

<编辑2:它似乎并不有所作为(至少不与我有设置)如果我改变AccountView CompanyIdCompanyID以匹配壳体,在定义的Company表。

<EDIT3:我问另一个相关的问题这一点, 如何在从EF模型ODataConventionModelBuilder建立了一个模型添加复杂性 。

Answer 1:

尝试$扩大,而不是与拓展。



Answer 2:

它看起来我这人回答为相关的另一篇文章,并从另一个论坛小推。

关于例外,事实上,它是由查询击打到数据库中,并试图找回这是没有定义的列造成的。 欲获得更多信息:

  • 指定类型部件没有在LINQ支撑到实体。 只有初始化,实体成员和实体导航属性都支持
  • EF 4:指定类型成员“*”不LINQ支撑到实体

然后,作为代码和回答,另一个问题是与ODataQueryOptions扩大导航属性 。 这里有点增强的代码如下

public async Task<IHttpActionResult> Get(ODataQueryOptions<T> options)
{
    IQueryable<T> tempQuery = Context.AccountView;
    IQueryable<T result = tempQuery;

    if(options.SelectExpand != null)
    {
        if(options.Filter != null)
        {
            tempQuery = options.Filter.ApplyTo(tempQuery, new ODataQuerySettings()) as IQueryable<T>;   
        }
         /* Other options that should go to the DB level... */

        //The results need to be materialized, or otherwise EF throws a
        //NotSupportedException due to columns and properties that aren't in the DB...
        result = (await tempQuery.ToListAsync()).AsQueryable();

        //Do here the queries that can't be hit straight by the queries. E.g.
        //navigation properties not defined in EF views (that can't be augmented)...
        //E.g. get the company here.

        //This is needed to that OData formatter knows to render navigation links too.
        Request.ODataProperties().SelectExpandClause = options.SelectExpand.SelectExpandClause;
}

return Ok(result);


文章来源: How does one define an (optional) navigation property (?$expand=) in code?