如何定义一个可选的导航属性(?$展开;)在code? [英] How does one define an (optional) navigation property (?$expand=) in 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
orhttp://example.com/Accounts?$Companies
?
现在它的工作原理,如果我称之为
Now it works if I call
-
http://example.com/Accounts
或 -
http://example.com/Accounts(someId)
http://example.com/Accounts
orhttp://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
orhttp://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屋!