我目前正在 asp.net 中从事 Web 服务项目。我尝试在检索数据的函数中包含子元素。
它与 url 一起使用:
http://localhost:8080/myEntity/?$expand=myChildElement
但我似乎无法像这样包含以下级别的子元素:
http://localhost:8080/myEntity/?$expand=myChildElement/mySubChildElement
这是我的功能:
public virtual async Task<IHttpActionResult> GetElements(ODataQueryOptions<TEntity> queryOptions)
{
IQueryable<TPoco> query = context.Set<TPoco>();
string[] includes = null;
string includeText = queryOptions.SelectExpand != null ? queryOptions.SelectExpand.RawExpand : null;
if(! string.IsNullOrEmpty(includeText))
{
includes = queryOptions.SelectExpand.RawExpand.Split(',');
return Ok(await query.ProjectTo<TEntity>(null, includes).ToListAsync());
}
return Ok(await query.ProjectTo<TEntity>().ToListAsync());
}
这是我的 TPoco 模型的示例(myChildElement 可以是实体“Project”,mySubChildElement 可以是子实体“ProjectType”):
public class ContractEntity : BaseEntity
{
public ContractEntity()
{
this.Addresses = new HashSet<AddressEntity>();
}
override public Guid Id { get; set; }
override public string DisplayName { get { return No.ToString(); } set { } }
override public string ClassType { get { return "Contract"; } set { } }
override public string MarkerColor { get { return Colors.Green.ToString(); } set { } }
public int? No { get; set; }
public DateTime? OfficialDate { get; set; }
public DateTime? ValidDate { get; set; }
public DateTime? SignatureDate { get; set; }
public Guid? ProjectId { get; set; }
[...]
public virtual ICollection<AccountingItemEntity> AccountingItems { get; set; }
public virtual ICollection<TagEntity> Tags { get; set; }
public virtual ProjectEntity Project { get; set; }
[...]
}
我希望你能帮助我。
最佳答案
我这样做的方式是,我使用了 .ProjectTo
返回一个 IQueryable
的事实,所以我让 OData 框架通过不调用 ToListAsync() 来处理查询
我自己,但返回 IQueryable
。
// In some class that is ': ODataController'
[EnableQuery] //Attribute makes sure the OData framework handles querying
public IQueryable<TDto> Get(ODataQueryOptions<TDto> options) {
//The names of the properties requested by the client in the '$expand=' query option
string[] requestedExpands = Helpers.Expand.GetMembersToExpandNames(options); // I made a helper for this, you can probably just use your code, or see my impementation below.
var set = Db.Set<TEntity>().AsNoTracking(); //You might want to remove AsNoTracking if it doesn't work
var converted = set.ProjectTo<TDto>(MapConfig, null, requestedExpands);
return converted;
}
在此示例中,TDto
是我要发送给客户端的类型 TEntity
是 Entity Framework POCO 类。
我的 MapConfig
我在应用程序启动时设置,这里我将可扩展属性设置为“显式扩展”模式:
MapConfig = new MapperConfiguration(cfg => {
cfg.CreateMap<EFType, DTOType>(MemberList.Destination)
.ForMember(c => c.ExpandableProperty, options => options.ExplicitExpansion());
});
正如我在评论中所说,我通过在 URL 中嵌套 $expand=
来请求数据:
api/myEntity?$expand=myChildElement($expand=mySubChildElement)
这对我有用,希望你能复制这种成功。
编辑:再看一遍,如果你想扩展 myEntity.myChildElement.mySubChildElement
你传递的 string[]
'requestedExpands' AutoMapper 必须包含 1 个条目:myChildElement.mySubChildElement
。我为所有 3 个实体定义了一个映射,同样使用 ExplicitExpansion
选项。
根据@Tim Pohlmann 的要求,更新我的 GetMembersToExpandNames
实现:
public static class Expand {
public static string[] GetMembersToExpandNames(ODataQueryOptions options) {
return GetExpandPropertyPaths(GetExpandItems(options?.SelectExpand?.SelectExpandClause)).ToArray();
}
private static IEnumerable<string> GetExpandPropertyPaths(IEnumerable<ExpandedNavigationSelectItem> items, string prefix = "") {
foreach(var item in items) {
foreach(var res in GetExpandPropertyPaths(item, prefix)) {
yield return res;
}
}
}
private static IEnumerable<string> GetExpandPropertyPaths(ExpandedNavigationSelectItem item, string prefix = "") {
var curPropName = item.NavigationSource.Name;
var nestedExpand = GetExpandItems(item.SelectAndExpand).ToArray();
if(nestedExpand.Count() > 0) {
foreach(var res in GetExpandPropertyPaths(nestedExpand, $"{prefix}{curPropName}.")) {
yield return res;
}
} else {
yield return $"{prefix}{curPropName}";
}
}
private static IEnumerable<ExpandedNavigationSelectItem> GetExpandItems(SelectExpandClause sec) {
if(sec != null) {
var res = sec?.SelectedItems?.OfType<ExpandedNavigationSelectItem>();
if(res != null) {
return res;
}
}
return new ExpandedNavigationSelectItem[0];
}
}
关于c# - 如何使用 AutoMapper 和 OData 扩展子级别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42394599/