首先是解释和要点,然后是问题。所以:
假设我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>
问题:如TODO
评论中所述,我应该如何定义
- 一个导航属性,以便我可以调用
http://example.com/Accounts?$expand=Company
或http://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 (?$expand=Companies) 或HTTP 500 (?$expand=Company) 的欢迎。
我已经成功地建立了Containment
关系。不过,它看起来需要由 ID 定义根实体,而我想向根提供“GET”并可选地扩展为“子列表”对象(因此这个关于 ?$expand= 的问题) .
现在的案例是为一个实体完成一个非可选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,视图并模仿文章Using $select, $expand, and $value in ASP.NET Web API 2 OData。到目前为止没有成功...
<编辑1:可以这么说,情节变厚了。HTTP 500 错误来自一个内部异常(我必须打开对托管框架异常的中断),它说
EntityFramework.dll 中发生了“System.NotSupportedException”类型的第一次机会异常
附加信息:LINQ to Entities 不支持指定的类型成员“公司”。仅支持初始化程序、实体成员和实体导航属性。
所以,是的,AccountView
是一个视图,它与表没有直接的外键关系Company
(它恰好是一个表,但它也可能是一个视图)。我怎么去加一个?正如信息所证明的那样,我虽然添加元数据已经成功了$metadata
。OData 不只是INNER JOIN
在数据库中写入一个吗?我在这里错过了什么吗?...这似乎与我添加Company
参考的方式有关,而 EF 不喜欢那样。看来我应该只将它添加到 OData 模型中......
<编辑 2:如果我将 更改AccountView
CompanyId
为CompanyID
以匹配Company
。
<edit3:我问了另一个与此相关的问题,How to add complex properties on a model build with ODataConventionModelBuilder from an EF model。