3

I'm trying to decide what's the best approach to instantiate a particular class. Basically there are two use cases for it: instantiate it in order to save a new entry to the database and fetch an existing entry from the database (and maybe edit the fetched entry and save it back to the database).

The issue I'm having right now is that I can't decide which mechanism for instantiating that class and populating its fields to choose. Say I have this class

public class Student
{
 public int Id { get; set; }
 public string FirstName { get; set; }
 public string LastName { get; set; }
 public Address Address { get; set; }
}

And here are the usecases. If you want to fetch a student for the database, the code looks something like:

Student student = MyLibrary.GetStudent(id);

And if you want to create a new student and add it to the database:

Student student = new Student();
student.FirstName = "James";
student.LastName = "Jackson";
// etc
MyLibrary.CreateStudent(student);

The massive issue with this approach is that all the setters are public and I absolutely do not want this. But at the same time I want the user to be able to populate most of the Student fields freely (maybe with the exception of Id.

I'm thinking the builder pattern could be employed in here. This way I can keep the setters private and force the user to create read-only students via the builders. However it then becomes really awkward if the user wants to update a field and save it to the database:

var student = MyLibrary.GetStudent(id);
var newStudent = new Student.Builder(id).FirstName("NewFirstName").LastName(student.LastName)...etc...Build();
MyLibrary.CreateStudent(newStudent);

Basically my only issue with the builder approach is that the code can get quite awkward and tedious if you want to update an existing entry. Some of the classes I have can have around 10 fields and it's not great having to copy 9 of the fields and update one. But it may be much nicer than having a class with public setters.

What other options do I have?

asked Jul 13, 2015 at 17:04
3
  • 2
    Can you clarify why you want your setters to be private? Commented Jul 13, 2015 at 17:31
  • 2
    Is there some reason you aren't just using constructor overloads or default parameters? Default parameters aren't usually a good idea, but they'd certainly give you what you seem to be looking for... Commented Jul 14, 2015 at 14:46
  • @Magus Because in most cases my models have around 10 fields. Telescoping constructors are not great in this scenario... Commented Jul 14, 2015 at 17:24

4 Answers 4

1

What you need is CQRS(Command Query Responsibility Segregation)

The idea is that what you save and what you load back and edit later is not the same object. This way you have control over what fields are private and what are public. What can be updated, and what can't.

In CQRS you have Command Model and Query Model. Command model is responsible for CREATE/UPDATE functionality, query model is responsible for fetching the data.

answered Jul 13, 2015 at 17:29
7
  • 1
    Thanks. Can you elaborate how that is appropriate though? Commented Jul 13, 2015 at 17:51
  • And I don't see the need to separate the command & query models in my case. They are basically identical. Commented Jul 13, 2015 at 17:52
  • You said you want user to be able to freely assign the fields. That's your command model. You also want to protect the fields when entity is already in the database - that's your query model. So they are definitely not identical, and that's how CQRS applies :) Commented Jul 13, 2015 at 17:55
  • I see what you mean now. So if I want to update an existing Student, I have to fetch a StudentQueryModel first, copy all its fields into a StudentCommandModel and then save the StudentCommandModel back to the database. I don't think it brings any benefits over the builder approach mentioned in my question. In fact it adds more complexity. Or maybe I'm missing something. Commented Jul 13, 2015 at 17:59
  • I don't see how builder patterns solves your issue? All I see it makes code look way more complicated and adds an extra pass-through layer. You might want to read Martin Fowler's article that I linked in my answer. Commented Jul 13, 2015 at 18:04
0

I think a nonpublic set for "user editable" properties is just making work for yourself.

I'd leave them public (for changeable properties, i.e. not Id) and then either use the DAO-style .Edit and .Update state change methods (where attempting to change before calling .Edit throws a runtime error), or simply always allow changes and supply .CommitChanges to store them, similar to .NET DataContext.

This also allows something like:

LoadStudent(s);
s.Name="Harry";
if(UserConfirmsChanges(s))
 s.CommitChanges();

where the important bit I'm referring to is UserConfirmsChanges which can work with modified, but not saved, data simply.

If you really want something similar to the DAO way, but with compile-time read only properties before .Edit, you'll have to have different classes or otherwise duplicate code.

answered Aug 21, 2015 at 15:36
0

If you want to keep the setter private then you have to use construction arguments to set the properties.

ie

public class Student
{
 public Student(string firstName, string lastName....

Even if you use an additional builder class it will still need to do this underneath. I wouldn't bother with one, unless you are publishing the class or need to enforce some complicated setup logic.

When you come to update an existing object, in the OOP world you would expect to be calling a method on your object which would modify the private properties in accordance with some business logic, rather than simply setting a data value.

ie

myStudent.MoveIntoAccomadation(myCollege);

rather than

myStudent.Address = myCollege.Address;

if you are just doing the latter then it suggests that you object is really just a data struct. There's nothing wrong with this, you could be apssing it to services as DTO, or just moving it around databases etc

answered Sep 20, 2015 at 16:00
0

As far as I can see, your Student is a composite struct of related fields.

From my preliminary experience with these, I highly recommend trying to make these fully immutable, which is also what you seem to have in mind(?)

As for your concern wrt. Builder Pattern:

Some of the classes I have can have around 10 fields and it's not great having to copy 9 of the fields and update one.

You have to give your builder a ctor that takes a Student, then the Builder can copy an existing Student and you can change only the update fields.

answered Nov 19, 2015 at 19:41

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.