DDD and CRUD on lookup tables using repository pattern - c#

So I am trying to follow the Domain Driven Design approach and am not sure how to handle lookup tables that require CRUD operations. Here is a contrived example to demonstrate my question.
Let's say I have a Person class
public class Person
{
public string Address { get; private set; }
}
My database has a table of People and a table of Addresses. The People table has a column for Address_Id which is a foreign key to the Address table. The obvious idea being you can't add a person record to the People table with an address value that doesn't exist in the Addresses table since there is a foreign key relationship.
In my application, Person is an aggregate root and thus has an associated repository. Using the repository, I load people which also loads the associated address.
My question is how do I do CRUD operations on the Addresses table? Following DDD principles, I don't think I am supposed to create a repository for the Addresses table.
The requirement for my application is that when creating a new Person object, a drop-down list of addresses is presented from which the user will select an address. They are not allowed to hand type addresses, they must pick from one that already exists. Hence, the CRUD operations on the Addresses table. The administrator of the system will need to manage the Addresses lookup table so that the proper selections are presented to a user creating Person objects.
Again, this is a very contrived example and I get that nobody would ever design such a system. It is simply to help illustrate the question.

IMO, you have two use cases: 1) Saving Person objects, but before 2) listing all available Addresses to be able to select the right one.
So, I would create a AddressRepository, maybe not a CRUD one, but only for fetching entities.

Are you ever editing or retrieving addresses on their own? The repository is essentially a mapper for a business object to a relational database, it is supposed to encapsulate how the object is persisted so you don't have to worry about it.
If the object is persisted in multiple tables the business logic does not have to know that, so unless you needed to edit Address objects on their own, I wouldn't add a repository for Address.
Have a look at this: Repository Pattern Step by Step Explanation

Well, but I guess property string Address should be Address Address.
In that case, when you store a Person on PersonRepository, if some given Address doesn't exists in the underlying store, the whole repository using its tech-specific implementation will create the whole address registry in your Addresses relational table for you.
Also, I guess you'll be using a repository over an existing data mapper - an OR/M -, which should manage this cases easily: it's just about mapping the whole property as a many-to-one assocation.
Actually I believe a repository should store root aggregates like you mention in your own question.
It depends on your own domain. If an address can live alone because it can be associated to 0 or more persons, you should consider adding addresses using a specific AddressRepository, register addresses using it and later you can always associate one to some Person.

Related

On the "owned" types in EF Core

In my project, I use the EF Core fluent config, code first. I read a little about the owned types, but the situation bellow is not really clear to me:
Suppose I have a Project entity and a ProjectType.
Should I map that property as :
Entity<Project>.HasOne<ProjectType>(); or rather as
Entity<Project>.OwnsOne<ProjectType>();
The ProjectType entity should be mapped to a table ProjectType(ProjectTypeId, Name, Description)
As I read, owned are
"types that can only ever appear on navigation properties of other
entity types. These are called owned entity types. The entity
containing an owned entity type is its owner. Owned entities are
essentially a part of the owner and cannot exist without it"
In my case
"ProjectType can only ever appear on navigation properties of Project entity type. ProjectType is essentially a part of the Project and cannot exist without it"... however, in order to create a separate table, as I understood I need to use HasOne, not OwnsOne... would be great if someone explain better this idea. Thanks a lot.
ProjectTypes sound like a reference table that might otherwise be modifiable over the course of an application's lifespan, such as through a system administration role. Usage of the new "Owns" is a convention to help enforce concepts like type-specific composition, and linking tables in a relational data model.
A better example for composition: Say you have a Project and as a part of a Project there are some details that are fairly large, and infrequently used. Things like an image or other binary data, or perhaps some large text. Having these BLOB/CLOB details inside the Project table can be a recipe for disaster when you fetch a Project, or many Projects, so you normalize them out into a separate related table called ProjectDetails, or possibly several related tables. This way, for the most part when you are working with Project and loading those entities you don't have to worry about pulling back these large fields all of the time, you can reference a ProjectDetails to include only when it is actually needed. Since ProjectDetails doesn't really serve any purpose on it's own, it doesn't need a DbSet or anything of the like, so we can set up the relationship from Project to OwnsOne ProjectDetails.
ProjectType on the other hand would potentially have a DbSet to establish new project types over the course of configuring an application. You may also want to associate other project-related details based on a Project Type. In this case it would make more sense for Project to HasOne ProjectType. We can have a DbSet of ProjectTypes to manage, and other entities may filter by ProjectTYpe as well, Project Stages/Phases, etc.
As far as the database schema goes between Owns and Has, there is no difference. It's solely about how the EF DbContext will expect to work with the entities.
Other common examples of using Owns are linking tables. For instance you have an Address table which is shared between Orders, Customers, etc. Neither "Owns" addresses, but they do own their linking table: Order Owns OrderAddress, Customer Owns CustomerAddress. These entities "Has" an Address. We may still want to review Addresses as they represent physical locations and there is a difference between associating an Order etc. to a different location, and "adjusting" the details recorded for a physical location. (I.e. correcting a street name or municipality) There is not a need to ever deal with OrderAddresses or CustomerAddresses outside of the scope of the Order or Customer respectively.

Multiple Contexts using EF 6 duplicating tables in identity db and main db

This may be obvious but I'm missing it, so apologies if so.
I have a project using Entity Framework code first and all that good stuff.
I read that you should keep the Identity framework separate from the main DB so I created a separate context for it.
So far so good and even though there is a bit of additional complexity it isn't too much.
However, I want to reference the Address object from the main Identity User object (every user will have at least one), but there is a need for other addresses not related to users, but still addresses right? So they go in the main DB context.
I have added the Address class into the Identity model:
public Address Address { get; set; }
This uses the Address class definition that is used in the 'MainDBcontext':
public DbSet<Address> Addresses { get; set; }
I add the migrations to set it all up but end up with an address table in both databases. Also I end up with different data in each Address table from the seed method depending if the Address is a user related one or not. Which makes sense I guess, but would really like all the addresses in one place. Yes, I guess I could just remove the address table from the 'MainDB' context and use the Identity one, but then I may as well move everything over ...
I am tempted just to move everything into one DB and have done with it but before I do, I wanted to see if there was a trick I'm missing.
Any ideas?

Understanding DDD (services, aggregate, entities, repositories and specifications)

I'm starting with DDD and trying to apply in my current project, but as you can suppose I have thousand of questions.
Here I present a sample domain so I can make different question and serves as an exercise on which you can explain me how things can be made.
Our hypothetical system must take control of companies and what persons works on each one.
Domain.
Company(id, name, address)
Employee(id, name, surname, age)
A person can only work on a company and a company can have many employees working on it.
Operations
The system must allow to add a new employee to a company. For this it receives the company id and the name, surname, age of the new employee. There are some restriction to satisfy:
There can not be another employee with the same name, surname and age in the company.
The employee can be working in another company.
Questions
I have a mess in my mind :)
To implement the operation I'm thinking on:
Service receives all the parameters.
Service call CompanyRepository->findCompanyById to retrieve the company instance.
Service creates a new instance of Employee using the specified parameters.
Services calls company->addEmployee to attach the employee to the company.
Within the company->AddEmployee check the new employee satisfies the conditions (specifications).
Service calls CompanyRepository->save(company) to persist the company in addition to the employee.
Because company+employee is managed as a cluster (aggregate) I'm considering the company the aggregate root.
Is this a good implementation?
If I consider company+employee an aggregate, in the same way I described to save the cluster company+employe, must I retrieve all the related employees too when I retrieve the company instance from repository ?
Respect specifications I can understand easily how to check, for example, if a employee name has more than 10 chars, but: how to check if the employee exists in the same company if the company has thousands of employees?
Can a specification call repository operations? and if yes, and the fact that considering company+employee a cluster is right, what would be the right place? CustomerRepository->findEmployeeByName(idCompany, nameEmployee) or better create a specific EmployeeRepository.
1
What is good or bad is just an opinion. DDD shouldn't be a dogma and you can take the best of it and your own additions to build good software architectures.
2
No, company can either lazily-load employees (i.e. when runtime access the Employee property the first time after the company has been retrieved) or company can implement a Load method which also supports pagination to load only required employees.
3
You should implement this at repository level (for example ICompanyRepository.ContainsEmployee(Employee)) and use the underlying data mapper to perform this heavy operation.
Also, I tend to call specifications as pre-/post-conditions in repositories, because it's the only way to be sure that they will be fulfilled in all cases.
4
I would avoid it, but if you want to ensure a lot of domain rules, you'll need to use them in specifications. BTW, I wouldn't use repositories but I would use services instead.
The right place depends on the requirement. If you want to perform checks to be sure that domain objects are being stored in the repository in a valid state, I find no issue if you want to call an specification from within ICompanyRepository.Add or ICompanyRepository.Update, or ICompanyRepository.AddOrUpdate. The point here is you shouldn't verify object states both when they're stored in the repository and when they're retrievied. If your specifications and your code is reliable, if the repository has filtered domain objects and it has stored them in the underlying data store, you can be sure than read operations will get valid domain objects.
Side note: While you shouldn't model your domain based on the underlying data store (either relational, NoSQL, file system...), again, you shouldn't apply DDD like a dogma. If the underlying data store provides a better approach to define data constraints, I would try to use them instead of implementing complex specifications which might need to access the data anyway.
Your solution should be a balance of an optimal software architecture and runtime performance.

Handling Duplicate Database Entries with C# and the Entity Framework

Let's say that I have an object model with many different objects that I then, using the Entity Framework map to database tables. That all works fine. The problem is what happens when I want to save more objects to the database. The objects in the model are interconnected, so when I am saving objects to the database, they may have references to objects that are already in the database.
For example, if I have an object called Person which has a property Friends which in itself is a list of people. This means that there is a table of Persons in the database and each of these has a list of friends which are identified by their ID's. Assuming that if the ID's of two people are the same then they are the same person, then I believe the Entity Framework will throw an error if I try to add them again. So the problem is when I add another person object who already has a list of friends, then I want to add friends who are not in the database, and I do not want to add the ones that already are in the database. Also each of those people may have friends who are/aren't in the database and I want them considered too. Another thing to consider is that even if the person is already in the database I want to look through their list of friends and add any new ones.
I feel like this should be a fairly common problem when working with databases, but I'm probably using the wrong vocabulary since nothing useful is actually coming up in all of my searches. It mostly deals with how to scan databases for duplicates after the fact or something like that. I want this to be handled in a business logic C# code layer through an Entity-Framework-approved venue. Any help is appreciated. Thank you in advance.
The problem you pose is valid, but it does not fundamentally differ from adding objects to a Dictionary or a HashSet. You simply have to check whether a certain Person or related Friend is already contained in the Dictionary or if you will the Databasetable. The beauty of using the Entity Framework is that it makes these operations very similar.
So, you can use either a method like context.People.Contains(newPerson) (you must implement IEquatable<Person> for that), orcontext.People.Find(id).
Likewise you can use
foreach(friend in newPerson.Friends)
{
if(!context.People.Contains(friend)
context.People.Add(friend)
}

Problem modelling address generalization

I’m a bit concerned about how to model this rather simple scenario the best way in UML and ERM. When designed it has to be implemented in C# (Entity Framework 4) and SQL Server 2008.
The case is that I have a person, who has a postal address. Now this address can be two types, either a postal box, or a house identifier (house number, street, etc.). I believe that this is called generalization, and might be modelled the following way using UML:
http://i.imgur.com/Vzx4Z.png (sorry for the link, but I don't have enough reputation to post images yet)
PostalAddressPostalBox and PostalAddressHouseIdentifier will of course have more properties and relations to other entities/tables. Same goes with the Person class. Also other classes will have a reference to a postal address, so it's not only persons.
My question is if this is the correct way to model this problem, and how I can implement it in SQL (schema wise) and what my entities in C# should look like?
Thank you in advance
I just think you shouldn't reuse the PostalAddress for different entities. It will just be harder to change the address for a given entity.
For the relational database, there are some options, like class table inheritance.
Or maybe single table inheritance or concrete table inheritance. It's up to you to decide the tradeoffs.

Categories