0

I've written a group of classes that access the database to map DB data to objects. Other programmers will be manipulating the objects, and so I'm trying to make it as difficult as possible for them to do anything that would break any contracts. One of the things that would help is to make the id (primary key) read-only. However, at some point or another, an id will need to be assigned to the object.

In Java, I'd simply group all of the DB access classes into a package, and declare a couple of methods in my abstract class

public int getId() { return id; }
default void setId(int id) { this.id = id; }

so that only members of the same package could set the id. I'm having trouble coming up with a good design in C#, though. Currently, the constructor to DB objects takes an int? that should be set to null before an object has persisted to the DB. If id is not set to null when instantiated outside of the DB-access classes, some contracts might be broken. I'd make a second constructor that doesn't take an argument for the id for access outside of the DB-access classes, but I'm running into the same problem with restricting access appropriately: if the constructor is accessible to classes in the same namespace / partial class, it's accessible to the assembly.

Does anyone have any good design strategies for handling a situation like this with C#?

Joseph Nields
  • 5,527
  • 2
  • 32
  • 48
  • if you would be happy with them being in a seperate package what is wrong with the internal access modifier on the methods and a seperate assembly? – tolanj Feb 19 '15 at 15:29
  • 1
    If you use Entity Framework I know that it can invoke a private setter. So something like `public int ID { get; private set; }` won't get in its way. You could still manually set it with `typeof(SomeType).GetProperty("ID").SetValue()` if you're not using EF (which is probably what EF does internally anyway), though any developer could also do that as well :) – David Feb 19 '15 at 15:30
  • @tolanj if I use "internal" they'll still be accessible by classes I don't want using it because the classes will be in the same assembly as those that are accessing it... Is the equiv. in C# just compiling this into a .dll? – Joseph Nields Feb 19 '15 at 15:34
  • @David I wish we'd just use EF, but legacy code prevents a lot of things from happening that might be better! – Joseph Nields Feb 19 '15 at 15:43
  • @joseph-nields yes you can just put these data types into a dll with the db specific code, I'm largely just saying that's the equivalent solution. – tolanj Feb 19 '15 at 15:53
  • 2
    @David's suggestion would do the job - make the setter private and then in your DB access layer, you could his reflection trick to write the value. It's a bit "smelly" because you're subverting the data encapsulation but you'll only be doing this in your "low level" database (retrieval) i.e. where you know the value. For anyone consuming these classes, Id will be read-only. Developers could use the same reflection trick to access it but presumably, you're trying to deter casual or "accidental" writing of the value. – Rory Solley Feb 19 '15 at 15:53
  • 1
    Also consider this, which is in some ways analagous http://stackoverflow.com/questions/27983732/access-a-method-only-if-calling-class-implements-specific-interface/27984205#27984205 my answer there is relevant, ie you can't 'set' the id at all outside the dataclass, but can call 'WriteToDb' IF you provide an IDBConnection and it is this that updates the id (as this is presumably the ONLY time the id can change), just a possible approach. – tolanj Feb 19 '15 at 16:01

0 Answers0