2

I've developed an application that reads a file, maps it and stores info on the database. For some columns we need the primary key of an object in the database, and if the record does not exist we need to create it, for that purpose we got a class called ReferenceSolver which is abstract and has many implementations that will check if the object exists and create it if necessary.

Since I want the operation to be atomic and create the main and object and the referenced objects in one transaction I'm using a class called TransactionBuilder to which I pass all the queries that I want to run. The problem I found is that I don't know how to pass the reference to TransactionBuilder every child of ReferenceSolver, I worked around it by using a Singleton but is raising plenty of red flags on my head.

The logic in the relevant method for ReferenceSolver like this in:

private string GetReferencedObjectKey(
        string referenceValue, 
        Dictionary<string, string> record
) {
    SQLConnector connector = new SQLConnector( LogImporter.ConnectionString );

    using (
        var reader = connector.ExecuteQuery(
            string.Format(
                "SELECT W6Key FROM {0} WHERE {1} = '{2}'", 
                TableName, 
                ReferenceField, 
                referenceValue
            )
        )
    ) {
        if ( reader.Read() ) { 
            return reader["W6Key"].ToString(); 
        } else {
            int key = KeyHelper.GetNextFreeKey(TableName);
            transactionBuilder.ExecuteQuery( GetInsertQuery() );

            return key.ToString();
        }
    }
}

Is there any way that I can pass the same instance of the object without using a singleton that I haven't thought of?? I also thought of raising an event to request the creation of the object but I'm not sure if this is a good solution either.

7
  • 1
    To me it seems the problem is solved trivially by having the base class ReferenceSolver a constructor parameter transactionBuilder which is required to be passed from outside and stored in some protected variable. All subclasses should have this parameter, too, and pass it to the base class constructor. But that seems to be too trivial, you would not have asked this question here, I guess, if it is would be just a matter of syntax, so please clarify where I did not understand you.
    – Doc Brown
    Jan 30, 2018 at 20:48
  • Please edit to clarify. "pass the reference to TransactionBuilder every child of ReferenceSolver" seems to indicate TransactionBuilder --> ReferenceSolverChild. Yet "logic in the relevant method for ReferenceSolver" seems to indicate TransactionBuilder <-- ReferenceSolverChild. Which is it? Which knows about the other? Please edit. Jan 30, 2018 at 22:19
  • @DocBrown, yeah, this is this is trivial solution, I'm aware of it but I don't love the idea of passing the reference in every child of ReferenceSolver.
    – Zalomon
    Jan 31, 2018 at 9:28
  • 1
    If ReferenceSolverChild is a ReferenceSolver then it's concerns include having a TransactionBuilder. If it isn't, don't use inheritance for this relationship
    – Caleth
    Jan 31, 2018 at 10:28
  • 1
    Part of having a base class is the requirement of constructing your base when you are constructed. If you don't want to do that, don't have a base class
    – Caleth
    Jan 31, 2018 at 10:34

1 Answer 1

5

If your class ReferenceSolver looks like this

abstract class ReferenceSolver
{
     private TransactionBuilder transactionBuilder;

     protected ReferenceSolver(TransactionBuilder tb)
     {
         transactionBuilder=tb;
     }
}

then make your child class look like

class ChildReferenceSolver : ReferenceSolver
{

     public ChildReferenceSolver(TransactionBuilder tb)
         :ReferenceSolver(tb)
     {
     }
}

So the code in those child classes cannot access the private transactionBuilder member. And it can't be easily forgotten, since the construction process for every child now requires to pass a TransactionBuilder object. Assumed this construction of those ChildReferenceSolvers is done in some factory class which has access to the initialized TransactionBuilder object (or actually does the construction), this whole construction will still be in one place.

3
  • That's the solution I wanted to avoid, since ReferenceSolver has many children but whatever, it is what I did but I hoped for a better solution that I haven't thought of. Thanks for you help, though.
    – Zalomon
    Feb 1, 2018 at 8:34
  • @Zalomon: why do you think "many children" is a reason against this kind of solution? This "many children" thing seems to bother you, you already wrote this in your question, but you did not give any reasons why you believe this makes it a problem.
    – Doc Brown
    Feb 1, 2018 at 18:28
  • Just a mix of laziness and legitimate curiosity, since they are all using the same TransactionBuilder I was hoping for a way to pass it to the base class and I couldn't think of one that made sense. I could use the singleton but did is a hack to me and negates the dependency injection.
    – Zalomon
    Feb 2, 2018 at 8:50

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.