0

For a ASP.NET Core application, I'm using a library which performs calculations using objects that have a similar interface but their constructors use different inputs. The inputs are market prices and volatilities.

public class Base 
{
    public virtual double Method1();
    public virtual double Method2();
}

public class BaseOne : Base 
{
    public override double Method1();
    public override double Method2();
}

public class BaseTwo : Base 
{
    public override double Method1();
    public override double Method2();
}

public class ConcreteOneA : BaseOne
{
    public ConcreteOneA(double F, double V, double r, double K, ...);
    public override double Method1() { // code }
    public override double Method2() { // code }
}
public class ConcreteOneB : BaseOne
{
    public ConcreteOneA(double F, double V, double r, double K, ...);
    public override double Method1() { // code }
    public override double Method2() { // code }
}
public class ConcreteTwoA : BaseTwo
{
    public ConcreteOneA(double F1, double F2, double V, double r, double K, ...);
    public override double Method1() { // code }
    public override double Method2() { // code }
}

To create the ConcreteOne and ConcreteTwo classes, I have to fetch the F, F1, F2, and V inputs from a SQL Server database. I have a EF Core DbContext entity which is injected into a ASP.NET Core controller.

Every time, I want to perform calculations, my code was littered with DbContext queries and filters. Also I wanted to be able to use a single controller action to compute values for Method1 and Method2, since these methods are similar to all the Concrete classes, and it provided for a convenient API interface for the users. So I created a factory class:

public class BaseFactory
{
    private MyContext _context;
    public BaseFactory(MyDbContext context)
    {
        _context = context;
    }
    public Base FromCode(MyDbEntity obj)
    {
        // use the context object to fetch F and V, and also F1 and F2 if the obj type is 3 
       //...

        // compute the other inputs for the concrete constructors which can be obtained directly from the MyDbEntity obj
       // ...

        switch (obj.Code)
        {
            case "1":
            case "4":
                return new ConcreteOneA(F, V, ....rest of the parameters computed from obj...
            case "5":
                return new ConcreteOneB(F,V, ....rest of the parameters computed from obj...);
            case "3":
                return new ConcreteTwoA(F1, F2, V, ......rest computed from obj.....);
        }
    }
}

Is this the right approach? The F is the price and V is the volatility which might need to come from a different data source in the future, so I could need to create another factory method for that specific source. But is it a good idea to make the factory dependent on this DbContext? My controller passes the injected DbContext into the factory when the controller is created:

[ApiController]
public class MyController
{
    public MyDbContext _context;
    private BaseFactory factory;
    public MyController(MyDbContext context)
    {
        _context = context;
        factory = new BaseFactory(_context);
    }
    [HttpGet('/route1')]
    public ActionResult<double> MyMethodCompute(string code, double m, double s, double p)
    {
        // use _context to get MyDbEntity obj...

        return factory.FromCode(obj).Method1();
    }
}
  • Looks sensible to me. Does this design allow to inject a "mock" db context object, for testing the factory or the controller without using a real database? – Doc Brown Sep 10 at 18:21
  • That's what I've been wondering too. If the controller didn't inject the DbContext into the factory, how can I get the ASP.NET DI Container to inject it for me? – Sagar Limaye Sep 10 at 18:30
  • Honestly, if you don't know what MyDbContext is and if it can be replaced by a mock, how shall we? In case it cannot be replaced, encapsulate it inside of some kind of repository class which abstracts the database away. – Doc Brown Sep 10 at 18:34
  • Yeah MyDbContext should be replaceable. I could just use the EF Core InMemory database provider for testing – Sagar Limaye Sep 10 at 18:38
  • I don't know if making the factory dependent on the context is a good idea though – Sagar Limaye Sep 10 at 18:39
0

Yes its a correct approach.

Essentially you are instantiating an object from a db where the object could be one of several child classes.

A factory is a common way of achieving this.

But is it a good idea to make the factory dependent on this DbContext

Yes. I would always abstract the database into a repository. However, repositories are supposed to return business objects, so in this case the repository and factory would be the same thing and of course a repository needs DB access.

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.