简体   繁体   中英

C# ODataQueryOptions with EF6 navigation property filters. System.ArgumentNullException : Value cannot be null. Parameter name: type

I've a parent class

public class Audit : BaseModel//Properties are intentionally made non virtual
{
    public string Name { get; set; }
    public int FacilityId { get; set; }
    public string Passcode { get; set; }
    public ICollection<AuditDate> AuditDates { get; set; }
}

and a child class

public class AuditDate : BaseModel
{
    public int Duration { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate{ get; set; }
}

Now, these are used in entity framework (ver. 6) CF approach where

public virtual DbSet Audits { get; set; }

is declared. Then, I'm using below code to apply oData queries-

Prepared ODataQueryOptions:

private ODataQueryOptions PrepareOdataQueryOption(Uri oDataUri)
    {
            HttpConfiguration httpConfiguration = new HttpConfiguration();
            httpConfiguration.EnableDependencyInjection();

            HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, oDataUri);
            httpRequestMessage.Properties[HttpPropertyKeys.HttpConfigurationKey] = httpConfiguration;

            ODataModelBuilder oDataModelBuilder = new ODataConventionModelBuilder();
            oDataModelBuilder.EntityType<TDomainModel>();

            ODataQueryContext oDataQueryContext = new ODataQueryContext(oDataModelBuilder.GetEdmModel(), typeof(TDomainModel), null);
            return new ODataQueryOptions(oDataQueryContext, httpRequestMessage);
    }

Apply ODataQueryOptions ( dbSet is DbSet<T>, T is Audit in this case )

ODataQueryOptions oDataQueryOptions = PrepareOdataQueryOption(oDataUri);
IQueryable Value = oDataQueryOptions.ApplyTo(dbSet);

But when I call this using following oData uri

http://localhost:7071/api/Audit ?$expand=AuditDates($filter=Id eq 1)

I get error at statement IQueryable Value = oDataQueryOptions.ApplyTo(dbSet);

System.ArgumentNullException : Value cannot be null. Parameter name: type at Microsoft.OData.Edm.EdmUtil.CheckArgumentNull[T](T value,String parameterName). Microsoft.OData.Edm: Value cannot be null.

This happens only when I try to filter child records so that I can retrieve only few child records, not all.

Following URIs work as expected (error is only in case of filter on navigation properties):

  1. http://localhost:7071/api/Audit ?$expand=AuditDates
  2. http://localhost:7071/api/Audit ?$expand=AuditDates&$filter=AuditDates/any(auditDate: auditDate/Id eq 1)
  3. http://localhost:7071/api/Audit ?$select=Id,Name
  4. http://localhost:7071/api/Audit ?$select=Id,Name&$expand=AuditDates($select=Id,StartDate)

Thanks!

The problem is in the following function (statement):

private ODataQueryOptions PrepareOdataQueryOption(Uri oDataUri)
{
    ...
    oDataModelBuilder.EntityType<TDomainModel>();
    ...
}

Firstly, it should be EntitySet, not EntityType. EntitySet registers an entity set as a part of the model.

Secondly, as only parent object was declared, not navigation properties, it was unable to find the type of child records (hence, that error in "Parameter name: type").

I presumed that ODataModelbuilder will auto pick the AuditDate entity set (just like entity Framework Code First approach), but it didn't. I had to declare it explicitly. Thus, I changed above statement to the following statements (to match DbContext) and everything started working.

private ODataQueryOptions PrepareOdataQueryOption(Uri oDataUri)
{
    ...
    oDataModelBuilder.EntitySet<Audit>("Audits");//Only parent domain model is required unless you want to filter navigation property rows
    oDataModelBuilder.EntitySet<AuditDate>("AuditDates");
    ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM