Complex Modeling
Motivation
Columns from database are flat, but sometimes we'll want to represent certain columns as a whole model to better describe them in code base. In other words, we need higher abstraction upon the columns.
Complex property
record class Person(string? FirstName, string? LastName);
public class Movie
{
public int Identifier { get; set; }
public string? Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string? Synopsis { get; set; }
public string? DirectorFirstName { get; set; } // [!code --]
public string? DirectorLastName { get; set; } // [!code --]
public Person? Director { get; set; } // [!code ++]
}
2
3
4
5
6
7
8
9
10
11
Entity framework core will spread properties of Director
as column mappings for database, which means we should have Director_FirstName
and Director_LastName
as columns in database.
builder.ComplexProperty(movie => movie.Director); // spread the structured property
Certainly, we can override mappings if you don't like the convetion.
builder.ComplexProperty(movie => movie.Director)
.Property(movie => movie.FirstName) // [!code highlight]
.HasColumnName("d_firstname"); // [!code highlight]
2
3
Complex modeling across tables
// equivalent to `ComplexProperty`
builder.OwnsOne(movie => movie.Director); // each movie entity owns one director
2
Generally we should separate the columns about something obviously not primitive to the table itself into another table for preventing pollution.
builder.OwnsOne(movie => movie.Director)
.ToTable("Directors") // move director to another table
2
Since director is owned by Movie
entity, Entity framework core generates a foreign key in director table as reference for movie table(also a primary key). But director table is not independent, if a row of movie is removed, the director row will also be removed(yes directors are not reused).
INFO
It's not common solution we do in database design, it's just a showcase.
OwnsMany
One movie will have multiple casts.
public class Movie
{
public int Identifier { get; set; }
public string? Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string? Synopsis { get; set; }
public Person? Director { get; set; }
public ICollection<Person>? Casts { get; set; } // [!code ++]
}
2
3
4
5
6
7
8
9
While one entity can own many other entites, we use OwnsMany
.
builder.OwnsMany(movie => movie.Casts)
.ToTable("Casts"); // [!code highlight]
2