2
votes

We are creating a Search Function to return Matching Address Records in large database.

Address Table contains 20+ columns in SQL table, needs to query using different OData parameters, (EqualTo, Contains, Starts With, etc).

Trying to use OData, without injecting DBContext into API Controller. This is not allowed in current architecture. How can code written to allow this?

*We have it working utilizing ProjectTo. However OData Http specific features are being passed into Non-Api levels. Currently have ODataQueryOptions in the AppServices.

How Can We convert the Whole ODataQueryOptions to a Linq expression query (regardless of what is passed in), this resource is only for the filter, How to transform OData filter to a LINQ expression?

DBContext-->DomainLayer-->Dto--> Then API Level,

The two middle layers. Mappers map from EF DBContext to Domain to Dto.

Repository methods bring data.

AppService Methods converts to Dto.

Current Solution with ProjectTo:

Controller API:

[HttpGet]
public async Task<ActionResult<IList<AddressTypeDto>> GetAddressAPI(ODataQueryOptions<AddressTypeDto> queryOptions)
{
    return Ok(await _service.GetAddressTypeDto(queryOptions));
}

Application Service:

(How can we apply ODataModelBuilder mapping in Startup here?)

public async Task<AddressTypeResponse> GetAddressTypeDto(ODataQueryOptions<AddressTypeDto> queryOptions)
{
    var dto = (IQueryable<AddressTypeDto>)queryOptions.ApplyTo(_addressRepository.GetAddressTypes().ProjectTo<AddressTypeDto>(_mapper.ConfigurationProvider));
    var dtoList = await dto.ToListAsync();
    return dto;
}

Repository:

[EnableQuery]
public IQueryable<LkAddressType> GetAddressTypesData()
{
    return _ctx.LkAddressType.AsNoTracking();
}

Classes:

    public class AddressTypeDto
    {
        public int AddressTypeId { get; set; }
        public int? LastModifiedByUserId { get; set; }
        public string AddressTypeCode { get; set; }
        public string AddressTypeDescription { get; set; }
        public bool? Status { get; set; }
        public DateTime? CreateDate { get; set; }
    }

    public LkAddressType()
    {
        public int LkAddressTypeId { get; set; }
        public int? LastModifiedByUserId { get; set; }
        public string AddressTypeCode { get; set; }
        public string AddressTypeDescription { get; set; }
        public bool? Status { get; set; }
        public DateTime? CreateDate { get; set; }
        public DateTime? EffectiveStartDate { get; set; }
        public DateTime? EffectiveEndDate { get; set; }
    }

Using C# Net Core 2.2, Entity Framework, Sql Server Database

Resource: Attempting to utilize this also

How do I map an OData query against a DTO to another entity?

1
I think the [Queryable] attribute working only with a result function of IQueryable. When you call ToListAsync the query is actually performed to the DB. Change your code to return the db.AddressDataMax
hi @Max ok, how would I pass the parameters into the repo queryable anyway? feel free to write full answer, and I can send points, thanksuser13817218

1 Answers

-1
votes

It's been ages since I wrote this function, but the links might help. GetAll() just returns an IEnumerable.

    [Route(""), HttpGet]
    public IHttpActionResult Get(ODataQueryOptions<Language> queryOptions)
    {
        Log.Info($"{nameof(Get)} (ODataQueryOptions)");

        //OData directly with normal WebAPI
        //https://blogs.msdn.microsoft.com/webdev/2013/02/25/translating-odata-queries-to-hql/
        //https://stackguides.com/questions/10781309/asp-net-mvc-4-webapi-manually-handle-odata-queries
        //https://blogs.msdn.microsoft.com/odatateam/2014/07/04/tutorial-sample-using-odatauriparser-for-odata-v4/

        //OData without entity framework, but full-on odata controller
        //http://www.odata.org/blog/how-to-use-web-api-odata-to-build-an-odata-v4-service-without-entity-framework/

        //OData tips and tricks
        //https://blogs.msdn.microsoft.com/davidhardin/2014/12/17/web-api-odata-v4-lessons-learned/

        return Ok(queryOptions.ApplyTo(_repository.GetAll().AsQueryable()));
    }