Proper domain model design - c#

Given an Employee entity and bunch of personal/organization-related information (like marital status, children information, department, position). Is all personal information to be represented as components/value objects or it is better for the information to reside inside the entity class?
Would using a person (which could gather all personal info) value object as an underlying object (composition) for an Employee entity be a bad design choice?
Also how would such a behaviour modelled properly (in terms of DDD): If employee has kids then it should have a birth certificate (with corresponding data: name, issue date, etc) or If employee is married then it should have marriage certificate (with corresponding data: spouse name, etc)?
For a kids case I decided to use ChildrenInformation value object:
public class ChildrenInformation
{
public String BirthCertificateCode { get;set; }
public DateTime BirthCertificateIssueDate { get;set; }
public ChildName { get; set; }
public ChildMiddleName { get; set; }
public ChildLastName { get; set; }
public DateTime ChildBirthday{ get; set; }
}
public class Employee : AbstractEntity<Employee>, IAggregateRoot
{
public ISet<ChildrenInformation> ChildrenInformation { get; set; }
/* other things ...*/
}
Wouldn't it be wrong from a design view?
EDIT
Another thought is to share Certificate class.
[Serializable]
public class Certificate
{
public String Code { get; set; }
public String Number { get; set; }
public String RegistreeName { get; set; }
public Address RegistreeAddress { get; set; }
public String RegistreeDateOfBirth { get; set; }
public String RegistredAt { get; set; }
public DateTime DateRegistred { get; set; }
}
[Serializable]
public class Employee : AbstractEntity<Employee>, IAggregateRoot
{
public Certificate Passport { get; set; }
public Certificate MarriageCertificate { get; set; }
public ISet<Certificate> ChildrenBirthCertificates { get; set; }
}
Thanks!

I would model it like this:
public class Person
{
public String Name { get; set; }
public String MiddleName { get; set; }
public String LastName { get; set; }
public DateTime Birthday { get; set; }
public BirthCertificate BirthCertificate { get;set; }
public MarriageCertificate MarriageCertificate { get;set; }
// ...etc...
}
public class Certificate
{
public String Code { get;set; }
public DateTime IssueDate { get;set; }
// ...etc...
}
public class BirthCertificate: Certificate
{
public DateTime BirthDate { get;set; }
// ...etc...
}
public class MarriageCertificate: Certificate
{
public String SpouseName { get;set; } // or Spouse could also be a person
// ...etc...
}
public class Employee
{
public ISet<Person> Children { get; }
// ...etc...
}
Some points:
Note the ? usage which means certificates are optional.
Certificate deserve their own types. If you have more than one property that start with the same prefix, most of the time, it means you can define an object off them. I have also created a base Certificate class because they may share some common properties and behavior.
Children is a collection of Person objects.
Spouse could also be a person, if you will (the property would then be named Spouse).
I don't repeat the declaring type name in a property name: Name instead of PersonName

Given an Employee entity and bunch of personal/organization-related information (like marital status, children information, department, position). Is all personal information to be represented as components/value objects or it is better for the information to reside inside the entity class?
I would put all of the given examples as properties in the employee entity. I don't see any benefit in having them as value objects?
Would using a person (which could gather all personal info) value object as an underlying object (composition) for an Employee entity be a bad design choice?
This is more of a domain question. I normally do not use inheritance but use Customer and Employee (instead of a Person entity) as to different models not related to each other.

Please note that the design concept of composition has nothing to do with the CLR concept of a value type. Composition just means that the life-time of the owned object is bound to the life-time of the owner. This can also be achieved with reference types, for example if the owner is the only one with a reference to the owned object.
That said, the solution from Simon is just fine.

Related

Entity Framework Code First One to One Cascade Deletes

Have and "Address" model used by several other models ("Employee" & "Client").
I would call this a one to one relationship, I could be wrong. The address is required by both of the other models. Remove, deletes only the parent object.
Tried in both EF Core and EF6. Remove deletes the parent object, but not the "Address" object.
public class Address
{
public int AddressID { get; set; }
public string Street { get; set; }
public string CityStateZip { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
[Required]
public virtual Address EmployeeAddress { get; set; }
}
public class Client
{
public int Id { get; set; }
public string Name { get; set; }
[Required]
public virtual Address ClientAddress { get; set; }
}
No error messages - context.remove simply won't delete the child object. Complete noob here when it comes to EF. Sorry, this is probably a very basic question, but please believe that I have searched extensively. Most solutions suggest a foreign key back to the parent - but, in this case, the child object can be used (but not shared) in several different models.
The same Address object can be used in multiple Employee and/or Client instances as currently implemented.
The suggestion you received
Most solutions suggest a foreign key back to the parent - but, in this case, the child object can be used (but not shared) in several different models.
informs Entity Framework that a given Address can only appear in one specific Employee/Client.
You should be able to resolve this by having Employee and Client inherit from a common base class, e.g.
public class Person
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
[Required]
public virtual Address PersonAddress { get; set; }
}
public class Employee : Person
{
// Other properties that make Employee unique go here
}
public class Client : Person
{
// Other properties that make Client unique go here
}
Then add the backreference to the base class
public class Address
{
public virtual int AddressID { get; set; }
public virtual string Street { get; set; }
public virtual string CityStateZip { get; set; }
[Required]
public virtual Person AddressOf { get; set; }
}

Navigational Properties vs Inheritance Entity Framework

I am trying to explore if there are different ways than how I am used to using EntityFramework and relationships between data models.
Let's say, I have the following two classes:
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
}
public class Employee
{
public string JobDescripion { get; set; }
}
Let's assume there is a One to Many relationship between these two models in the database, with the many on the Employee class.
I would map this as follow:
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
//Navigational Property
public ICollection<Employee> Employees { get; set; }
}
public class Employee
{
public string JobDescripion { get; set; }
//navigational property
public virtual Person Person { get; set; }
}
This for me, takes away the principle of Object Orientated, as the Employee now do not Inherit from the Person class anymore, or at least, from my understanding.
Is this proper design, and would still be considered good Object Orientated Code, or is there a better way to be handling this, if for instance, I would like the following inheritance in my code:
public class Employee : Person
How would EntityFramework handle this?

Filling list with different types of objects

I'm working on a recommendation algorithm which all works fine. But now I wanted to implement this code into the branch of my development team.
I'll start from the top. My algorithm can recommend 2 types of objects, restaurants and dishes.
Restaurant:
public class Restaurant
{
public Guid Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
public List<Tag> Tags { get; set; } = new List<Tag>();
public int PriceRange { get; set; }
}
And dish:
public class Dish
{
public Guid Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public virtual Restaurant rest { get; set; }
[ForeignKey("rest")]
public Guid RestaurantId { get; set; }
public List<Tag> Tags { get; set; }
}
Now my product owner wants the list to be like this when it's being presented on the home page of our app:
[Restaurant][Dish][Restaurant][Dish] Etc...
So basically, he wants to alternate the type of object that's being recommended. These dishes and restaurants are completely separate. They are generated by my algorithm purely on the user's preferences and have no correlation with eachother at all.
Now my problem is how to return such a list. I figured I'd need a wrapper class which contains either a Restaurant or Dish like this:
public class RecommenderItem
{
public Restaurant rest { get; set; }
public Dish dish { get; set; }
}
This way I can create a List<RecommenderItem> and return that to the client. The client would only need to check which attribute is null and retrieve the values from the one that is not.
I'm just unsure if this is the correct approach. Are there any 'best practices' in doing this? Let me know if I should elaborate more!
If they doesn't have common base class then creating one wrapper class is the best solution. At the same time you can be more flexible and create something like
public class RecommendationItem
{
public Guid Id { get; set; }
public string Name { get; set; }
public string PageUrl { get; set; }
public object Entity { get; set; }
}
So you can include all common information in this class and client will not be required to check with which object type he works. In such case it would be easier to add one more item type. At the same type I added reference to entity itself - it can be used if some specific handling for one or two item types is required.
You can declare an interface IRecommenderItem:
public interface IRecommenderItem
{
//shared properties
}
public class Restaurant : IRecommenderItem
{
}
public class Dish : IRecommenderItem
{
}
than, you can type:
List<IRecommenderItem> m = new List<IRecommenderItem>();
If you are going to connect pairs of elements it always makes sense to me to... well, pair the elements. I am assuming that each dish is specific to a particular restaurant? So the list would be [Restaurant1][Dish for Restaurant1][Restaurant2][Dish for Restaurant2]...?
I like the previous answer by oryol creating a common base class as well.
So, your RecommenderItem class is fine. But fill in both properties and pass a list of pairs back. Expand the list into the full set of items for display by creating a new List, iterating through the list of RecommenderItems and adding Restaurant and Dish from each entry in it.

C# Family Class Design

I am working on building a single family unit (class) for an application. I've done some searching and found solutions for entire family trees, but this app doesn't care about anything outside the single family unit which is defined as (Father, Mother, Child1, Child+n)
This application is about the children (activities they can do based upon age and skill levels), but needs references to the parents. The parents are only needed for reporting purposes and are required to have driver's license and insurance on file.
The application is being built using C# & EF Code First. None of the database annotation elements have been added to the class yet as that isn't the problem.
Below are my classes. The main business rule state that each sibling will have his/her own record, but they need to be linked together so only one mailing (electronic or snail) is sent, if the parents live together. If the parents are divorced, then two letter (or emails) need to be sent.
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string Suffix { get; set; }
public string Sex { get; set; }
public DateTime DOB { get; set; }
}
public class Youth : Person
{
public string CurrentGrade { get; set; }
public Adult Mother { get; set; }
public Adult Father { get; set; }
public Adult ICE { get; set; }
public virtual Adult Adult { get; set; }
}
public class Adult : Person
{
public string DriversLicense { get; set; }
public string StateIssued { get; set; }
public string AutoInsuranceCarrier { get; set; }
public string PolicyNumer { get; set; }
public string MaritalStatus { get; set; }
//foreign key
public int VehicleId { get; set; }
public virtual Vehicle Vehicle { get; set; }
}
public class Address
{
public int AddressId { get; set; }
public int PersonId { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public virtual Person Person { get; set; }
}
The logic pattern I was stuck in was that siblings will have the same AddressId. That failed when I applied the divorced parents, each having one child at their address. As far as mailings go, it would work because they are at different addresses. It doesn't feel like the best design. If this were handled by UI, then it would work.
My next thought was to create a Family class and add each family member to it. In this instance, the user would have to make the selection of which people would be living at which address.
public class Family
{
public int FamilyId { get; set; }
public int AddressId { get; set; }
public List<Person> Person;
}
That also doesn't seem like the best solution. I feel there is a better design. I just cannot find it on my own.
Are there any pitfalls to one of these approaches that I'm not seeing yet?
Can someone point me in a better direction? And explain why that direction is better?
Thanks in advance for all your insights!
The "Father", "Youth", "Brother", etc... is not attribute of the person, but attribute of relationship between persons. One person can be both "Father" and "Brother" and "Uncle".
Better design is something like this (i don't know all your requirements):
public class Person {
public Name{get;set;}
// etc...
public List<Relationship> Relationships{get;set;}
}
public class Relationship {
public Person P1{get;set;}
public Person P2{get;set;}
public RelationshipKind Kind{get;set;}
}
public class RelationshipKind {
// for example: Father
public Name1 {get;set;}
// for example: Child
public Name2 {get;set;}
}
Typically you want to keep your models flowing as you would think about them.
For instance, I would not have an Address class that contains Person. I would have an Address class containing only base data about the Address. In Person, I would have an Address. This fits with the "Person lives at this address" and will likely fix your who-lives-where issue. This is the type of setup you have for "Vehicle"
Without going into details regarding whole design, I will focus only on the address issue.
I recommend that you have your address class defined in a way that it does not have navigation property back to a person:
public class Address
{
public int AddressId { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
}
Then I would link your Adult (or even Person) class to Address like so:
public class Adult : Person
{
public string DriversLicense { get; set; }
public string StateIssued { get; set; }
public string AutoInsuranceCarrier { get; set; }
public string PolicyNumer { get; set; }
public string MaritalStatus { get; set; }
//foreign key
public int VehicleId { get; set; }
public virtual Vehicle Vehicle { get; set; }
public int AddressId {get; set;}
public virtual Address Address { get; set; }
}
With this approach, if parents are not divorced, they can share the same address instance. In case they are divorced, your application has to set different address for one of the parents. In case you need to find people living under same address, you can do sth like this:
_dbContext.Persons.Where(p => p.AddressId = addressId) ...
If you have a table of States then you can use that in a lot of places: DriversLicenseState, AddressState, InsuranceState etc. If this isn't a blank string then you don't have to validate the user input and can just put a drop-down on the application.
String current grade. If you instead enter the year the child entered first grade then you don't have to manually update this every year; it can be calculated - though you also have to include an int for NumberOfYearsHeldBack. But its less work to update that int once in a great while, than update every student every year.
Personal Preference: I like 'NameLast' and 'NameFirst' rather than 'FirstName' & 'LastName' just because it means these properties will bunch together alphabetically in all the IDE drop downs etc, just like AddressID, Address1 and Address2
You might consider making 'Mother' into a nullable 'Mother?' and the same with 'Father' to 'Father?'. Some kids simply don't have both parents. If you want to be politically correct you might consider 'Parent1?' and 'Parent2' and put an enum on the relationship to select mother, father, guardian because some kids have 2 moms or 2 dads or their older brother is their legal guardian.
In your address class why is there a person property when you already have a PersonID property? For that matter why does the address have a personID at all? This only needs to be one-way. A person has an address, but an address doesn't have a person. This way you can have 5 people all with the same address. If you try to keep both synchronized two-way it will get fouled up, not to mention you have to have a List<> of personID inside the address. Since address is a type, add another one to each person so you have an AddressPhysical and AddressMailing. Now you can have 4 kids each with different places they sleep but they all get their mail at grandma's P.O.Box.
I wouldn't add a third adult to the child as their ICE. Instead I would make a List<> of adults (its just going to be a list of ID ints really) That way you can keep working down the list in an emergency until you reach someone.

Entity Framework 6 - Multiple lookup inserts vs An object with the same key already exists in the ObjectStateManager

I am apparently having a real devil of a time understanding Entity Framework 6 which I am using with ASP.NET MVC 5.
The core of the matter is that I have a really quite simple data model that is typical of any real world situation where I have various business objects that have other business objects as properties (and of course they child objects may in turn have other child business objects) and also various types of lookup/type data (Country, State/Province, LanguageType, StatusType etc.) and I cannot figure out how to save/update it properly.
I keep going back and forth between two error states:
1) I either run into the situation where saving a parent business object results in unwanted duplicate values being inserted into my lookup/type tables (for example saving a business object that has been assigned an existing LanguageType of 'English' will result in another LanguageType for 'English' being inserted into the LanguageType table), or
2) I use some of the suggestions I've seen here and elsewhere on the net (e.g. Saving Entity causes duplicate insert into lookup data, Prevent Entity Framework to Insert Values for Navigational Properties ) to solve issue 1 and then find myself fighting against this same issue: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key .
I will now provide a few code snippets to help build the picture of what I am trying to do and what I am using to do it. First, an example of the entities involved:
public class Customer : BaseEntity
{
public string Name { get; set; }
[LocalizedDisplayName("Contacts")]
public virtual List Contacts { get; set; }
}
public class Contact : BaseEntity
{
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public int? LanguageTypeID { get; set; }
[Required]
[ForeignKey("LanguageTypeID")]
public virtual LanguageType Language { get; set; }
}
public class LanguageType : Lookup
{
[LocalizedDisplayName("CultureName")]
public string CultureName { get; set; }
}
public class Lookup : BaseEntity
{
public string DisplayName { get; set; }
public int DisplayOrder { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class BaseEntity
{
public int ID { get; set; }
public DateTime? CreatedOn { get; set; }
public DateTime? UpdatedOn { get; set; }
public DateTime? DeletedOn { get; set; }
public bool Deleted { get; set; }
public bool Active { get; set; }
public ApplicationUser CreatedByUser { get; set; }
public ApplicationUser UpdatedByUser { get; set; }
}
In my controller, I have some code like the following:
foreach(Contact contact in lstContacts)
{
customer.Contacts.Add(contact);
}
if (ModelState.IsValid)
{
repository.Add(customer);
}
Let us suppose that each of the contacts has the same LanguageType of 'English' assigned (and in this example it is the fact that I am trying to save multiple contacts that have the same LanguageType that triggers the ObjectStateManager error). Initially, the repository.Add() code just did a context.SaveChanges() which did not work as expected, so now it looks something like this (Entity variable is a Customer):
try
{
if(Entity.Contacts != null)
{
foreach(Contact contact in Entity.Contacts)
{
var entry = this.context.Entry(contact.Language);
var key = contact.Language.ID;
if (entry.State == EntityState.Detached)
{
var currentEntry = this.context.LanguageTypes.Local.SingleOrDefault(l => l.ID == key);
if (currentEntry != null)
{
var attachedEntry = this.context.Entry(currentEntry);
//attachedEntry.CurrentValues.SetValues(entityToUpdate);
attachedEntry.State = EntityState.Unchanged;
}
else
{
this.context.LanguageTypes.Attach(contact.Language);
entry.State = EntityState.Unchanged;
}
}
}
}
context.Customers.Add(Entity);
context.SaveChanges();
}
catch(Exception ex)
{
throw;
}
Is it fundamentally wrong to expect this to have worked? How am I supposed to save and example like this? I have similar problems saving similar object graphs. When I look at tutorials and examples for EF, they are all simple and they all just call SaveChanges() after doing something very similar to what I am doing here.
I've just recently been using the ORM capabilities of ColdFusion (which is hibernate under the covers) and there are would simply load the LanguageType entity, assign it to the Contact entity, save the Contact entity, assign it to the Customer and then save the Customer.
In my mind, this is the most basic of situations and I cannot believe that it has caused me so much pain - I hate to say it, but using plain old ADO.NET (or heaven forbid, ColdFusion which I really don't enjoy) would have been MUCH simpler. So I am missing SOMETHING. I apparently have a key flaw in my understanding/approach to EF and If somebody could help me to make this work as expected and help me to figure out just where my misunderstanding lies, I would greatly appreciate it. I have spend too many hours and hours on this and it is a waste of time - I have/will have countless examples just like this one in the code I am building so I need to adjust my thinking with respect to EF right now so I can be productive and do approach things in the expected way.
Your help will mean so much and I thank you for it!
Let's consider the following object graph in which a teacher instance is the root object,
Teacher --[has many]--> courses
Teacher --[Has One]--> Department
In entity framework's DbContext, each instance of an object has a State indicating whether the object is Added, Modified, Removed or Unchanged. What happens apparently is the following :
Creating the root object for the first time
In this case, in addition to the newly created root object Teacher, ALL the child objects in the graph will have the State Added as well even if they're already created. The solution for this problem is to include the foreign key property for each child element and use it instead, i.e. Teacher.DepartmentId = 3 for example.
Updating the root object and one of its child elements' properties
Suppose you fetch a teacher object from the db, and you change the Teacher.Name property as well as the Teacher.Department.Name property; in this case, only the teacher root object will have the State marked as Modified, the department's State on the other hand remains Unchanged and the modification won't be persisted into DB; Silently without any warning.
EDIT 1
I used your classes as follows and I don't have a problem with persisting the objects :
public class Customer : BaseEntity
{
public string Name { get; set; }
public virtual List<Contact> Contacts { get; set; }
}
public class Contact : BaseEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int? LanguageTypeID { get; set; }
public Customer Customer { get; set; }
[ForeignKey("LanguageTypeID")]
public LanguageType Language { get; set; }
}
public class LanguageType : Lookup
{
public string CultureName { get; set; }
}
public class Lookup : BaseEntity
{
public string DisplayName { get; set; }
public int DisplayOrder { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class BaseEntity
{
public int ID { get; set; }
public DateTime? CreatedOn { get; set; }
public DateTime? UpdatedOn { get; set; }
public DateTime? DeletedOn { get; set; }
public bool Deleted { get; set; }
public bool Active { get; set; }
public ApplicationUser CreatedByUser { get; set; }
public ApplicationUser UpdatedByUser { get; set; }
}
public class ApplicationUser
{
public int ID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
}
And used the following Context :
public class Context : DbContext
{
public Context() : base("name=CS") { }
public DbSet<Customer> Customers { get; set; }
public DbSet<Contact> Contacts { get; set; }
public DbSet<LanguageType> LanguageTypes { get; set; }
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//I'm generating the database using those entities you defined;
//Here we're demanding not add 's' to the end of table names
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Then I created a unit tests class with the following :
[TestMethod]
public void TestMethod1()
{
//our context
var ctx = new Infrastructure.EF.Context();
//our language types
var languageType1 = new LanguageType { ID = 1, Name = "French" };
var languageType2 = new LanguageType { ID = 2, Name = "English" };
ctx.LanguageTypes.AddRange(new LanguageType[] { languageType1, languageType2 });
//persist our language types into db before we continue.
ctx.SaveChanges();
//now we're about to start a new unit of work
var customer = new Customer
{
ID = 1,
Name = "C1",
Contacts = new List<Contact>() //To avoid null exception
};
//notice that we're assigning the id of the language type and not
//an object.
var Contacts = new List<Contact>(new Contact[] {
new Contact{ID=1, Customer = customer, LanguageTypeID=1},
new Contact{ID=2, Customer = customer, LanguageTypeID=2}
});
customer.Contacts.AddRange(Contacts);
//adding the customer here will mark the whole object graph as 'Added'
ctx.Customers.Add(customer);
//The customer & contacts are persisted, and in the DB, the language
//types are not redundant.
ctx.SaveChanges();
}
It all worked smoothly without any problems.
As far as i know there is no build in support for reattaching modified graphs (like the SaveOrUpdate method of nHibernate). Perhaps this or this can help you.

Categories