One file vs. many partials
My first comment is about the
ProjectExtensions class itself. I would prefer keeping it together. If for any reason you want to make some consistent change in the extensions it's very hard to do that when they're scattered all over the place.
When to use extension methods
This is the main question: should I do this? My opinion: no. At least not to that extent.
When extension methods were unleashed in c# 3.0, the whole developer community (including me) went on a razzle with them and started creating extensions for just about anything. A bit like the days when text processors with more than one font entered the market. Suddenly we saw club bulletins appear that looked like (and violated) this:
The trouble is that with extension methods it's too easy to 'add' methods to a very general type while the scope of these methods is more restricted than the scope of the type itself, even within one namespace. For example, I had extension methods on
string that I decided to ditch again later, when wisdom finally took over.
This phenomenon also applies to your extension methods. They are defined on
IDbContext. Now I don't know how many
IDbContext classes you intend to implement, but who says they're all going to have
This means that you'd have to confine the extension methods to contexts knowing about
Project. This, in turn, may imply that you may as well replace the extension methods by instance methods in one specific context class.
When create a method at all?
That's another question. No matter if it's an extension method or an instance method. Is the task even worth creating a generally accessible method? I specifically frown upon this
GetProjectsFormatted method. To me, this looks like something that should probably be a service method. Remember the single responsibility principle? A context shouldn't have any knowledge about any format. That's a (domain) service's responsibility. It may make the context with all its paraphernalia less applicable (or targeted) to other parts of the application or other assemblies. Or, worse, you may get tempted to enter a range of
FomatXyz methods to meet other specifications.
Finally, there are other ways to deal with this 'soft delete' problem, i.e. the problem that records are deactivated rather than physically deleted, while the deactivated records shouldn't be displayed. Of course (and that justifies your [extension] method efforts) you don't want to add
where IsActive to each and every query.
But extension or instance methods supplying a pre-filtered set aren't enough either! Any old time you apply an
Include you'll be in trouble.
var projects = db.GetProjects.Include(p => p.Members);
Of course this includes all members, active or not. And (grief),
Includes can't be filtered.
Fortunately, there are better solutions for this. The most viable one, in my opinion, is EntityFramework.DynamicFilters, by which you can define filters that will be applied any time a type is queried, also in
A very technical, but more complete, solution is the one proposed by the EF team's product owner himself, the code and explanation of which is available here. More complete, because it also redirects deletes to setting a delete flag instead of physical deletes.
Another, pretty elegant, solution, also redirecting deletes, is here. But it uses inheritance, so it may not play nice with other inheritance schemes.