如何定义一个可选的导航属性(?$展开;)在code? [英] How does one define an (optional) navigation property (?$expand=) in code?

查看:538
本文介绍了如何定义一个可选的导航属性(?$展开;)在code?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

First the explanation and the gist, then the question. So:

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

Let's say I have a view AccountView defined in EF (6.1.1) database first (edmx) so that the code-generated class is

//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; }
}

然后,我创建了相同的命名空间部分类(实体)的

[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,最新的也有)如下:

And then in WebApiConfig I Write, or try to, something in OData v4 (the newest, 6.9.0.0 series with WebApi, the newest also) as follows

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

生成的 $元

<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 评论中提及,我应该如何定义

Question(s): As mentioned in the TODO comment, how should I define


  • 的导航属性,这样我可以打电话给 http://example.com/Accounts?$expand=Company 的http://例子.COM /账户?$公司

  • A navigational property so that I could call http://example.com/Accounts?$expand=Company or http://example.com/Accounts?$Companies?

现在它的工作原理,如果我称之为

Now it works if I call


  • http://example.com/Accounts

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

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

然后,如果我做这样的事情。

Then if I do something like


  • http://example.com/Accounts?$expand=Companies

  • http://example.com/Accounts?$expand=Company

  • http://example.com/Accounts(someId)?$ =拓展公司

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

我得到映入眼帘的 HTTP 400 (?$展开;公司)或 HTTP 500 (?$ =拓展公司)。

I get greeted by HTTP 400 (?$expand=Companies) or HTTP 500 (?$expand=Company).

我会成功,但创建一个遏制关系了。它看起来像,不过,它需要具有由一个ID定义的根实体,而我想提供GET为根和可选扩展到子榜对象(因此这个问题呢?$ =扩展)

I succeeded with creating a Containment relationship already. It looks like, though, it requires having the root entity defined by an ID, whereas I'd like to provide "GET" to the root and optionally expand to a "child list" objects (hence this question about ?$expand=).

现在的情况是有一个非可选的展开做了一个实体,但我怀疑,我想未来的事情已经是那里的列表的场景实体(或公司在这个具体的例子而言),但我怎么能实现这些场景?如何修复即使这种情况下的扩展应用于第一总是存在的子对象?

Now the case is having one non-optional expand done for one entity, but I suspect the next thing I'd like have is a scenario where there's a list of entities (or companies in terms of this specific example) but how could I achieve these scenarios? How to fix even this case of expanding to the first always existing sub-object?

我的控制器被定义如下

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,观点和模拟天生的文章<一个href=\"http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/using-$select,-$expand,-and-$value\"相对=nofollow>使用$选择,$扩大,并在的ASP.NET Web API的OData 2 $ 的价值。迄今没有成功...

What I'm basically trying to do is to add some more metadata to database first, edmx, views and mimick the article Using $select, $expand, and $value in ASP.NET Web API 2 OData. Thus far with no success...

&LT;编辑1:越来越复杂了,可以这么说。 HTTP 500错误来自内部异常(我不得不把打破托管框架例外),上面写着

<edit 1: The plot thickens, so to speak. The HTTP 500 error comes from an internal exception (I had to turn on breaking to managed framework exceptions) that says

System.NotSupportedException类型的第一次机会异常出现在EntityFramework.dll

A first chance exception of type 'System.NotSupportedException' occurred in EntityFramework.dll

其他信息:指定的类型成员公司不支持LINQ到实体。只有初始化,实体成员和实体导航属性都支持。

Additional information: The specified type member 'Company' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

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

So, yes, AccountView is a view and it does not have a direct foreign key relation to Company table (which just happens to be a table, but it could be a view too). How could I go to add one? I though adding metadata did the trick already, as evidenced by $metadata information. Doesn't OData just write an INNER JOIN in the database? Am I missing something here? ... This seem to be related to the way I added the Company reference and EF doesn't like that. It looks I should go about adding it to the OData model only...

&LT;编辑2:这似乎并没有发挥作用(至少不符合我的设置),如果我更改 AccountView CompanyId CompanyID 相匹配的外壳,在公司定义的表。

<edit 2: It doesn't seem to make a difference (at least not with the setting I have) if I change the AccountView CompanyId to CompanyID to match the casing that of the definition in Company table.

&LT; EDIT3:我问另外一个相关的问题这一点,<一个href=\"http://stackoverflow.com/questions/27580167/how-to-add-complex-properties-on-a-model-built-with-odataconventionmodelbuilder\">How在从EF模型与ODataConventionModelBuilder建立了一个模型添加复杂的属性。

<edit3: I asked another, related question to this, How to add complex properties on a model built with ODataConventionModelBuilder from an EF model.

推荐答案

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

It looks I got this one answered as to related another post and little pushing from another forum.

关于异常,事实上,它是由该查询击中到数据库并尝试检索它们没有定义的列引起的。欲了解更多信息:

About the exception, indeed, it was caused by the query hitting to the database and trying to retrieve columns which aren't defined there. For more information:

  • The specified type member is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported
  • EF 4: The specified type member '*' is not supported in LINQ to Entities

然后作为code和答案,另一个问题是,<一个href=\"http://stackoverflow.com/questions/27535409/expanding-navigation-properties-with-odataqueryoptions/27603462#27603462\">Expanding导航性能与ODataQueryOptions 。在code有点这里增加如下:

Then as for the code and answer, the other question is Expanding navigation properties with ODataQueryOptions. The code a bit augmented here is as follows

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

这篇关于如何定义一个可选的导航属性(?$展开;)在code?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆