Query with OData without viewing ORM models?

In my web api 2 project, if I want to use the OData library (which looks amazing and very tempting) for queries on some properties, this would make the client side know the exact properties of my database models. Is this a good practice? Is there any way to avoid this denouement?

For the following models:

public class LetterEntity { public int Id {get; set;} public string Title {get; set;} public string Content {get; set;} public string Source {get; set;} public DateTime SendingTime {get; set;} public string AnotherWierdString {get; set; ... } public class LetterDTO { public int Id {get; set;} public string Title {get; set;} public string LetterContent {get; set;} public string Source {get; set;} public DateTime SendingTime {get; set;} } public class LetterInsideFolderDTO { public string Title {get; set;} public string Source {get; set;} } public class LettersController : ApiController { // In this approach method, I hate the fact that a LetterEntity must be used for the query. [HttpGet] [Route("api/letters")] [EnableQuery] public IQueryable<LetterInsideFolderDTO> Get(ODataQueryOptions<LetterEntity> query) { IQueryable<Letter> letters = db.Letters; var afterQuery = query.ApplyTo(letters) IQueryable<LetterInsideFolderDTO> dtos = afterQuery.ProjectTo<LetterInsideFolderDTO>(afterQuery) return dtos; } // Is there a way to do something like the following?: [HttpGet] [Route("api/letters")] [EnableQuery] public IQueryable<LetterInsideFolderDTO> Get(ODataQueryOptions<LetterDTO> query) { IQueryable<Letter> letters = db.Letters; // Convert the query to work on the entities somehow? Should I use a mapping between LetterDTO to LetterEntity? // I only have a map from LetterEntity to LetterDTO var afterQuery = query.ApplyTo(letters) IQueryable<LetterInsideFolderDTO> dtos = afterQuery.ProjectTo<LetterInsideFolderDTO>(afterQuery) return dtos; } } 

Due to the fact that at the moment I take the Entity model directly in the client request, there is a strong connection between the clients and the server. For example, if I want to query and get all the letters that have "abc" inside the Content field, I need to go to the following:

 api/letters/?$filter=contains(Content,'abc') 

If tomorrow I decide to change this property from "Content" to "LetterContent", all client codes will be violated.

How can I surpass him?

Thanks!

EDIT:

Please give me a specific example, I don’t understand what HATEOAS is (if this helps me solve this problem), How can the documentation service help me? Does it still force customers to change their code if I want to change my EDM models?

+5
source share
2 answers

if I want to use the OData library (which looks amazing and very tempting) for queries on some properties, which will make the client side know the exact properties of my database models. Is this a good practice?

It depends on what you mean by "make the client side know the exact properties." There are two ways:

  • Use auto-generated proxies created by datasvcutil. Indeed, this would make the client side know the exact properties, as they are hard-coded on the client side. When the server side is changed, the client will be broken - the client / server is closely connected. In general, this is bad, but usually if you need to do something quickly - datasvcutil is your tool.

  • Get to know your client to read a service document so that he can dynamically decide what resources he can request. You have everything for him - a service document, metadata.

Remember that OData is built on the REST architecture, which has a number of advantages that are achieved through a set of constraints. Some of the limitations are targeting and HATEOAS.

Addressing means that each resource must have its own address.

HATEOAS means that at any moment the client based on hypermedia in the presentation of the current resource must have all the information he needs to decide where to go next.

To find out where to go, the client must

  • Know how to find resources (URLs) in the data stream where it can go. How do you get data with text and a URL - the client must know how to find the URLs. URLs can have different meanings β€” for example, multiple URLs for CRUD operations.

  • Get this data using resources. In general, the client needs to know how to start a service request.

The first point is allowed through profiles. Profile - allows customers to learn about additional semantics associated with the presentation of resources ( https://tools.ietf.org/html/rfc6906 ). View the OData documentation. In the case of OData, your client should know that the data in OData is in Atom or Json formats. The client must know the principles of building requests to the OData service, obtaining a specific record, etc.

If the client calls the root address of OData - smth like ... OData.svc, he will receive a list of all the resources that he can request (service document). This is how the second point resolves.

You can go ahead and get metadata through $ metadata suffix. This will give you all the properties of the resources.

0
source

I really believe that exposing your entities directly is bad practice in most cases. I would recommend DTO in almost every case. This allows you to grow your database and business logic without breaking the API. OData has some use cases, such as open data initiatives, in which the government publishes data as is.

I had to create an application that essentially came down to data with all filtering and sorting options. I wanted to use OData, but I did not find a way to make queries on objects, but the project is for DTO, so I created my own library for converting jqgrid filters to IQueryable queries - https://github.com/KodarLtd/WebApiJQGridFilters Please note that I do not recommend using this code, since it is not a fully functional library and is not documented at all. I just provide this as evidence of how confident I am that the DTO approach.

I would like to be proved wrong, so I can use OData, but return a DTO for my next project.

0
source

All Articles