views:

206

answers:

4

Each business object has a matching object that contains sql calls. I'd like to restrict these sql objects in a way where they can only be used by the matching business object. How can this be achieved?

Update

Greg brought up the point about testability. Since the SqlObjects will contain very business-process specific sql I don't want them reused in multiple buiness objects. (Basic CRUD operations are all code-generated) Is there a way to make the SqlObjects accessible to only one business object in the business assembly (like yshuditelu and Greg Beech showed) AND expose the SqlObjects to the unit testing assembly?

+9  A: 

If this is the approach you want or need to take, you could make the sql objects private classes within the business object.

public class BusinessObject
{
    private class SqlObject { }
}

Additionally, by making use of partial classes, you could separate this into separate files if desired.

//in one file
public partial class BusinessObject
{
    //business object implementation
}

//in another file
public partial class BusinessObject
{
    private class SqlObject { }
}

Joel makes a good point in a comment below "the SqlObject can still inherit from a common type, to that things like connection information can be shared across those "inner" classes." this is absolutely true, and potentially very beneficial.

In response to your edit, unit tests can only test public classes and functions (without using reflection in your tests). The only option I can think of that would do this is:

  • make one assembly per business/sql object pair
  • changing the private class SqlObject to internal class SqlObject
  • then use the [InternalsVisibleTo("UnitTestsAssembly")] for the project

Also, at this point you wouldn't have to keep the sql object as a nested class. Generally speaking, I think this would likely add more complexity than the value it adds, but I completely understand that every situation is different, and if your requirements/expectations are driving you this, I wish you well. Personally, I think I would go with making the SqlObjects public (or internal with internals visible to for unit testing), and accept the fact that that means the sql classes are exposed to all of the business classes.

Timothy Carter
Also: the SqlObject can still inherit from a common type, to that things like connection information can be shared across those "inner" classes.
Joel Coehoorn
Thanks. I'm already using partial classes for code generation. I'm separating the sql for Dependency Injection. Your approach will require very little change to my templates!
adam0101
+4  A: 

The only way to do it is make the SQL object a private nested type, i.e.

public class BusinessObject
{
    private class SqlObject
    {
    }
}

Whether this is a good idea from the point of view of testability is another matter entirely...

Greg Beech
That's a good point about testability. Is there a way to do this AND expose the SqlObject class to the unit testing assembly, but not to the other business objects?
adam0101
A: 

You are attmepting to implement what is a Friend Class in C++. As far as I know C# and VB.Net do not have anything equivalent. My only suggestion is to make the class you wish to restrict an internal class of the class that needs to access it.

ChrisLoris
A: 

You could also work with two assemblies (one for business objects and one for the related SQL objects) and use the internal modifier on each SQL class and use then [InternalsVisibleTo("BusinessObjectAssembly")] for the SQLAssembly.

weismat