Question

I'm creating an .NET Core 3 API with Entity Framework. The data is from an existing database.

Now I've the following situation:

/persons -- get all the persons
/companies -- get all the companies
/attributes -- get all the attributes
/attributes/groups -- get all the attribute groups
/attributes/types -- get all the attribute types
/attributes/usage - get all the attribute usages
  • Attributes can be in one or multiple groups.
  • Attributes can have one type: person or company.
  • Attributes are assigned to a person or company, listed in the usage end-point.

We have in the 'usage' end-point something like:

fk_attribute_id = 1
identifier_attribute = 3
type_id = "person"

So, this means person 3 has attribute 1.

Another example:

fk_attribute_id = 2
identifier_attribute = 2
type_id = "company"

This means company 2 has attribute 2.

In my API I have multiple controllers / services to get this data based on EF. The client could combine the data to get the desired result.

Now I think it's nice to be able to have these end-points:

/persons/3/attributes -- Get the attributes of person 3
/companies/2/attributes -- Get the attributes of company 2

But... that means I have to call my own end-points somehow and combine the data? I can also call the DB and use a stored procedure for this, althrough we do want to avoid have business logic in multiple places.

What would be the best-practise for this? Should we say: the API doesn't provide this, good luck client. Or... are there other options to provide this?

Was it helpful?

Solution

But... that means I have to call my own end-points somehow and combine the data? I can also call the DB and use a stored procedure for this, althrough we do want to avoid have business logic in multiple places.

This is a decision you have to make. Either you reuse your existing queries, or you create a merged query.

  • Reusing queries will have lower performance (due to the aggregation mapping), but it cuts down on the amount of queries you have to develop and maintain.
  • Creating new queries will improve performance (as you can rely on optimized database joins) but it will increase the amount of queries you have to develop and maintain.

While one additional query doesn't sound like much, keep in mind that this problem can quickly grow to proportions that are hard to maintain. If you have a significant amount of entities and need queries for many different entity combinations (or different filtering logic), the amount of extra queries is going to be quite large.

Which option is the best for you is not a decision anyone but you(r company) can make. Which bottleneck do you want to avoid the most, runtime performance or development/maintenance effort?


In either case, I would advise against stored procedures. Not that they don't work, but they fraction your business logic and divide it over the codebase and the database, which is something you don't want. It's generally better to keep your queries (whether SQL or code-to-SQL) together in your DAL. The performance hit is not as big as the impact on readability and maintainability of the codebase.

That being said, if all existing queries are already stored procs, then this advice doesn't apply of course.

OTHER TIPS

To prevent using Stored Procedures so the business logic doesn't split, we can use LinQ. The build-in from Entity Framework can not handle this specific situations.

You do not want to call your own API to get the data and combine them. LinQ can help here.

Part of the code:

IQueryable<Models.Attribute> queryResult = (from p in context.tbl_person
                                            join ia in context.tbl_n_n_identifier_attribute on p.id equals ia.identifier_value
                                            join a in context.tbl_attribute on ia.attributeID equals a.attributeId
                                            join at in context.tbl_attribute_type on a.attributeTypeId equals at.attributeTypeId
                                            where p.id == id
                                            where at.attribute_type == "person"
                                            select new Models.Attribute
                                            {
                                               PK_attribute_id = a.PK_attribute_id,
                                               FK_attribute_type_id = a.FK_attribute_type_id,
                                               attribute_naam = a.attribute_naam
                                           })
                                           .OrderBy(x => x.attribute_naam);

listAttributesForPerson = queryResult.ToList();
Licensed under: CC-BY-SA with attribution
scroll top