Typical Use Case
Functional
You have a collection of Patients. Before inserting a new Patient, you need to check if there already exists a past record of the same Patient. The Patient is considered already existing if there is a matching Government provided ID (for example SSN, Passport, etc.) Or a combination of First Name, Last Name, and DOB.
Note
The above functional requirement is not an absolute one in the real world. It is just for illustration purposes.
Let's say we have a very simple domain entity class of the Patient. For brevity purpose, I am not decorating the attributes of Required or null coalescing
- public class Patient
- {
- public long PatientID { get; set; }
- public string FirstName { get; set; }
- public string LastName { get; set; }
- public DateTime DOB { get; set; }
- public string GovtID { get; set; }
- }
Now to build our custom comparison for the duplicate check, we would make the <Patient> class inherit from the interface of IEquatable.
- public class Patient : IEquatable<Patient>
This will enforce to implement and override the Equals method. I have added another property for returning the related error message in case there is a duplicate record found. In order to enhance the "equal to" and "not equal to" operators, override them as well. Thus the class will now look like,
- public class Patient : IEquatable<Patient>
- {
- public long PatientID { get; set; }
- public string FirstName { get; set; }
- public string LastName { get; set; }
- public DateTime DOB { get; set; }
- public string GovtID { get; set; }
-
- public string DuplicateEntityFoundMessage { get; set; }
-
-
-
-
- public bool Equals(Patient other)
- {
- bool response = false;
- other.DuplicateEntityFoundMessage = string.Empty;
-
- if (other == null)
- response = false;
-
- if (this.GovtID == other.GovtID)
- {
- response = true;
- other.DuplicateEntityFoundMessage = "Patient already exists with the same GovtID";
- }
- else if (this.FirstName == other.FirstName && this.LastName == other.LastName && this.DOB == other.DOB)
- {
- response = true;
- other.DuplicateEntityFoundMessage = "Patient already exists with the same First Name, Last Name and DOB";
- }
-
- return response;
- }
-
-
- public static bool operator == (Patient person1, Patient person2)
- {
- if (((object)person1) == null || ((object)person2) == null)
- return Object.Equals(person1, person2);
-
- return person1.Equals(person2);
- }
-
- public static bool operator != (Patient person1, Patient person2)
- {
- if (((object)person1) == null || ((object)person2) == null)
- return !Object.Equals(person1, person2);
-
- return !(person1.Equals(person2));
- }
- }
Now to the client class. Here I have taken a simple Console program to illustrate the processing. Also, I am creating four subject patients to test the changes that we made in the Entity class.
-
- Patient patient1 = new Patient() { FirstName = "John",
- LastName = "Doe",
- GovtID = "ASDF12345",
- DOB = Convert.ToDateTime("12-Mar-1998")
- };
-
- Patient patient2 = new Patient() { FirstName = "David",
- LastName = "De",
- GovtID = "ASDF123458",
- DOB = Convert.ToDateTime("12-Mar-1998")
- };
-
- Patient patient3 = new Patient() { FirstName = "Sam",
- LastName = "Dickson",
- GovtID = "ASDF12345",
- DOB = Convert.ToDateTime("12-Mar-1995")
- };
-
- Patient patient4 = new Patient() { FirstName = "John",
- LastName = "Doe",
- GovtID = "ASDF1234523",
- DOB = Convert.ToDateTime("12-Mar-1998")
- };
Let's complete the rest of the code to just test our concepts.
- class Program
- {
- static void Main(string[] args)
- {
- Patient patient1 = new Patient() { FirstName = "John", LastName = "Doe", GovtID = "ASDF12345", DOB = Convert.ToDateTime("12-Mar-1998") };
- Patient patient2 = new Patient() { FirstName = "David", LastName = "De", GovtID = "ASDF123458", DOB = Convert.ToDateTime("12-Mar-1998") };
- Patient patient3 = new Patient() { FirstName = "Sam", LastName = "Dickson", GovtID = "ASDF12345", DOB = Convert.ToDateTime("12-Mar-1995") };
- Patient patient4 = new Patient() { FirstName = "John", LastName = "Doe", GovtID = "ASDF1234523", DOB = Convert.ToDateTime("12-Mar-1998") };
-
-
-
- List<Patient> allPatients = new List<Patient>();
- if (allPatients.Contains(patient1))
- Console.WriteLine("Patient 1:" + patient1.DuplicateEntityFoundMessage);
- else
- allPatients.Add(patient1);
-
- if (allPatients.Contains(patient2) == true)
- Console.WriteLine("Patient 2:" + patient2.DuplicateEntityFoundMessage);
- else
- allPatients.Add(patient2);
-
- if (allPatients.Contains(patient3))
- Console.WriteLine("Patient 3:" + patient3.DuplicateEntityFoundMessage);
- else
- allPatients.Add(patient3);
-
- if (allPatients.Contains(patient4))
- Console.WriteLine("Patient 4:" + patient4.DuplicateEntityFoundMessage);
- else
- allPatients.Add(patient4);
-
-
- if (patient1 != patient2)
- {
- Console.WriteLine("patient 1 and 2 are not same");
-
- }
- if (patient1 == patient3)
- {
- Console.WriteLine("patient 1 and patient 3: " + patient3.DuplicateEntityFoundMessage);
-
- }
- Console.ReadLine();
- }
- }
The final output on the console,
- Patient 3:Patient already exists with the same GovtID
- Patient 4:Patient already exists with the same First Name, Last Name and DOB
- patient 1 and 2 are not same
- patient 1 and patient 3: Patient already exists with the same GovtID
Patient 1 and Patient 2 have been successfully added to the collection.
Conclusion
There is a number of ways to achieve the above objective. You can use the Lambda Where<> on the Collection List or even used simple if's in the client itself. However, in the real world of entities where you have a large number of permutations and combinations of attributes that can be a candidate for the comparison, the code gets messier when you do it in the client-side code. Another aspect is code quality. It reduces the cognitive complexity of the client function and achieves the single responsibility design principle for the class/method.
- Professional looking code
- Improves testability. Thus reducing Cyclomatic Complexity
- Improves Readability: Thus reducing Cognitive Complexity
- Implements Single Responsibility design principle. (from S.O.L.I.D)
Thank You! stay safe, stay blessed !!