I have two entities defined in the server:
public partial class MyModel
{
public string ModelCode { get; set; }
public virtual ICollection<MyModelSubItem> SubItems { get; set; } = new HashSet<MyModelSubItem>();
[NotMapped]
public IDictionary<string, object> DynamicProperties { get; set; }
}
public partial class MyModelSubItem
{
public string SubItemCode { get; set; }
}
The controller has the following:
[EnableQuery]
public IQueryable<MyModel> Get()
{
return _myModelContext.GetAll();
}
In the client, I extend MyModel
:
public partial class MyModel
{
public int SubItemCount => SubItems.Count;
}
When I try to query the DB using the client-defined SubItemCount
property, I get the following error
Query: /odata/v1/MyModel?$filter=true&$orderby=SubItemCount%20desc
Error: System.ArgumentException: Static property requires null instance, non-static property requires non-null instance. (Parameter 'instance')
Querying using the non-dynamic properties work fine. Even adding/patching work fine when requests include the dynamic properties. It's only filtering/sorting that isn't working.
I am using OData v4 and the Unchase OData client code generator.
I was wondering why this is case. Any help would be highly appreciated.
I solved the issue by using a custom EnableQuery
attribute on the controller, as per the answer posted here:
.NET Core 2.1 OData v4 modify $filter on server side
public class MyModelEnableQueryAttribute : EnableQueryAttribute
{
public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
{
if (queryOptions.Filter != null)
{
var queryDict = new Dictionary<string, StringValues>();
foreach (var queryKeyValPair in queryOptions.Request.Query)
{
var modifiedSingleQueryValues = new List<string>();
foreach (var singleQueryValues in queryKeyValPair.Value)
{
if (singleQueryValues.Contains("SubItemCount"))
{
modifiedSingleQueryValues.Add(singleQueryValues.Replace("SubItemCount", "SubItems/$count"));
}
else
{
modifiedSingleQueryValues.Add(singleQueryValues);
}
}
queryDict.Add(queryKeyValPair.Key, new StringValues(modifiedSingleQueryValues.ToArray()));
}
queryOptions.Request.Query = new QueryCollection(queryDict);
queryOptions = new ODataQueryOptions(queryOptions.Context, queryOptions.Request);
}
return base.ApplyQuery(queryable, queryOptions);
}
}
Controller:
[MyModelEnableQuery]
public IQueryable<MyModel> Get()
{
return _myModelContext.GetAll();
}
This requires that the request includes $expand
and $count
on SubItems
e.g.
/odata/v1/MyModel?$filter=true&$orderby=SubItemCount%20desc&$expand=SubItems($count=true)
Hopefully someone finds this useful if they come across the same problem as I did.