Problems with Using Static Classes for Database Access in C#

cdependency-injectionentity-frameworkstatic methods

Many place that i have read about static method they said please shouldn't use static method for access to database and should use dependency injection for inject other service and use that service to write other logic.But problem it
happen when i inject AService in BService and inject AService in CService many month pass business logic is grow it make i need to inject BService in CService ,It make problem cause AService it already inject in two place can't do it. I try something like this for fix that solution.

 public class InterlocutorFacade : GenericEFRepository<MsSql1DbContext, GenericUser>, IInterlocutorFacade
 {
    public InterlocutorFacade(MsSql1DbContext _msGenericDb) : base(_msGenericDb)
    {

    }

    public async Task AddC()
    {
        await UserService.CreateLogs(_msGenericDb.Set<Logs>());
        await _msGenericDb.SaveChangesAsync();
    }


    public async Task GetC()
    {
        var result = await UserService.GetFirstLogs(_msGenericDb.Set<Logs>());
    }
 }

and this is service is i use

public static class UserService
{ 
    internal static async Task<Logs> GetFirstLogs(DbSet<Logs> dbSet)
    {
        var result = await dbSet.FirstOrDefaultAsync();
        return result;
    }

    internal static async Task CreateLogs(DbSet<Logs> dbSet)
    {
        var result = await dbSet.AddAsync(new Logs() { });
    }

}

But i not sure what problem will happen if i do it, have someone can show me a problem (etc performance , data conflict ) it will happen when i use this?

Best Answer

The problem with using a static over injecting a dependency is that you are unable to switch out the implementation. This is mainly done in your unit tests

eg

public class Service
{
    public Service() {}
    public AddData(Data data)
    {
        MyStaticDBClass.Add(data);
    }
}

In the application this works fine, but in the unit test it will actual write to the database. Which you don't want it to do.

Compared to:

public class Service
{
    private readonly IDataLayer dl;
    public Service(IDataLayer dl) { this.dl = dl;}
    public AddData(Data data)
    {
        dl.Add(data);
    }
}

Now In the application I can pass in the real data layer object and in my test I pass in a mocked version.

You second problem. The cyclic dependency is basically saying that you can't compile dll A because it depends on dll B and you can't compile dll B because it depends on A.

In order to resolve it you will want to separate the interfaces from the implementations. Put them in different projects ie.

IAService //no references
    IAService.cs //interface for AService

IBService //no references
    IBService.cs //interface for BService

AService // references IAService and IBService
    Aservice.cs //implementation of IAService


BService // references IAService and IBService
    BService.cs //implementation of IBService

Now I can compile the IAService project first as the IBService reference is only in the actual implementation project