3

This question is related to How should an `Employee` class be designed?

In the above question, to uniquely identify an employee, each Employee object has an id field as shown below

class Employee
{
    private int id // id is given by the database
    // Employee data (let's say, dozens of properties).


    //methods.....

}

The id of an employee object is given by the database.

So if I use the object for describing a new employee, there will be no id to store yet. But an object representing an existing employee will have an id. So I have a property that sometimes describes the object and sometimes doesn't.

Also, id = null makes the Employee object's state invalid but

[A] properly encapsulated object cannot be brought into an invalid state via the public interface [...]

https://softwareengineering.stackexchange.com/a/258281/234665

Does this design violate encapsulation because id = null at the start?

  • Why does id = null make the state invalid? The linked question does not say that and the accepted answer seems to imply that it should be considered valid. – Stop harming Monica Apr 4 at 21:13
  • softwareengineering.stackexchange.com/questions/258275/… [That means a properly encapsulated object cannot be brought into an invalid state via the public interface, or conversely] – Susantha7 Apr 5 at 9:34
  • Where does it say that id = null makes the state invalid? Anyway the answer to your question is obviously yes, what you describe are not properly encapsulated objects. But you already know that don't you? – Stop harming Monica Apr 5 at 9:54
  • are you telling when id = null state is in valid – Susantha7 Apr 5 at 18:11
  • 1
    No, it is your design, it is not for me to say what states are invalid. – Stop harming Monica Apr 5 at 21:21
0

The simplest method is to just ignore your perceived problem. Items that are in the database have an id, provided by the database. Items not in the database have no id. Both are valid states. “Insert” is not a valid operation if the item has an I’d that is not null. And “update” is an invalid operation if the item is not in the database.

You can decide whether id should be immutable - in that case adding an item to the database leads to the creation of a new item with the id changed.

5

Identify your single source of truth. That's what has the authority.

If your program is the authority on what can and can't happen with an employee then the DB is nothing but a way to persist employee info. The DB id is of no consequence. The object model will have it's own way of identifying and relating entities.

If the DB is the authority on what can and can't happen with an employee then an employee object with no id is simply a pending request to create an employee. An employee object with an id is a stale report of the state of the employee. At no time is the employee object ever the single source of truth about the state of the employee. Anything you wish to change must be checked against the DB.

3

so if I use the object for describing a new employee, there will be no id to store yet

Then they aren't an employee; they are an applicant. So don't use the Employee type for them. The reason why you are struggling with how to represent this scenario is because you are using the wrong type.

  • 2
    That’s nonsense. They are an employee that hasn’t been added to the database yet. – gnasher729 Apr 7 at 10:07
2

One way is to ensure that new entities do have a valid identifier, before even being saved to a database. This is exactly the benefit of UUID type; you don't need to query the database in order to get a new identifier. Instead, you just create a new UUID, and you know that it is unique, i.e. there are no other entities in the database with the same identifier.

Another way is to avoid creating an instance of the Employee class if you haven't created one yet. In other words, when a user of the application creates an employee, the first step consists of INSERTing a row in the database, and getting back a valid identifier (and other default values, if any). Only then you'll initialize (from the information you just got from the database) an instance of the Employee class.

This second approach has naturally one drawback: you may end up with a lot of unused entities—things that users created inadvertently by opening a form, even if they didn't want to create ones. One way to mitigate this problem is to ensure that the user interface is very clear on the fact that an entity would be created if the user clicks on a button, opens a page, etc. Displaying the list of already created entities should give an immediate feedback. Another approach is to mark an entity as empty if the user haven't saved anything in it. Empty entities could then be deleted on regular basis, such as every night.

A third way, finally, is to have a base class which represents an employee without an identifier. This would, however, make the code more complex than it needs to be, so use this approach only when it brings clear benefits.

0

I don't know what the answer to your title question is.

But the reality is that all theoretical ideas will be broken when applied to real-world scenarios. And software design is thus job of compromises. Will you break the ideal scenario of "object should always be in correct state" and allow an employee to exist without an Id before it is inserted into database? Or will you create some system that allows you to give Employee an Id on creation? Options are many. Use GUID. Or pre-insert an empty row to get the Id. Or use Hi\Lo algorithm.

In the end, it is up to you, your (hopefully extensive) experience and your specific requirements what option is best.

0

properly encapsulated object cannot be brought into an invalid state via the public interface...

As mention there, properly encapsulation is the key. Where is your encapsulation for Id ? I really don't get what is for private int Id without encapsulating it.

You can encapsulate it like:

class Employee
{
    private int Id;

    public int ID
    {
        get => Id;
        set
        {
            if (value > 0)
            {
                Id = value;
            }
        }
    }

    // other properties and methods.
}

What's wrong with this Employee class and what makes your Id invalid? This Id can be invalid if you not design your code properly and try to preform CRUD operation when it hasn't valid value.

To achieve this you can determine which method you should run by checking Id. If it is equal to 0 then insert it. If not, then update it. Entity Framework AddorUpdate(TEntity model) extension method is good example for this.

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.