我想知道是否有可能在扩展子句中为项目预先过滤ODAP结果。我只希望根据预定义的界面过滤掉一个已删除的标志。WebAPI OData预过滤扩展查询
public interface IDbDeletedDateTime
{
DateTime? DeletedDateTime { get; set; }
}
public static class IDbDeletedDateTimeExtensions
{
public static IQueryable<T> FilterDeleted<T>(this IQueryable<T> self)
where T : IDbDeletedDateTime
{
return self.Where(s => s.DeletedDateTime == null);
}
}
public class Person : IDbDeletedDateTime
{
[Key]
public int PersonId { get; set }
public DateTime? DeletedDateTime { get; set; }
public virtual ICollection<Pet> Pets { get; set; }
}
public class Pet : IDbDeletedDateTime
{
[Key]
public int PetId { get; set }
public int PersonId { get; set }
public DateTime? DeletedDateTime { get; set; }
}
public class PersonController : ApiController
{
private PersonEntities db = new PersonEntities();
[EnableQuery]
// GET: api/Persons
public IQueryable<Person> GetPersons()
{
return db.Persons.FilterDeleted();
}
}
你可以看到我很容易过滤删除的人。当一个人从查询像/API /人删除宠物的问题就来了?$扩大=宠物
有没有一种方法来检查,如果这种扩张“宠物”是一个IDbDeletedDateTime并相应地进行筛选?也许有更好的方法来解决这个问题?
编辑:
我想基于什么在this answer捡起来解决这个问题。我不认为这是可以做到的,至少在所有情况下都是如此。 ExpandedNavigationSelectItem
的唯一部分看起来像是与过滤器相关的是FilterClause
。当它没有过滤器时,它可以为空,,它只是一个吸气属性,这意味着我们不能如果我们想要设置一个新的过滤器。天气还是不可能修改一个当前的过滤器只能覆盖一个小的用例,如果我不能新增一个过滤器,我并不特别感兴趣。
我有一个扩展方法,将递归通过所有展开子句,并且您至少可以看到每个展开的FilterOption。如果任何人都可以完全实现这个90%的代码,那将是惊人的,但我不会屏住呼吸。
public static void FilterDeletables(this ODataQueryOptions queryOptions)
{
//Define a recursive function here.
//I chose to do it this way as I didn't want a utility method for this functionality. Break it out at your discretion.
Action<SelectExpandClause> filterDeletablesRecursive = null;
filterDeletablesRecursive = (selectExpandClause) =>
{
//No clause? Skip.
if (selectExpandClause == null)
{
return;
}
foreach (var selectedItem in selectExpandClause.SelectedItems)
{
//We're only looking for the expanded navigation items.
var expandItem = (selectedItem as ExpandedNavigationSelectItem);
if (expandItem != null)
{
//https://msdn.microsoft.com/en-us/library/microsoft.data.odata.query.semanticast.expandednavigationselectitem.pathtonavigationproperty(v=vs.113).aspx
//The documentation states: "Gets the Path for this expand level. This path includes zero or more type segments followed by exactly one Navigation Property."
//Assuming the documentation is correct, we can assume there will always be one NavigationPropertySegment at the end that we can use.
var edmType = expandItem.PathToNavigationProperty.OfType<NavigationPropertySegment>().Last().EdmType;
string stringType = null;
IEdmCollectionType edmCollectionType = edmType as IEdmCollectionType;
if (edmCollectionType != null)
{
stringType = edmCollectionType.ElementType.Definition.FullTypeName();
}
else
{
IEdmEntityType edmEntityType = edmType as IEdmEntityType;
if (edmEntityType != null)
{
stringType = edmEntityType.FullTypeName();
}
}
if (!String.IsNullOrEmpty(stringType))
{
Type actualType = typeof(PetStoreEntities).Assembly.GetType(stringType);
if (actualType != null && typeof (IDbDeletable).IsAssignableFrom(actualType))
{
var filter = expandItem.FilterOption;
//expandItem.FilterOption = new FilterClause(new BinaryOperatorNode(BinaryOperatorKind.Equal, new ,));
}
}
filterDeletablesRecursive(expandItem.SelectAndExpand);
}
}
};
filterDeletablesRecursive(queryOptions.SelectExpand?.SelectExpandClause);
}
我不确定如果这会让我需要去哪里,但这是一个很好的答案。非常感谢!我可能会尝试一些今天的尝试 –
它看起来像OData甚至不支持过滤扩展内容在它的当前实施无论如何。不幸的是,我不认为真的有办法解决这个问题。 –
OData v4支持在$ expand子句中进行过滤。我编辑了我的答案,以解释如何手动处理这些嵌套过滤器(我不确定您是否可以嵌套OData支持的所有可能的过滤器,但至少包含基本过滤器,如$ skip,$ top for pagination,$ filter和$ select can嵌套)。 希望它对你有用。 (无论如何OData一天天在演变,所以我猜这很快会改变,并在不久的将来包含更多的选择)。 – elbecita