0

I have used IdentityDbContext in my project. My database has some tables which are connected to each other (relational). I want to use Repository pattern. I declared all my Interfaces. Then, I tried to Implement them. The problem is that I cannot create an instance of IdentityAppContext, because the constructor needs an input parameter 'option'. How can I implement them?

IdentityAppContext.cs :

public class IdentityAppContext: IdentityDbContext<AppUser, AppRole, int>
{
    public IdentityAppContext(DbContextOptions<IdentityAppContext> options) : base(options)
    {

    }
    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    }
    public DbSet<AppUser> Users { get; set; }
    public DbSet<Message> Messages { get; set; }
    public DbSet<PM> PMs { get; set; }
    public DbSet<Notification> Notifications { get; set; }
    public DbSet<FileRepository> Files { get; set; }
}

IPmRepository.cs :

public interface IPmRepository
{
    IEnumerable<PM> GetAllPMs();
    PM GetPmById(int pmId);
    bool InsertPM(PM pm);
    bool UpdatePM(PM pm);
    bool DeletePM(int pmId);
    bool DeletePM(PM pm);
    void Save();
}

PmRepository.cs :

public class PmRepository : IPmRepository
{
    IdentityAppContext db = new IdentityAppContext();
    public IEnumerable<PM> GetAllPMs()
    {
        
    }
    public PM GetPmById(int pmId)
    {
        throw new NotImplementedException();
    }
    public bool InsertPM(PM pm)
    {
        throw new NotImplementedException();
    }
    public bool UpdatePM(PM pm)
    {
        throw new NotImplementedException();
    }
    public bool DeletePM(int pmId)
    {
        throw new NotImplementedException();
    }

    public bool DeletePM(PM pm)
    {
        throw new NotImplementedException();
    }
    public void Save()
    {
        throw new NotImplementedException();
    }
}
8
  • 3
    Why do you assume you need to use the repository pattern? A DbSet is already a single-entity repository. A DbContext is already a multi-entity Unit-of-Work. That GetAllPMs method is seldom useful - there's seldom any reason to load all rows in a table unless you want to fill a lookup table. Using a low-level "repository" interface over a high level abstraction like an ORM is actually an antipattern Commented Dec 3, 2021 at 16:45
  • In agreement with @PanagiotisKanavos, avoid the antipattern. This will help you setup when dealing with IdentityDbContext: stackoverflow.com/questions/50377705/…, Possible duplicate: stackoverflow.com/questions/23226140/… Commented Dec 3, 2021 at 17:20
  • If you want to use DDD, be aware that DDD uses a Repository for the aggregate root - that's the root of the object graph you need to load to handle a specific use case (bounded context in DDD terms). NOT individual entities. In that case, Yes, a specialized Repository makes sense. At that level there's definitely no need for classes with CRUD methods, no need to load all objects in a table. Commented Dec 3, 2021 at 17:35
  • 1
    As for why you can't use IdentityDbContext with new, it's because it's meant to be used with dependency injection. Your classes that use that DbContext need to work the same way - instead of trying to manually create their dependencies, accept them as constructor parameters. That makes it easy to change the underlying storage from SQL Server to MySQL to Oracle to NoSQL databases just by changing the options registered in AddDbContext, or passed to the constructor. This allows easy unit testing - you can use the in-memory provider without modifying your DbContext or any code that uses it Commented Dec 3, 2021 at 17:38
  • Assuming you really ned a PmRepository, it needs a constructor that accepts an IdentityAppContext parameter. Commented Dec 3, 2021 at 17:41

1 Answer 1

0

Presuming that the DbContext is registered with a DI Container in your Startup.cs file, using something like:

services.AddDbContext<IdentityAppContext>(opt => 
{
   opts.UseSqlServer(myConnectionString);
})

then adding the following in the same method as the above will register your repository in the same DI Container:

services.AddScoped<IPmRepository, PmRepository>();

Then in your repository:

public class PmRepository : IPmRepository
{
    readonly IdentityAppContext _context;
 
    // 'context' parameter is automagically provided by the container.
    public PmRepository(IdentityAppContect context)
    {
        _context = context;
    }

    public bool InsertPM(PM pm)
    {
        _context.PMs.Add(pm);
    }
}

Then, in your controller (which is also provided by the container), you should be able to request from the container an IPmRepository in the constructor:

public class MyController : Controller
{
    readonly IdentityAppContext _context;
    readonly IPmRepository _pmRepository;

    // Both 'context' and 'pmRepository' are automagically provided by the container
    public MyController(
        IdentityAppContext context,
        IPmRepository pmRepository)
    {
        _context = context;
        _pmRepository = pmRepository;
    }

    [HttpPost]
    public async Task DoSomething(MyRequest request)
    {
        _pmRepository.InsertPM(new PM() { Id = request.Id });

        await _context.SaveChangesAsync();
    }
}

Note that because IdentityAppContext and IPmRepository are registered in the same container as MyController, then the framework can automatically provide the parameters for the MyController constructor.

Further, when the PmRepository is being created for the Controller the container can look at the constructor parameters of PmRepository and see that it wants an IdentityAppContext, which can be provided automatically because its registered in the same container.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.