1

I fear I'm asking a somewhat silly question, but I'm now completely lost as to which principle I should follow.

To my understanding - in terms of Single Responsibility Principle it's best we don't tweak OR inject services into OR introduce extra fields in DB Context.

Simply because the purpose of DB Context is to provide database access.

The single responsibility principle is a computer programming principle that states that every module or class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class. All its services should be narrowly aligned with that responsibility. Robert C. Martin expresses the principle as, "A class should have only one reason to change."

The reason why I'm posting this - I'm trying to refactor Service Layer code and would like to make my app set some fields automatically (e.g. CreatorUserId, ModifierUserId, DeleterUserId) rather than manually set all of them each time - fore more info check this.

If you look at the answer the person says

UserId and TenantId here are just pieces of data that your repository service (here a DbContext) needs. If a service needs data, it should be injected into the service.

also one of the comments

Giving your DbContext open access to the session state or the Http context is clearly wrong. But having your DbContext depend on a small number of fixed parameters is fine. Both the UserId and the TenantId might be necessary to connect to the correct database using the correct identity and record audit data. All well within the single responsibility of the repository.

But I also received different feedback from another person under this post.

Here's the answer

You should really think about whether your database context having a dependency on your tenant provider is the right thing to do. As per SRP, your database should only do a single thing and that is provide database access.

Depending on how your tenant provider affects your database access, it might make more sense to move this dependency up one level into some service that uses both the database context and the tenant provider to query data in the right way.


The opinions seem to differ. Does anyone have any recommendations?

  • why is it harder to set them in the service layer than (potentially) the db context? – Ewan Sep 2 '18 at 7:15
  • @Ewan this way we end up doing routine things, having duplicated code in various service methods - I'm afraid it harms DRY principle. – Alex Herman Sep 2 '18 at 12:30
1

What you are attempting to do, inherit DBContext and add extra logging functionality with overridden methods is architecturally fine, but unusual and potentially over complex, simply because its DBContext rather than one of your own classes.

I would not advise anyone to try to implement their own DBContext simply because you would need a deep understanding of how the class functions to be able to correctly add your own logic.

Trivially for example, you might override SaveChangesAsync(), but not SaveChanges()

It would be far more simple to wrap the DBContext calls in a Repository layer for example and put your audit functionality in there.

I think this is why you are receiving different advice. If you are confident in your understanding of DBContext then go ahead and sub class it, injecting your UserContext and call it DBContextWithUserAuditing

If you don't want to have to understand the workings of DBContext then inject a standard one, along with a UserContext into a RepositoryWithUserAuditing

  • overriding SaveChanges seems to be the most optimal and cleanest solution - plus we only introduce 2 fields UserID & TenantID in DbContext which doesn't result in violation of SRP in my judgement. naming it as DBContextWithUserAuditing makes A LOT MORE sense! will go with that, thank you very much for your answer! :) – Alex Herman Sep 2 '18 at 12:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.