Skip to content

Commit

Permalink
test
Browse files Browse the repository at this point in the history
  • Loading branch information
sharpchen committed Aug 24, 2024
1 parent f1b41de commit 6d19557
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 3 deletions.
85 changes: 82 additions & 3 deletions docs/about.md
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.
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>();
```

0 comments on commit 6d19557

Please sign in to comment.