-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
129 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,83 @@ | ||
# About me | ||
# 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 | ||
|
||
```cs | ||
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 ++] | ||
} | ||
``` | ||
|
||
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. | ||
|
||
```cs | ||
builder.ComplexProperty(movie => movie.Director); // spread the structured property | ||
``` | ||
|
||
Certainly, we can override mappings if you don't like the convetion. | ||
|
||
```cs | ||
builder.ComplexProperty(movie => movie.Director) | ||
.Property(movie => movie.FirstName) // [!code highlight] | ||
.HasColumnName("d_firstname"); // [!code highlight] | ||
``` | ||
|
||
## Complex modeling across tables | ||
|
||
|
||
```cs | ||
// equivalent to `ComplexProperty` | ||
builder.OwnsOne(movie => movie.Director); // each movie entity owns one director | ||
``` | ||
|
||
Generally we should separate the columns about something obviously not primitive to the table itself into another table for preventing pollution. | ||
|
||
```cs | ||
builder.OwnsOne(movie => movie.Director) | ||
.ToTable("Directors") // move director to another table // [!code highlight] | ||
``` | ||
|
||
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. | ||
|
||
```cs | ||
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 ++] | ||
} | ||
``` | ||
|
||
While one entity can own many other entites, we use `OwnsMany`. | ||
|
||
```cs | ||
builder.OwnsMany(movie => movie.Casts) | ||
.ToTable("Casts"); // [!code highlight] | ||
``` | ||
|
||
This is a personal blog for documenting my learning journey of various things(primarily programming). | ||
All those records are organized as markdowns. |
47 changes: 47 additions & 0 deletions
47
docs/document/Entity Framework Core/docs/8. Mapping Default Values.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Mapping Default Values | ||
|
||
## Motivation | ||
|
||
You may want a certain value as default for a column or a expression to invoke on update, insert and so on. | ||
|
||
## Static default | ||
|
||
```cs | ||
builder.Property(x => x.FullName) | ||
.HasDefaultValue("John Smith") // all default value should be `John Smith` in database! | ||
builder.Property(x => x.CreatedDate) | ||
.HasDefaultValue(DateTime.Now); // should be the datetime value when compiled. | ||
``` | ||
|
||
## Dynamic default | ||
|
||
### Server side | ||
|
||
Once again, entity framework core translates the form, so we'll need a sql expression to map the dynamic default. | ||
|
||
```cs | ||
builder.Property(x => x.CreatedDate) | ||
.HasDefaultValueSql("now()"); // evaluates function `now()` on insert | ||
``` | ||
|
||
### Client side | ||
|
||
Default values can also be generated dynamically from client side with a generator class. | ||
|
||
```cs | ||
using Microsoft.EntityFrameworkCore.ChangeTracking; | ||
using Microsoft.EntityFrameworkCore.ValueGeneration; | ||
|
||
public class CreatedDateGenerator : ValueGenerator<DateTime> | ||
{ | ||
public override DateTime Next(EntityEntry entry) | ||
{ | ||
return DateTime.UtcNow; // what value should generate, can be more complex | ||
} | ||
|
||
public override bool GeneratesTemporaryValues => false; | ||
} | ||
|
||
builder.Property(x => x.CreatedDate) | ||
.HasDefaultValue<CreatedDateGenerator>(); | ||
``` |