Compare commits

...

2 Commits

Author SHA1 Message Date
Aaron Po
d6e176bcd9 Split dbo schema into per-domain SQL schemas (#274) 2026-09-02 22:23:30 -04:00
Aaron Po
8d59f09cb2 chore/update layouts in diagrams (#273) 2026-09-02 21:28:23 -04:00
43 changed files with 319 additions and 235 deletions

View File

@@ -1,4 +1,8 @@
flowchart TD ---
config:
layout: elk
---
flowchart LR
Start([start]) --> ParseArgs["main.cc: ParseArguments(argc, argv)"] Start([start]) --> ParseArgs["main.cc: ParseArguments(argc, argv)"]
ParseArgs --> ArgsValid{Arguments valid?} ParseArgs --> ArgsValid{Arguments valid?}
ArgsValid -- no --> LogErr[Log error / usage info] --> Stop1([stop]) ArgsValid -- no --> LogErr[Log error / usage info] --> Stop1([stop])

View File

@@ -1,3 +1,8 @@
---
config:
layout: elk
---
classDiagram classDiagram
class BiergartenPipelineOrchestrator { class BiergartenPipelineOrchestrator {
-shared_ptr~ILogger~ logger_ -shared_ptr~ILogger~ logger_

View File

@@ -1,4 +1,9 @@
flowchart TD ---
config:
layout: elk
---
flowchart LR
Start([start]) --> ParseArgs["Main: ParseArguments(argc, argv)"] Start([start]) --> ParseArgs["Main: ParseArguments(argc, argv)"]
ParseArgs --> InvalidArgs{Invalid args?} ParseArgs --> InvalidArgs{Invalid args?}
InvalidArgs -- yes --> LogErr["spdlog::error"] --> Stop1([stop]) InvalidArgs -- yes --> LogErr["spdlog::error"] --> Stop1([stop])

View File

@@ -1,3 +1,7 @@
---
config:
layout: elk
---
classDiagram classDiagram
namespace DomainModels { namespace DomainModels {
class Location { class Location {

View File

@@ -15,33 +15,51 @@ convention. For the vertical-slice code that talks to this schema, see
## Schema ## Schema
The full schema lives under The schema is split into six SQL Server schemas, one per feature area, each
`web/backend/Database/Database.Migrations/scripts/01-schema/` with one numbered living in its own numbered folder under
script per table. `web/backend/Database/Database.Migrations/scripts/`. The folder numbers
(`01`-`06`) fix the load order so foreign-key dependencies resolve — DbUp runs
embedded scripts in alphabetical-by-resource-name order, so e.g. `04-Brewery`
(which references `Auth`, `Geolocation`, and `Media`) runs after all three.
Each folder's `00-Schema.sql` creates its SQL schema before its tables run:
``` ```
01-schema scripts
├── 01-UserAccount.sql ├── 01-Auth (UserAccount, UserVerification, UserCredential)
├── 02-Photo.sql │ ├── 00-Schema.sql
├── 03-UserVerification.sql │ ├── 01-UserAccount.sql
├── 04-UserCredential.sql │ ├── 02-UserVerification.sql
├── 05-UserFollow.sql │ └── 03-UserCredential.sql
├── 06-Country.sql ├── 02-Geolocation (Country, StateProvince, City)
├── 07-StateProvince.sql │ ├── 00-Schema.sql
├── 08-City.sql │ ├── 01-Country.sql
├── 09-BreweryPost.sql │ ├── 02-StateProvince.sql
├── 10-BreweryPostLocation.sql │ └── 03-City.sql
├── 11-BreweryPostPhoto.sql ├── 03-Media (Photo)
├── 12-BeerStyle.sql │ ├── 00-Schema.sql
├── 13-BeerPost.sql │ └── 01-Photo.sql
├── 14-BeerPostPhoto.sql ├── 04-Brewery (BreweryPost, BreweryPostLocation, BreweryPostPhoto)
├── 15-BeerPostComment.sql │ ├── 00-Schema.sql
├── 16-UserProfile.sql │ ├── 01-BreweryPost.sql
└── 17-UserAvatar.sql │ ├── 02-BreweryPostLocation.sql
│ └── 03-BreweryPostPhoto.sql
├── 05-Beer (BeerStyle, BeerPost, BeerPostPhoto, BeerPostComment)
│ ├── 00-Schema.sql
│ ├── 01-BeerStyle.sql
│ ├── 02-BeerPost.sql
│ ├── 03-BeerPostPhoto.sql
│ └── 04-BeerPostComment.sql
└── 06-Social (UserFollow, UserProfile, UserAvatar)
├── 00-Schema.sql
├── 01-UserFollow.sql
├── 02-UserProfile.sql
└── 03-UserAvatar.sql
``` ```
Each script is run in order by `Database.Migrations` (DbUp) on startup. Each Each script is run in order by `Database.Migrations` (DbUp) on startup. Tables
table is queried directly by the owning feature slice's repository (see are referenced schema-qualified in code (e.g. `Auth.UserAccount`), not under
the default `dbo` schema. Each table is queried directly by the owning
feature slice's repository (see
[Direct SQL via Dapper/ADO.NET](architecture.md#direct-sql-via-dapperadonet)). [Direct SQL via Dapper/ADO.NET](architecture.md#direct-sql-via-dapperadonet)).
A generated DBML copy of the schema (for import into a diagramming tool such as A generated DBML copy of the schema (for import into a diagramming tool such as

View File

@@ -1,39 +1,46 @@
# Database Schema # Database Schema
Five diagrams, one per schema category — mirrors the `identity` / `media` / Six diagrams, one per SQL Server schema — mirrors the `Auth` / `Geolocation` /
`location` / `brewery` / `beer` schema split. Every table also has a `Media` / `Brewery` / `Beer` / `Social` schema split under
`web/backend/Database/Database.Migrations/scripts/`. Every table also has a
`RowVersion ROWVERSION` column (optimistic concurrency), omitted below for `RowVersion ROWVERSION` column (optimistic concurrency), omitted below for
brevity. Tables marked `(*)` have no repository/feature slice yet. brevity. Tables marked `(*)` have no repository/feature slice yet.
Boxes with no attribute list (e.g. `Photo` in the identity diagram) are owned by Boxes with no attribute list (e.g. `Photo` in the auth diagram) are owned by a
a different schema and shown only to keep the relationship visible; see the different schema and shown only to keep the relationship visible; see the
diagram named after that schema for its full definition. diagram named after that schema for its full definition.
## Identity (`identity`) ## Auth (`Auth`)
```mermaid ```mermaid
--8<-- "web/diagrams/database-schema/identity.mmd" --8<-- "web/diagrams/database-schema/auth.mmd"
``` ```
## Media (`media`) ## Social (`Social`)
```mermaid
--8<-- "web/diagrams/database-schema/social.mmd"
```
## Media (`Media`)
```mermaid ```mermaid
--8<-- "web/diagrams/database-schema/media.mmd" --8<-- "web/diagrams/database-schema/media.mmd"
``` ```
## Location (`location`) ## Geolocation (`Geolocation`)
```mermaid ```mermaid
--8<-- "web/diagrams/database-schema/location.mmd" --8<-- "web/diagrams/database-schema/geolocation.mmd"
``` ```
## Brewery (`brewery`) ## Brewery (`Brewery`)
```mermaid ```mermaid
--8<-- "web/diagrams/database-schema/brewery.mmd" --8<-- "web/diagrams/database-schema/brewery.mmd"
``` ```
## Beer (`beer`) ## Beer (`Beer`)
```mermaid ```mermaid
--8<-- "web/diagrams/database-schema/beer.mmd" --8<-- "web/diagrams/database-schema/beer.mmd"

View File

@@ -1,12 +1,16 @@
---
config:
layout: elk
---
erDiagram erDiagram
User ||--o{ Cred : "has credentials" User ||--o{ Cred : "has credentials"
User ||--o| Verify : "has verification" User ||--o| Verify : "has verification"
%% Cross-schema: defined in full in social.mmd / media.mmd / brewery.mmd / beer.mmd
User ||--o| Profile : "has profile" User ||--o| Profile : "has profile"
User ||--o{ Follow : "follows" User ||--o{ Follow : "follows"
User ||--o{ Follow : "followed by" User ||--o{ Follow : "followed by"
%% Cross-schema: defined in full in media.mmd / brewery.mmd / beer.mmd
Profile ||--o{ Avatar : "has avatar history"
User ||--o{ Photo : "uploads" User ||--o{ Photo : "uploads"
User ||--o{ Brewery : "posts" User ||--o{ Brewery : "posts"
User ||--o{ Beer : "posts" User ||--o{ Beer : "posts"
@@ -38,16 +42,3 @@ erDiagram
uniqueidentifier UserAccountID "FK, UK" uniqueidentifier UserAccountID "FK, UK"
datetime VerificationDateTime datetime VerificationDateTime
} }
Profile {
uniqueidentifier UserProfileID PK
uniqueidentifier UserAccountID "FK, UK"
nvarchar Biography
}
Follow {
uniqueidentifier UserFollowID PK
uniqueidentifier UserAccountID FK
uniqueidentifier FollowingID FK
datetime CreatedAt
}

View File

@@ -1,12 +1,18 @@
---
config:
layout: elk
---
erDiagram erDiagram
BeerStyle ||--o{ Beer : "categorizes" BeerStyle ||--o{ Beer : "categorizes"
Beer ||--o{ BeerPhoto : "has photos" Beer ||--o{ BeerPhoto : "has photos"
Beer ||--o{ BeerComment : "has comments" Beer ||--o{ BeerComment : "has comments"
%% Cross-schema: defined in full in identity.mmd / brewery.mmd / media.mmd %% Cross-schema: defined in full in auth.mmd / brewery.mmd / media.mmd
User ||--o{ Beer : "posts" User ||--o{ Beer : "posts"
Brewery ||--o{ Beer : "brews" Brewery ||--o{ Beer : "brews"
User ||--o{ BeerComment : "comments" User ||--o{ BeerComment : "comments"
BeerPhoto }o--|| Photo : "uses photo"
BeerStyle { BeerStyle {
uniqueidentifier BeerStyleID PK uniqueidentifier BeerStyleID PK
@@ -36,3 +42,10 @@ erDiagram
datetime CreatedAt datetime CreatedAt
datetime UpdatedAt "nullable" datetime UpdatedAt "nullable"
} }
BeerPhoto {
uniqueidentifier BeerPostPhotoID PK
uniqueidentifier BeerPostID FK
uniqueidentifier PhotoID FK
datetime LinkedAt
}

View File

@@ -1,10 +1,18 @@
---
config:
layout: elk
---
erDiagram erDiagram
Brewery ||--o| BreweryLoc : "has location" Brewery ||--o| BreweryLocation : "has location"
Brewery ||--o{ BreweryPhoto : "has photos" Brewery ||--o{ BreweryPhoto : "has photos"
Brewery ||--o{ Beer : "brews" Brewery ||--o{ Beer : "brews"
%% Cross-schema: defined in full in identity.mmd / location.mmd / media.mmd / beer.mmd %% Cross-schema: defined in full in auth.mmd / geolocation.mmd / media.mmd / beer.mmd
User ||--o{ Brewery : "posts" User ||--o{ Brewery : "posts"
BreweryLocation }o--|| City : "located in"
BreweryPhoto }o--|| Photo : "uses photo"
Brewery { Brewery {
uniqueidentifier BreweryPostID PK uniqueidentifier BreweryPostID PK
@@ -14,3 +22,20 @@ erDiagram
datetime CreatedAt datetime CreatedAt
datetime UpdatedAt "nullable" datetime UpdatedAt "nullable"
} }
BreweryLocation {
uniqueidentifier BreweryPostLocationID PK
uniqueidentifier BreweryPostID "FK, UK"
nvarchar AddressLine1
nvarchar AddressLine2 "nullable"
nvarchar PostalCode
uniqueidentifier CityID FK
geography Coordinates "nullable"
}
BreweryPhoto {
uniqueidentifier BreweryPostPhotoID PK
uniqueidentifier BreweryPostID FK
uniqueidentifier PhotoID FK
datetime LinkedAt
}

View File

@@ -1,10 +1,9 @@
erDiagram erDiagram
Country ||--o{ StateProvince : "has" Country ||--o{ StateProvince : "has"
StateProvince ||--o{ City : "has" StateProvince ||--o{ City : "has"
City ||--o{ BreweryLoc : "located in"
%% Cross-schema: defined in full in brewery.mmd %% Cross-schema: defined in full in brewery.mmd
Brewery ||--o| BreweryLoc : "has location" City ||--o{ BreweryLocation : "located in"
Country { Country {
uniqueidentifier CountryID PK uniqueidentifier CountryID PK
@@ -24,13 +23,3 @@ erDiagram
nvarchar CityName nvarchar CityName
uniqueidentifier StateProvinceID FK uniqueidentifier StateProvinceID FK
} }
BreweryLoc {
uniqueidentifier BreweryPostLocationID PK
uniqueidentifier BreweryPostID "FK, UK"
nvarchar AddressLine1
nvarchar AddressLine2 "nullable"
nvarchar PostalCode
uniqueidentifier CityID FK
geography Coordinates "nullable"
}

View File

@@ -1,39 +1,19 @@
---
config:
layout: elk
---
erDiagram erDiagram
User ||--o{ Photo : "uploads"
%% Cross-schema: defined in full in auth.mmd / social.mmd / brewery.mmd / beer.mmd
Avatar }o--|| Photo : "uses photo" Avatar }o--|| Photo : "uses photo"
Photo ||--o{ BreweryPhoto : "used in" Photo ||--o{ BreweryPhoto : "used in"
Photo ||--o{ BeerPhoto : "used in" Photo ||--o{ BeerPhoto : "used in"
%% Cross-schema: defined in full in identity.mmd / brewery.mmd / beer.mmd
Profile ||--o{ Avatar : "has avatar history"
User ||--o{ Photo : "uploads"
Brewery ||--o{ BreweryPhoto : "has photos"
Beer ||--o{ BeerPhoto : "has photos"
Photo { Photo {
uniqueidentifier PhotoID PK uniqueidentifier PhotoID PK
nvarchar Hyperlink "nullable" nvarchar Hyperlink "nullable"
uniqueidentifier UploadedByID FK uniqueidentifier UploadedByID FK
datetime UploadedAt datetime UploadedAt
} }
Avatar {
uniqueidentifier UserAvatarID PK
uniqueidentifier UserProfileID FK
uniqueidentifier PhotoID FK
datetime2 ValidFrom
datetime2 ValidTo "nullable; at most one row per UserProfileID has ValidTo IS NULL (active avatar)"
}
BreweryPhoto {
uniqueidentifier BreweryPostPhotoID PK
uniqueidentifier BreweryPostID FK
uniqueidentifier PhotoID FK
datetime LinkedAt
}
BeerPhoto {
uniqueidentifier BeerPostPhotoID PK
uniqueidentifier BeerPostID FK
uniqueidentifier PhotoID FK
datetime LinkedAt
}

View File

@@ -0,0 +1,34 @@
---
config:
layout: elk
---
erDiagram
User ||--o| Profile : "has profile"
User ||--o{ Follow : "follows"
User ||--o{ Follow : "followed by"
Profile ||--o{ Avatar : "has avatar history"
%% Cross-schema: defined in full in auth.mmd / media.mmd
Avatar }o--|| Photo : "uses photo"
Profile {
uniqueidentifier UserProfileID PK
uniqueidentifier UserAccountID "FK, UK"
nvarchar Biography
}
Follow {
uniqueidentifier UserFollowID PK
uniqueidentifier UserAccountID FK
uniqueidentifier FollowingID FK
datetime CreatedAt
}
Avatar {
uniqueidentifier UserAvatarID PK
uniqueidentifier UserProfileID FK
uniqueidentifier PhotoID FK
datetime2 ValidFrom
datetime2 ValidTo "nullable; at most one row per UserProfileID has ValidTo IS NULL (active avatar)"
}

View File

@@ -1,8 +1,6 @@
--- ---
config: config:
flowchart: layout: elk
curve: stepAfter
layout: elk
--- ---
flowchart TB flowchart TB

View File

@@ -1,7 +1,6 @@
--- ---
config: config:
flowchart: {} layout: elk
layout: fixed
--- ---
flowchart TB flowchart TB

View File

@@ -0,0 +1,2 @@
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = 'Auth')
EXEC('CREATE SCHEMA Auth');

View File

@@ -1,4 +1,4 @@
CREATE TABLE dbo.UserAccount CREATE TABLE Auth.UserAccount
( (
UserAccountID UNIQUEIDENTIFIER UserAccountID UNIQUEIDENTIFIER
CONSTRAINT DF_UserAccountID DEFAULT NEWID(), CONSTRAINT DF_UserAccountID DEFAULT NEWID(),

View File

@@ -1,4 +1,4 @@
CREATE TABLE UserVerification -- delete verification data when user account is deleted CREATE TABLE Auth.UserVerification -- delete verification data when user account is deleted
( (
UserVerificationID UNIQUEIDENTIFIER UserVerificationID UNIQUEIDENTIFIER
CONSTRAINT DF_UserVerificationID DEFAULT NEWID(), CONSTRAINT DF_UserVerificationID DEFAULT NEWID(),
@@ -15,7 +15,7 @@ CREATE TABLE UserVerification -- delete verification data when user account is d
CONSTRAINT FK_UserVerification_UserAccount CONSTRAINT FK_UserVerification_UserAccount
FOREIGN KEY (UserAccountID) FOREIGN KEY (UserAccountID)
REFERENCES UserAccount (UserAccountID) REFERENCES Auth.UserAccount (UserAccountID)
ON DELETE CASCADE, ON DELETE CASCADE,
CONSTRAINT AK_UserVerification_UserAccountID CONSTRAINT AK_UserVerification_UserAccountID
@@ -24,4 +24,4 @@ CREATE TABLE UserVerification -- delete verification data when user account is d
CREATE CREATE
NONCLUSTERED INDEX IX_UserVerification_UserAccount NONCLUSTERED INDEX IX_UserVerification_UserAccount
ON UserVerification(UserAccountID); ON Auth.UserVerification(UserAccountID);

View File

@@ -1,4 +1,4 @@
CREATE TABLE UserCredential -- delete credentials when user account is deleted CREATE TABLE Auth.UserCredential -- delete credentials when user account is deleted
( (
UserCredentialID UNIQUEIDENTIFIER UserCredentialID UNIQUEIDENTIFIER
CONSTRAINT DF_UserCredentialID DEFAULT NEWID(), CONSTRAINT DF_UserCredentialID DEFAULT NEWID(),
@@ -26,15 +26,15 @@ CREATE TABLE UserCredential -- delete credentials when user account is deleted
CONSTRAINT FK_UserCredential_UserAccount CONSTRAINT FK_UserCredential_UserAccount
FOREIGN KEY (UserAccountID) FOREIGN KEY (UserAccountID)
REFERENCES UserAccount (UserAccountID) REFERENCES Auth.UserAccount (UserAccountID)
ON DELETE CASCADE ON DELETE CASCADE
); );
CREATE CREATE
NONCLUSTERED INDEX IX_UserCredential_UserAccount NONCLUSTERED INDEX IX_UserCredential_UserAccount
ON UserCredential(UserAccountID); ON Auth.UserCredential(UserAccountID);
CREATE CREATE
NONCLUSTERED INDEX IX_UserCredential_Account_Active NONCLUSTERED INDEX IX_UserCredential_Account_Active
ON UserCredential(UserAccountID, IsRevoked, Expiry) ON Auth.UserCredential(UserAccountID, IsRevoked, Expiry)
INCLUDE (Hash); INCLUDE (Hash);

View File

@@ -0,0 +1,2 @@
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = 'Geolocation')
EXEC('CREATE SCHEMA Geolocation');

View File

@@ -1,4 +1,4 @@
CREATE TABLE Country CREATE TABLE Geolocation.Country
( (
CountryID UNIQUEIDENTIFIER CountryID UNIQUEIDENTIFIER
CONSTRAINT DF_CountryID DEFAULT NEWID(), CONSTRAINT DF_CountryID DEFAULT NEWID(),

View File

@@ -1,4 +1,4 @@
CREATE TABLE StateProvince CREATE TABLE Geolocation.StateProvince
( (
StateProvinceID UNIQUEIDENTIFIER StateProvinceID UNIQUEIDENTIFIER
CONSTRAINT DF_StateProvinceID DEFAULT NEWID(), CONSTRAINT DF_StateProvinceID DEFAULT NEWID(),
@@ -20,9 +20,9 @@ CREATE TABLE StateProvince
CONSTRAINT FK_StateProvince_Country CONSTRAINT FK_StateProvince_Country
FOREIGN KEY (CountryID) FOREIGN KEY (CountryID)
REFERENCES Country (CountryID) REFERENCES Geolocation.Country (CountryID)
); );
CREATE CREATE
NONCLUSTERED INDEX IX_StateProvince_Country NONCLUSTERED INDEX IX_StateProvince_Country
ON StateProvince(CountryID); ON Geolocation.StateProvince(CountryID);

View File

@@ -1,4 +1,4 @@
CREATE TABLE City CREATE TABLE Geolocation.City
( (
CityID UNIQUEIDENTIFIER CityID UNIQUEIDENTIFIER
CONSTRAINT DF_CityID DEFAULT NEWID(), CONSTRAINT DF_CityID DEFAULT NEWID(),
@@ -14,9 +14,9 @@ CREATE TABLE City
CONSTRAINT FK_City_StateProvince CONSTRAINT FK_City_StateProvince
FOREIGN KEY (StateProvinceID) FOREIGN KEY (StateProvinceID)
REFERENCES StateProvince (StateProvinceID) REFERENCES Geolocation.StateProvince (StateProvinceID)
); );
CREATE CREATE
NONCLUSTERED INDEX IX_City_StateProvince NONCLUSTERED INDEX IX_City_StateProvince
ON City(StateProvinceID); ON Geolocation.City(StateProvinceID);

View File

@@ -0,0 +1,2 @@
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = 'Media')
EXEC('CREATE SCHEMA Media');

View File

@@ -1,4 +1,4 @@
CREATE TABLE Photo -- All photos must be linked to a user account, you cannot delete a user account if they have uploaded photos CREATE TABLE Media.Photo -- All photos must be linked to a user account, you cannot delete a user account if they have uploaded photos
( (
PhotoID UNIQUEIDENTIFIER PhotoID UNIQUEIDENTIFIER
CONSTRAINT DF_PhotoID DEFAULT NEWID(), CONSTRAINT DF_PhotoID DEFAULT NEWID(),
@@ -18,10 +18,10 @@ CREATE TABLE Photo -- All photos must be linked to a user account, you cannot de
CONSTRAINT FK_Photo_UploadedBy CONSTRAINT FK_Photo_UploadedBy
FOREIGN KEY (UploadedByID) FOREIGN KEY (UploadedByID)
REFERENCES UserAccount (UserAccountID) REFERENCES Auth.UserAccount (UserAccountID)
ON DELETE NO ACTION ON DELETE NO ACTION
); );
CREATE CREATE
NONCLUSTERED INDEX IX_Photo_UploadedByID NONCLUSTERED INDEX IX_Photo_UploadedByID
ON Photo(UploadedByID); ON Media.Photo(UploadedByID);

View File

@@ -0,0 +1,2 @@
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = 'Brewery')
EXEC('CREATE SCHEMA Brewery');

View File

@@ -1,4 +1,4 @@
CREATE TABLE BreweryPost -- A user cannot be deleted if they have a post CREATE TABLE Brewery.BreweryPost -- A user cannot be deleted if they have a post
( (
BreweryPostID UNIQUEIDENTIFIER BreweryPostID UNIQUEIDENTIFIER
CONSTRAINT DF_BreweryPostID DEFAULT NEWID(), CONSTRAINT DF_BreweryPostID DEFAULT NEWID(),
@@ -21,10 +21,10 @@ CREATE TABLE BreweryPost -- A user cannot be deleted if they have a post
CONSTRAINT FK_BreweryPost_UserAccount CONSTRAINT FK_BreweryPost_UserAccount
FOREIGN KEY (PostedByID) FOREIGN KEY (PostedByID)
REFERENCES UserAccount (UserAccountID) REFERENCES Auth.UserAccount (UserAccountID)
ON DELETE NO ACTION ON DELETE NO ACTION
); );
CREATE CREATE
NONCLUSTERED INDEX IX_BreweryPost_PostedByID NONCLUSTERED INDEX IX_BreweryPost_PostedByID
ON BreweryPost(PostedByID); ON Brewery.BreweryPost(PostedByID);

View File

@@ -1,4 +1,4 @@
CREATE TABLE BreweryPostLocation CREATE TABLE Brewery.BreweryPostLocation
( (
BreweryPostLocationID UNIQUEIDENTIFIER BreweryPostLocationID UNIQUEIDENTIFIER
CONSTRAINT DF_BreweryPostLocationID DEFAULT NEWID(), CONSTRAINT DF_BreweryPostLocationID DEFAULT NEWID(),
@@ -25,24 +25,24 @@ CREATE TABLE BreweryPostLocation
CONSTRAINT FK_BreweryPostLocation_BreweryPost CONSTRAINT FK_BreweryPostLocation_BreweryPost
FOREIGN KEY (BreweryPostID) FOREIGN KEY (BreweryPostID)
REFERENCES BreweryPost (BreweryPostID) REFERENCES Brewery.BreweryPost (BreweryPostID)
ON DELETE CASCADE, ON DELETE CASCADE,
CONSTRAINT FK_BreweryPostLocation_City CONSTRAINT FK_BreweryPostLocation_City
FOREIGN KEY (CityID) FOREIGN KEY (CityID)
REFERENCES City (CityID) REFERENCES Geolocation.City (CityID)
); );
CREATE CREATE
NONCLUSTERED INDEX IX_BreweryPostLocation_BreweryPost NONCLUSTERED INDEX IX_BreweryPostLocation_BreweryPost
ON BreweryPostLocation(BreweryPostID); ON Brewery.BreweryPostLocation(BreweryPostID);
CREATE CREATE
NONCLUSTERED INDEX IX_BreweryPostLocation_City NONCLUSTERED INDEX IX_BreweryPostLocation_City
ON BreweryPostLocation(CityID); ON Brewery.BreweryPostLocation(CityID);
CREATE SPATIAL INDEX SIDX_BreweryPostLocation_Coordinates CREATE SPATIAL INDEX SIDX_BreweryPostLocation_Coordinates
ON BreweryPostLocation(Coordinates) ON Brewery.BreweryPostLocation(Coordinates)
USING GEOGRAPHY_GRID USING GEOGRAPHY_GRID
WITH ( WITH (
GRIDS = (LEVEL_1 = MEDIUM, LEVEL_2 = MEDIUM, LEVEL_3 = MEDIUM, LEVEL_4 = MEDIUM), GRIDS = (LEVEL_1 = MEDIUM, LEVEL_2 = MEDIUM, LEVEL_3 = MEDIUM, LEVEL_4 = MEDIUM),

View File

@@ -1,4 +1,4 @@
CREATE TABLE BreweryPostPhoto -- All photos linked to a post are deleted if the post is deleted CREATE TABLE Brewery.BreweryPostPhoto -- All photos linked to a post are deleted if the post is deleted
( (
BreweryPostPhotoID UNIQUEIDENTIFIER BreweryPostPhotoID UNIQUEIDENTIFIER
CONSTRAINT DF_BreweryPostPhotoID DEFAULT NEWID(), CONSTRAINT DF_BreweryPostPhotoID DEFAULT NEWID(),
@@ -17,19 +17,19 @@ CREATE TABLE BreweryPostPhoto -- All photos linked to a post are deleted if the
CONSTRAINT FK_BreweryPostPhoto_BreweryPost CONSTRAINT FK_BreweryPostPhoto_BreweryPost
FOREIGN KEY (BreweryPostID) FOREIGN KEY (BreweryPostID)
REFERENCES BreweryPost (BreweryPostID) REFERENCES Brewery.BreweryPost (BreweryPostID)
ON DELETE CASCADE, ON DELETE CASCADE,
CONSTRAINT FK_BreweryPostPhoto_Photo CONSTRAINT FK_BreweryPostPhoto_Photo
FOREIGN KEY (PhotoID) FOREIGN KEY (PhotoID)
REFERENCES Photo (PhotoID) REFERENCES Media.Photo (PhotoID)
ON DELETE CASCADE ON DELETE CASCADE
); );
CREATE CREATE
NONCLUSTERED INDEX IX_BreweryPostPhoto_Photo_BreweryPost NONCLUSTERED INDEX IX_BreweryPostPhoto_Photo_BreweryPost
ON BreweryPostPhoto(PhotoID, BreweryPostID); ON Brewery.BreweryPostPhoto(PhotoID, BreweryPostID);
CREATE CREATE
NONCLUSTERED INDEX IX_BreweryPostPhoto_BreweryPost_Photo NONCLUSTERED INDEX IX_BreweryPostPhoto_BreweryPost_Photo
ON BreweryPostPhoto(BreweryPostID, PhotoID); ON Brewery.BreweryPostPhoto(BreweryPostID, PhotoID);

View File

@@ -0,0 +1,2 @@
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = 'Beer')
EXEC('CREATE SCHEMA Beer');

View File

@@ -1,4 +1,4 @@
CREATE TABLE BeerStyle CREATE TABLE Beer.BeerStyle
( (
BeerStyleID UNIQUEIDENTIFIER BeerStyleID UNIQUEIDENTIFIER
CONSTRAINT DF_BeerStyleID DEFAULT NEWID(), CONSTRAINT DF_BeerStyleID DEFAULT NEWID(),

View File

@@ -1,4 +1,4 @@
CREATE TABLE BeerPost CREATE TABLE Beer.BeerPost
( (
BeerPostID UNIQUEIDENTIFIER BeerPostID UNIQUEIDENTIFIER
CONSTRAINT DF_BeerPostID DEFAULT NEWID(), CONSTRAINT DF_BeerPostID DEFAULT NEWID(),
@@ -31,16 +31,16 @@ CREATE TABLE BeerPost
CONSTRAINT FK_BeerPost_PostedBy CONSTRAINT FK_BeerPost_PostedBy
FOREIGN KEY (PostedByID) FOREIGN KEY (PostedByID)
REFERENCES UserAccount (UserAccountID) REFERENCES Auth.UserAccount (UserAccountID)
ON DELETE NO ACTION, ON DELETE NO ACTION,
CONSTRAINT FK_BeerPost_BeerStyle CONSTRAINT FK_BeerPost_BeerStyle
FOREIGN KEY (BeerStyleID) FOREIGN KEY (BeerStyleID)
REFERENCES BeerStyle (BeerStyleID), REFERENCES Beer.BeerStyle (BeerStyleID),
CONSTRAINT FK_BeerPost_Brewery CONSTRAINT FK_BeerPost_Brewery
FOREIGN KEY (BrewedByID) FOREIGN KEY (BrewedByID)
REFERENCES BreweryPost (BreweryPostID), REFERENCES Brewery.BreweryPost (BreweryPostID),
CONSTRAINT CHK_BeerPost_ABV CONSTRAINT CHK_BeerPost_ABV
CHECK (ABV >= 0 AND ABV <= 67), CHECK (ABV >= 0 AND ABV <= 67),
@@ -51,12 +51,12 @@ CREATE TABLE BeerPost
CREATE CREATE
NONCLUSTERED INDEX IX_BeerPost_PostedBy NONCLUSTERED INDEX IX_BeerPost_PostedBy
ON BeerPost(PostedByID); ON Beer.BeerPost(PostedByID);
CREATE CREATE
NONCLUSTERED INDEX IX_BeerPost_BeerStyle NONCLUSTERED INDEX IX_BeerPost_BeerStyle
ON BeerPost(BeerStyleID); ON Beer.BeerPost(BeerStyleID);
CREATE CREATE
NONCLUSTERED INDEX IX_BeerPost_BrewedBy NONCLUSTERED INDEX IX_BeerPost_BrewedBy
ON BeerPost(BrewedByID); ON Beer.BeerPost(BrewedByID);

View File

@@ -1,4 +1,4 @@
CREATE TABLE BeerPostPhoto -- All photos linked to a beer post are deleted if the post is deleted CREATE TABLE Beer.BeerPostPhoto -- All photos linked to a beer post are deleted if the post is deleted
( (
BeerPostPhotoID UNIQUEIDENTIFIER BeerPostPhotoID UNIQUEIDENTIFIER
CONSTRAINT DF_BeerPostPhotoID DEFAULT NEWID(), CONSTRAINT DF_BeerPostPhotoID DEFAULT NEWID(),
@@ -17,19 +17,19 @@ CREATE TABLE BeerPostPhoto -- All photos linked to a beer post are deleted if th
CONSTRAINT FK_BeerPostPhoto_BeerPost CONSTRAINT FK_BeerPostPhoto_BeerPost
FOREIGN KEY (BeerPostID) FOREIGN KEY (BeerPostID)
REFERENCES BeerPost (BeerPostID) REFERENCES Beer.BeerPost (BeerPostID)
ON DELETE CASCADE, ON DELETE CASCADE,
CONSTRAINT FK_BeerPostPhoto_Photo CONSTRAINT FK_BeerPostPhoto_Photo
FOREIGN KEY (PhotoID) FOREIGN KEY (PhotoID)
REFERENCES Photo (PhotoID) REFERENCES Media.Photo (PhotoID)
ON DELETE CASCADE ON DELETE CASCADE
); );
CREATE CREATE
NONCLUSTERED INDEX IX_BeerPostPhoto_Photo_BeerPost NONCLUSTERED INDEX IX_BeerPostPhoto_Photo_BeerPost
ON BeerPostPhoto(PhotoID, BeerPostID); ON Beer.BeerPostPhoto(PhotoID, BeerPostID);
CREATE CREATE
NONCLUSTERED INDEX IX_BeerPostPhoto_BeerPost_Photo NONCLUSTERED INDEX IX_BeerPostPhoto_BeerPost_Photo
ON BeerPostPhoto(BeerPostID, PhotoID); ON Beer.BeerPostPhoto(BeerPostID, PhotoID);

View File

@@ -1,4 +1,4 @@
CREATE TABLE BeerPostComment CREATE TABLE Beer.BeerPostComment
( (
BeerPostCommentID UNIQUEIDENTIFIER BeerPostCommentID UNIQUEIDENTIFIER
CONSTRAINT DF_BeerPostComment DEFAULT NEWID(), CONSTRAINT DF_BeerPostComment DEFAULT NEWID(),
@@ -23,11 +23,11 @@ CREATE TABLE BeerPostComment
CONSTRAINT FK_BeerPostComment_BeerPost CONSTRAINT FK_BeerPostComment_BeerPost
FOREIGN KEY (BeerPostID) FOREIGN KEY (BeerPostID)
REFERENCES BeerPost (BeerPostID), REFERENCES Beer.BeerPost (BeerPostID),
CONSTRAINT FK_BeerPostComment_UserAccount CONSTRAINT FK_BeerPostComment_UserAccount
FOREIGN KEY (CommentedByID) FOREIGN KEY (CommentedByID)
REFERENCES UserAccount (UserAccountID) REFERENCES Auth.UserAccount (UserAccountID)
ON DELETE NO ACTION, ON DELETE NO ACTION,
CONSTRAINT CHK_BeerPostComment_Rating CONSTRAINT CHK_BeerPostComment_Rating
@@ -36,8 +36,8 @@ CREATE TABLE BeerPostComment
CREATE CREATE
NONCLUSTERED INDEX IX_BeerPostComment_BeerPost NONCLUSTERED INDEX IX_BeerPostComment_BeerPost
ON BeerPostComment(BeerPostID); ON Beer.BeerPostComment(BeerPostID);
CREATE CREATE
NONCLUSTERED INDEX IX_BeerPostComment_CommentedBy NONCLUSTERED INDEX IX_BeerPostComment_CommentedBy
ON BeerPostComment(CommentedByID); ON Beer.BeerPostComment(CommentedByID);

View File

@@ -0,0 +1,2 @@
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = 'Social')
EXEC('CREATE SCHEMA Social');

View File

@@ -1,4 +1,4 @@
CREATE TABLE UserFollow CREATE TABLE Social.UserFollow
( (
UserFollowID UNIQUEIDENTIFIER UserFollowID UNIQUEIDENTIFIER
CONSTRAINT DF_UserFollowID DEFAULT NEWID(), CONSTRAINT DF_UserFollowID DEFAULT NEWID(),
@@ -17,12 +17,12 @@ CREATE TABLE UserFollow
CONSTRAINT FK_UserFollow_UserAccount CONSTRAINT FK_UserFollow_UserAccount
FOREIGN KEY (UserAccountID) FOREIGN KEY (UserAccountID)
REFERENCES UserAccount (UserAccountID) REFERENCES Auth.UserAccount (UserAccountID)
ON DELETE NO ACTION, ON DELETE NO ACTION,
CONSTRAINT FK_UserFollow_UserAccountFollowing CONSTRAINT FK_UserFollow_UserAccountFollowing
FOREIGN KEY (FollowingID) FOREIGN KEY (FollowingID)
REFERENCES UserAccount (UserAccountID) REFERENCES Auth.UserAccount (UserAccountID)
ON DELETE NO ACTION, ON DELETE NO ACTION,
CONSTRAINT CK_CannotFollowOwnAccount CONSTRAINT CK_CannotFollowOwnAccount
@@ -32,8 +32,8 @@ CREATE TABLE UserFollow
CREATE CREATE
NONCLUSTERED INDEX IX_UserFollow_UserAccount_FollowingID NONCLUSTERED INDEX IX_UserFollow_UserAccount_FollowingID
ON UserFollow(UserAccountID, FollowingID); ON Social.UserFollow(UserAccountID, FollowingID);
CREATE CREATE
NONCLUSTERED INDEX IX_UserFollow_FollowingID_UserAccount NONCLUSTERED INDEX IX_UserFollow_FollowingID_UserAccount
ON UserFollow(FollowingID, UserAccountID); ON Social.UserFollow(FollowingID, UserAccountID);

View File

@@ -1,4 +1,4 @@
CREATE TABLE dbo.UserProfile CREATE TABLE Social.UserProfile
( (
UserProfileID UNIQUEIDENTIFIER UserProfileID UNIQUEIDENTIFIER
CONSTRAINT DF_UserProfileID DEFAULT NEWID(), CONSTRAINT DF_UserProfileID DEFAULT NEWID(),
@@ -17,6 +17,6 @@ CREATE TABLE dbo.UserProfile
CONSTRAINT FK_UserProfile_UserAccount CONSTRAINT FK_UserProfile_UserAccount
FOREIGN KEY (UserAccountID) FOREIGN KEY (UserAccountID)
REFERENCES UserAccount (UserAccountID) REFERENCES Auth.UserAccount (UserAccountID)
ON DELETE CASCADE ON DELETE CASCADE
); );

View File

@@ -1,4 +1,4 @@
CREATE TABLE dbo.UserAvatar CREATE TABLE Social.UserAvatar
( (
UserAvatarID UNIQUEIDENTIFIER UserAvatarID UNIQUEIDENTIFIER
CONSTRAINT DF_UserAvatarID DEFAULT NEWID(), CONSTRAINT DF_UserAvatarID DEFAULT NEWID(),
@@ -18,12 +18,12 @@ CREATE TABLE dbo.UserAvatar
CONSTRAINT FK_UserAvatar_UserProfile CONSTRAINT FK_UserAvatar_UserProfile
FOREIGN KEY (UserProfileID) FOREIGN KEY (UserProfileID)
REFERENCES dbo.UserProfile (UserProfileID) REFERENCES Social.UserProfile (UserProfileID)
ON DELETE CASCADE, ON DELETE CASCADE,
CONSTRAINT FK_UserAvatar_Photo CONSTRAINT FK_UserAvatar_Photo
FOREIGN KEY (PhotoID) FOREIGN KEY (PhotoID)
REFERENCES dbo.Photo (PhotoID) REFERENCES Media.Photo (PhotoID)
ON DELETE NO ACTION ON DELETE NO ACTION
ON UPDATE NO ACTION, ON UPDATE NO ACTION,
@@ -33,11 +33,11 @@ CREATE TABLE dbo.UserAvatar
-- At most one active avatar per profile -- At most one active avatar per profile
CREATE UNIQUE NONCLUSTERED INDEX UX_UserAvatar_ActiveOne CREATE UNIQUE NONCLUSTERED INDEX UX_UserAvatar_ActiveOne
ON dbo.UserAvatar (UserProfileID) ON Social.UserAvatar (UserProfileID)
WHERE ValidTo IS NULL; WHERE ValidTo IS NULL;
CREATE NONCLUSTERED INDEX IX_UserAvatar_Photo CREATE NONCLUSTERED INDEX IX_UserAvatar_Photo
ON dbo.UserAvatar (PhotoID); ON Social.UserAvatar (PhotoID);
CREATE NONCLUSTERED INDEX ix_UserAvatar_Profile CREATE NONCLUSTERED INDEX ix_UserAvatar_Profile
ON dbo.UserAvatar (UserProfileID) ON Social.UserAvatar (UserProfileID)

View File

@@ -62,11 +62,11 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
co.CountryID, co.CountryID,
co.CountryName, co.CountryName,
co.ISO3166_1 AS Iso31661 co.ISO3166_1 AS Iso31661
FROM dbo.BreweryPost bp FROM Brewery.BreweryPost bp
LEFT JOIN dbo.BreweryPostLocation bpl ON bp.BreweryPostID = bpl.BreweryPostID LEFT JOIN Brewery.BreweryPostLocation bpl ON bp.BreweryPostID = bpl.BreweryPostID
LEFT JOIN dbo.City c ON bpl.CityID = c.CityID LEFT JOIN Geolocation.City c ON bpl.CityID = c.CityID
LEFT JOIN dbo.StateProvince sp ON c.StateProvinceID = sp.StateProvinceID LEFT JOIN Geolocation.StateProvince sp ON c.StateProvinceID = sp.StateProvinceID
LEFT JOIN dbo.Country co ON sp.CountryID = co.CountryID LEFT JOIN Geolocation.Country co ON sp.CountryID = co.CountryID
WHERE bp.BreweryPostID = @BreweryPostId WHERE bp.BreweryPostID = @BreweryPostId
""", """,
new { BreweryPostId = id }, new { BreweryPostId = id },
@@ -85,7 +85,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
await using DbConnection connection = await CreateConnection(); await using DbConnection connection = await CreateConnection();
return await connection.ExecuteScalarAsync<Guid?>( return await connection.ExecuteScalarAsync<Guid?>(
new CommandDefinition( new CommandDefinition(
"SELECT PostedByID FROM dbo.BreweryPost WHERE BreweryPostID = @BreweryPostId", "SELECT PostedByID FROM Brewery.BreweryPost WHERE BreweryPostID = @BreweryPostId",
new { BreweryPostId = id }, new { BreweryPostId = id },
cancellationToken: cancellationToken cancellationToken: cancellationToken
) )
@@ -126,11 +126,11 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
co.CountryID, co.CountryID,
co.CountryName, co.CountryName,
co.ISO3166_1 AS Iso31661 co.ISO3166_1 AS Iso31661
FROM dbo.BreweryPost bp FROM Brewery.BreweryPost bp
LEFT JOIN dbo.BreweryPostLocation bpl ON bp.BreweryPostID = bpl.BreweryPostID LEFT JOIN Brewery.BreweryPostLocation bpl ON bp.BreweryPostID = bpl.BreweryPostID
LEFT JOIN dbo.City c ON bpl.CityID = c.CityID LEFT JOIN Geolocation.City c ON bpl.CityID = c.CityID
LEFT JOIN dbo.StateProvince sp ON c.StateProvinceID = sp.StateProvinceID LEFT JOIN Geolocation.StateProvince sp ON c.StateProvinceID = sp.StateProvinceID
LEFT JOIN dbo.Country co ON sp.CountryID = co.CountryID LEFT JOIN Geolocation.Country co ON sp.CountryID = co.CountryID
ORDER BY bp.CreatedAt DESC ORDER BY bp.CreatedAt DESC
OFFSET @Offset ROWS FETCH NEXT @Limit ROWS ONLY OFFSET @Offset ROWS FETCH NEXT @Limit ROWS ONLY
""", """,
@@ -173,11 +173,11 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
co.CountryName, co.CountryName,
co.ISO3166_1 AS Iso31661, co.ISO3166_1 AS Iso31661,
bpl.Coordinates.STDistance(@Origin) AS DistanceMetres bpl.Coordinates.STDistance(@Origin) AS DistanceMetres
FROM dbo.BreweryPost bp FROM Brewery.BreweryPost bp
INNER JOIN dbo.BreweryPostLocation bpl ON bp.BreweryPostID = bpl.BreweryPostID INNER JOIN Brewery.BreweryPostLocation bpl ON bp.BreweryPostID = bpl.BreweryPostID
LEFT JOIN dbo.City c ON bpl.CityID = c.CityID LEFT JOIN Geolocation.City c ON bpl.CityID = c.CityID
LEFT JOIN dbo.StateProvince sp ON c.StateProvinceID = sp.StateProvinceID LEFT JOIN Geolocation.StateProvince sp ON c.StateProvinceID = sp.StateProvinceID
LEFT JOIN dbo.Country co ON sp.CountryID = co.CountryID LEFT JOIN Geolocation.Country co ON sp.CountryID = co.CountryID
WHERE bpl.Coordinates IS NOT NULL WHERE bpl.Coordinates IS NOT NULL
AND bpl.Coordinates.STDistance(@Origin) <= @RangeInMetres AND bpl.Coordinates.STDistance(@Origin) <= @RangeInMetres
ORDER BY bpl.Coordinates.STDistance(@Origin) ASC ORDER BY bpl.Coordinates.STDistance(@Origin) ASC
@@ -223,11 +223,11 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
co.CountryID, co.CountryID,
co.CountryName, co.CountryName,
co.ISO3166_1 AS Iso31661 co.ISO3166_1 AS Iso31661
FROM dbo.BreweryPost bp FROM Brewery.BreweryPost bp
INNER JOIN dbo.BreweryPostLocation bpl ON bp.BreweryPostID = bpl.BreweryPostID INNER JOIN Brewery.BreweryPostLocation bpl ON bp.BreweryPostID = bpl.BreweryPostID
LEFT JOIN dbo.City c ON bpl.CityID = c.CityID LEFT JOIN Geolocation.City c ON bpl.CityID = c.CityID
LEFT JOIN dbo.StateProvince sp ON c.StateProvinceID = sp.StateProvinceID LEFT JOIN Geolocation.StateProvince sp ON c.StateProvinceID = sp.StateProvinceID
LEFT JOIN dbo.Country co ON sp.CountryID = co.CountryID LEFT JOIN Geolocation.Country co ON sp.CountryID = co.CountryID
WHERE bpl.Coordinates IS NOT NULL WHERE bpl.Coordinates IS NOT NULL
ORDER BY bp.BreweryPostID ASC ORDER BY bp.BreweryPostID ASC
""", """,
@@ -249,7 +249,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
new CommandDefinition( new CommandDefinition(
""" """
SELECT 1 FROM SELECT 1 FROM
dbo.BreweryPost Brewery.BreweryPost
WHERE WHERE
BreweryPostID = @BreweryPostId BreweryPostID = @BreweryPostId
""", """,
@@ -268,7 +268,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
bool cityExists = bool cityExists =
await connection.ExecuteScalarAsync<int?>( await connection.ExecuteScalarAsync<int?>(
new CommandDefinition( new CommandDefinition(
"SELECT 1 FROM dbo.City WHERE CityID = @CityId", "SELECT 1 FROM Geolocation.City WHERE CityID = @CityId",
new { brewery.Location.CityId }, new { brewery.Location.CityId },
transaction, transaction,
cancellationToken: cancellationToken cancellationToken: cancellationToken
@@ -283,7 +283,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
int updatedRows = await connection.ExecuteAsync( int updatedRows = await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
UPDATE dbo.BreweryPost UPDATE Brewery.BreweryPost
SET BreweryName = @BreweryName, SET BreweryName = @BreweryName,
Description = @Description, Description = @Description,
UpdatedAt = GETDATE() UpdatedAt = GETDATE()
@@ -315,7 +315,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
new CommandDefinition( new CommandDefinition(
""" """
DELETE FROM DELETE FROM
dbo.BreweryPostLocation Brewery.BreweryPostLocation
WHERE BreweryPostID = @BreweryPostId WHERE BreweryPostID = @BreweryPostId
""", """,
new { brewery.BreweryPostId }, new { brewery.BreweryPostId },
@@ -331,7 +331,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
new CommandDefinition( new CommandDefinition(
""" """
SELECT 1 SELECT 1
FROM dbo.BreweryPostLocation FROM Brewery.BreweryPostLocation
WHERE BreweryPostID = @BreweryPostId WHERE BreweryPostID = @BreweryPostId
""", """,
new { brewery.BreweryPostId }, new { brewery.BreweryPostId },
@@ -345,7 +345,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
await connection.ExecuteAsync( await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
UPDATE dbo.BreweryPostLocation UPDATE Brewery.BreweryPostLocation
SET CityID = @CityId, SET CityID = @CityId,
AddressLine1 = @AddressLine1, AddressLine1 = @AddressLine1,
AddressLine2 = @AddressLine2, AddressLine2 = @AddressLine2,
@@ -375,7 +375,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
await connection.ExecuteAsync( await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
INSERT INTO dbo.BreweryPostLocation INSERT INTO Brewery.BreweryPostLocation
(BreweryPostLocationID, (BreweryPostLocationID,
BreweryPostID, BreweryPostID,
CityID, CityID,
@@ -434,7 +434,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
int rows = await connection.ExecuteAsync( int rows = await connection.ExecuteAsync(
""" """
DELETE FROM DELETE FROM
dbo.BreweryPost Brewery.BreweryPost
WHERE WHERE
BreweryPostID = @BreweryPostId BreweryPostID = @BreweryPostId
""", """,
@@ -462,7 +462,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
""" """
SELECT 1 SELECT 1
FROM FROM
dbo.UserAccount Auth.UserAccount
WHERE WHERE
UserAccountID = @PostedById UserAccountID = @PostedById
""", """,
@@ -481,7 +481,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
""" """
SELECT 1 SELECT 1
FROM FROM
dbo.City Geolocation.City
WHERE WHERE
CityID = @CityId CityID = @CityId
""", """,
@@ -497,7 +497,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
await connection.ExecuteAsync( await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
INSERT INTO dbo.BreweryPost INSERT INTO Brewery.BreweryPost
(BreweryPostID, BreweryName, Description, PostedByID) (BreweryPostID, BreweryName, Description, PostedByID)
VALUES VALUES
(@BreweryPostId, @BreweryName, @Description, @PostedById) (@BreweryPostId, @BreweryName, @Description, @PostedById)
@@ -516,7 +516,7 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
await connection.ExecuteAsync( await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
INSERT INTO dbo.BreweryPostLocation INSERT INTO Brewery.BreweryPostLocation
(BreweryPostLocationID, (BreweryPostLocationID,
BreweryPostID, BreweryPostID,
CityID, CityID,

View File

@@ -46,7 +46,7 @@ public class LocationRepository(ISqlConnectionFactory connectionFactory)
await connection.ExecuteScalarAsync<int?>( await connection.ExecuteScalarAsync<int?>(
""" """
SELECT 1 SELECT 1
FROM dbo.City FROM Geolocation.City
WHERE CityName = @CityName AND StateProvinceID = @StateProvinceId WHERE CityName = @CityName AND StateProvinceID = @StateProvinceId
""", """,
new { location.CityName, StateProvinceId = stateProvinceId } new { location.CityName, StateProvinceId = stateProvinceId }
@@ -56,7 +56,7 @@ public class LocationRepository(ISqlConnectionFactory connectionFactory)
if (!cityExists) if (!cityExists)
await connection.ExecuteAsync( await connection.ExecuteAsync(
""" """
INSERT INTO dbo.City (StateProvinceID, CityName) INSERT INTO Geolocation.City (StateProvinceID, CityName)
VALUES (@StateProvinceId, @CityName) VALUES (@StateProvinceId, @CityName)
""", """,
new { StateProvinceId = stateProvinceId, location.CityName } new { StateProvinceId = stateProvinceId, location.CityName }
@@ -79,7 +79,7 @@ public class LocationRepository(ISqlConnectionFactory connectionFactory)
await connection.ExecuteScalarAsync<int?>( await connection.ExecuteScalarAsync<int?>(
""" """
SELECT 1 SELECT 1
FROM dbo.Country FROM Geolocation.Country
WHERE ISO3166_1 = @ISO3166_1 WHERE ISO3166_1 = @ISO3166_1
""", """,
new { ISO3166_1 = isoCode } new { ISO3166_1 = isoCode }
@@ -91,7 +91,7 @@ public class LocationRepository(ISqlConnectionFactory connectionFactory)
// race is tolerated (the resulting duplicate row, if any, is out of scope for this method). // race is tolerated (the resulting duplicate row, if any, is out of scope for this method).
await connection.ExecuteAsync( await connection.ExecuteAsync(
""" """
INSERT INTO dbo.Country (CountryName, ISO3166_1) INSERT INTO Geolocation.Country (CountryName, ISO3166_1)
VALUES (@CountryName, @ISO3166_1) VALUES (@CountryName, @ISO3166_1)
""", """,
new { CountryName = countryName, ISO3166_1 = isoCode } new { CountryName = countryName, ISO3166_1 = isoCode }
@@ -125,7 +125,7 @@ public class LocationRepository(ISqlConnectionFactory connectionFactory)
await connection.ExecuteScalarAsync<int?>( await connection.ExecuteScalarAsync<int?>(
""" """
SELECT 1 SELECT 1
FROM dbo.StateProvince FROM Geolocation.StateProvince
WHERE ISO3166_2 = @ISO3166_2 WHERE ISO3166_2 = @ISO3166_2
""", """,
new { ISO3166_2 = isoCode } new { ISO3166_2 = isoCode }
@@ -135,7 +135,7 @@ public class LocationRepository(ISqlConnectionFactory connectionFactory)
if (!exists) if (!exists)
await connection.ExecuteAsync( await connection.ExecuteAsync(
""" """
INSERT INTO dbo.StateProvince (StateProvinceName, ISO3166_2, CountryID) INSERT INTO Geolocation.StateProvince (StateProvinceName, ISO3166_2, CountryID)
VALUES (@StateProvinceName, @ISO3166_2, @CountryId) VALUES (@StateProvinceName, @ISO3166_2, @CountryId)
""", """,
new new
@@ -153,7 +153,7 @@ public class LocationRepository(ISqlConnectionFactory connectionFactory)
return await connection.ExecuteScalarAsync<Guid?>( return await connection.ExecuteScalarAsync<Guid?>(
""" """
SELECT CountryID SELECT CountryID
FROM dbo.Country FROM Geolocation.Country
WHERE ISO3166_1 = @ISO3166_1 WHERE ISO3166_1 = @ISO3166_1
""", """,
new { ISO3166_1 = isoCode } new { ISO3166_1 = isoCode }
@@ -166,7 +166,7 @@ public class LocationRepository(ISqlConnectionFactory connectionFactory)
return await connection.ExecuteScalarAsync<Guid?>( return await connection.ExecuteScalarAsync<Guid?>(
""" """
SELECT StateProvinceID SELECT StateProvinceID
FROM dbo.StateProvince FROM Geolocation.StateProvince
WHERE ISO3166_2 = @ISO3166_2 WHERE ISO3166_2 = @ISO3166_2
""", """,
new { ISO3166_2 = isoCode } new { ISO3166_2 = isoCode }
@@ -179,8 +179,8 @@ public class LocationRepository(ISqlConnectionFactory connectionFactory)
return await connection.ExecuteScalarAsync<Guid?>( return await connection.ExecuteScalarAsync<Guid?>(
""" """
SELECT c.CityID SELECT c.CityID
FROM dbo.City c FROM Geolocation.City c
INNER JOIN dbo.StateProvince sp ON sp.StateProvinceID = c.StateProvinceID INNER JOIN Geolocation.StateProvince sp ON sp.StateProvinceID = c.StateProvinceID
WHERE c.CityName = @CityName AND sp.ISO3166_2 = @StateProvinceCode WHERE c.CityName = @CityName AND sp.ISO3166_2 = @StateProvinceCode
""", """,
new { CityName = cityName, StateProvinceCode = stateProvinceIsoCode } new { CityName = cityName, StateProvinceCode = stateProvinceIsoCode }

View File

@@ -28,7 +28,7 @@ public class PhotoUploadRepository(ISqlConnectionFactory connectionFactory)
""" """
SELECT 1 SELECT 1
FROM FROM
dbo.UserAccount Auth.UserAccount
WHERE WHERE
UserAccountID = @UploadedById UserAccountID = @UploadedById
""", """,
@@ -44,7 +44,7 @@ public class PhotoUploadRepository(ISqlConnectionFactory connectionFactory)
await connection.ExecuteAsync( await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
INSERT INTO dbo.Photo (PhotoID, Hyperlink, UploadedByID) INSERT INTO Media.Photo (PhotoID, Hyperlink, UploadedByID)
VALUES (@PhotoId, @Hyperlink, @UploadedById) VALUES (@PhotoId, @Hyperlink, @UploadedById)
""", """,
new { photo.PhotoId, photo.Hyperlink, photo.UploadedById }, new { photo.PhotoId, photo.Hyperlink, photo.UploadedById },

View File

@@ -8,8 +8,8 @@ namespace Features.Auth.Identity;
/// <summary> /// <summary>
/// Dapper-based implementation of the ASP.NET Core Identity store interfaces consumed by /// Dapper-based implementation of the ASP.NET Core Identity store interfaces consumed by
/// <see cref="UserManager{TUser}" />, persisting against the existing <c>dbo.UserAccount</c>, /// <see cref="UserManager{TUser}" />, persisting against the existing <c>Auth.UserAccount</c>,
/// <c>dbo.UserCredential</c>, and <c>dbo.UserVerification</c> tables. No EF Core is used, and no schema /// <c>Auth.UserCredential</c>, and <c>Auth.UserVerification</c> tables. No EF Core is used, and no schema
/// changes were required: normalized name/email are computed on the fly rather than persisted (the /// changes were required: normalized name/email are computed on the fly rather than persisted (the
/// existing unique indexes are already case-insensitive under SQL Server's default collation). /// existing unique indexes are already case-insensitive under SQL Server's default collation).
/// </summary> /// </summary>
@@ -21,7 +21,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
{ {
private const string SelectUserSql = """ private const string SelectUserSql = """
SELECT UserAccountID AS Id, Username AS UserName, FirstName, LastName, Email, DateOfBirth SELECT UserAccountID AS Id, Username AS UserName, FirstName, LastName, Email, DateOfBirth
FROM dbo.UserAccount FROM Auth.UserAccount
"""; """;
/// <remarks>No unmanaged resources to release; each method opens and disposes its own connection.</remarks> /// <remarks>No unmanaged resources to release; each method opens and disposes its own connection.</remarks>
@@ -87,7 +87,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
Guid userAccountId = await connection.ExecuteScalarAsync<Guid>( Guid userAccountId = await connection.ExecuteScalarAsync<Guid>(
new CommandDefinition( new CommandDefinition(
""" """
INSERT INTO dbo.UserAccount (Username, FirstName, LastName, DateOfBirth, Email) INSERT INTO Auth.UserAccount (Username, FirstName, LastName, DateOfBirth, Email)
OUTPUT INSERTED.UserAccountID OUTPUT INSERTED.UserAccountID
VALUES (@UserName, @FirstName, @LastName, @DateOfBirth, @Email); VALUES (@UserName, @FirstName, @LastName, @DateOfBirth, @Email);
""", """,
@@ -107,7 +107,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
await connection.ExecuteAsync( await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
INSERT INTO dbo.UserCredential (UserAccountId, Hash) INSERT INTO Auth.UserCredential (UserAccountId, Hash)
VALUES (@UserAccountId, @Hash); VALUES (@UserAccountId, @Hash);
""", """,
new { UserAccountId = userAccountId, Hash = user.PasswordHash }, new { UserAccountId = userAccountId, Hash = user.PasswordHash },
@@ -141,7 +141,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
/// <inheritdoc /> /// <inheritdoc />
/// <remarks> /// <remarks>
/// Persists profile field changes and keeps <c>dbo.UserVerification</c> in sync with /// Persists profile field changes and keeps <c>Auth.UserVerification</c> in sync with
/// <see cref="ApplicationUser.EmailConfirmed" />: a row is inserted (idempotently, matching the /// <see cref="ApplicationUser.EmailConfirmed" />: a row is inserted (idempotently, matching the
/// previous <c>AuthRepository.ConfirmUserAccountAsync</c> behavior) when /// previous <c>AuthRepository.ConfirmUserAccountAsync</c> behavior) when
/// <see langword="true" />, and removed when <see langword="false" /> -- notably after /// <see langword="true" />, and removed when <see langword="false" /> -- notably after
@@ -157,7 +157,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
await connection.ExecuteAsync( await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
UPDATE dbo.UserAccount UPDATE Auth.UserAccount
SET Username = @UserName, FirstName = @FirstName, LastName = @LastName, SET Username = @UserName, FirstName = @FirstName, LastName = @LastName,
Email = @Email, DateOfBirth = @DateOfBirth, UpdatedAt = GETDATE() Email = @Email, DateOfBirth = @DateOfBirth, UpdatedAt = GETDATE()
WHERE UserAccountID = @Id WHERE UserAccountID = @Id
@@ -185,9 +185,9 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
/// <inheritdoc /> /// <inheritdoc />
/// <remarks> /// <remarks>
/// A plain <c>DELETE</c> against <c>dbo.UserAccount</c>: its foreign keys from /// A plain <c>DELETE</c> against <c>Auth.UserAccount</c>: its foreign keys from
/// <c>dbo.UserCredential</c>, <c>dbo.UserVerification</c>, and <c>dbo.UserProfile</c> cascade /// <c>Auth.UserCredential</c>, <c>Auth.UserVerification</c>, and <c>Social.UserProfile</c> cascade
/// (<c>dbo.UserAvatar</c> cascades transitively through <c>dbo.UserProfile</c>), so no manual /// (<c>Social.UserAvatar</c> cascades transitively through <c>Social.UserProfile</c>), so no manual
/// child cleanup is needed. Other tables (posts, comments, photos, follows) reference the /// child cleanup is needed. Other tables (posts, comments, photos, follows) reference the
/// account with <c>ON DELETE NO ACTION</c> by design; deleting an account that still has any of /// account with <c>ON DELETE NO ACTION</c> by design; deleting an account that still has any of
/// those fails with a foreign key violation, which is surfaced as a failed /// those fails with a foreign key violation, which is surfaced as a failed
@@ -204,7 +204,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
{ {
await connection.ExecuteAsync( await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
"DELETE FROM dbo.UserAccount WHERE UserAccountID = @Id", "DELETE FROM Auth.UserAccount WHERE UserAccountID = @Id",
new { user.Id }, new { user.Id },
cancellationToken: cancellationToken cancellationToken: cancellationToken
) )
@@ -273,7 +273,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
/// <inheritdoc /> /// <inheritdoc />
/// <remarks> /// <remarks>
/// For an existing account (<see cref="ApplicationUser.Id" /> already assigned), rotates the /// For an existing account (<see cref="ApplicationUser.Id" /> already assigned), rotates the
/// credential transactionally -- revoking the previous <c>dbo.UserCredential</c> row(s) and inserting /// credential transactionally -- revoking the previous <c>Auth.UserCredential</c> row(s) and inserting
/// the new hash -- mirroring the previous <c>AuthRepository.RotateCredentialAsync</c> behavior. During /// the new hash -- mirroring the previous <c>AuthRepository.RotateCredentialAsync</c> behavior. During
/// registration <see cref="UserManager{TUser}" /> calls this before the account has an ID (i.e. before /// registration <see cref="UserManager{TUser}" /> calls this before the account has an ID (i.e. before
/// <see cref="CreateAsync" /> runs); in that case only the in-memory hash is set, and /// <see cref="CreateAsync" /> runs); in that case only the in-memory hash is set, and
@@ -301,7 +301,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
await connection.ExecuteAsync( await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
UPDATE dbo.UserCredential UPDATE Auth.UserCredential
SET IsRevoked = 1, RevokedAt = GETDATE() SET IsRevoked = 1, RevokedAt = GETDATE()
WHERE UserAccountId = @UserAccountId AND IsRevoked = 0 WHERE UserAccountId = @UserAccountId AND IsRevoked = 0
""", """,
@@ -314,7 +314,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
await connection.ExecuteAsync( await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
INSERT INTO dbo.UserCredential (UserAccountId, Hash) INSERT INTO Auth.UserCredential (UserAccountId, Hash)
VALUES (@UserAccountId, @Hash); VALUES (@UserAccountId, @Hash);
""", """,
new { UserAccountId = user.Id, Hash = passwordHash }, new { UserAccountId = user.Id, Hash = passwordHash },
@@ -423,7 +423,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
new CommandDefinition( new CommandDefinition(
""" """
SELECT Hash SELECT Hash
FROM dbo.UserCredential FROM Auth.UserCredential
WHERE UserAccountId = @UserAccountId AND IsRevoked = 0 WHERE UserAccountId = @UserAccountId AND IsRevoked = 0
""", """,
new { UserAccountId = user.Id }, new { UserAccountId = user.Id },
@@ -435,7 +435,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
new CommandDefinition( new CommandDefinition(
""" """
SELECT TOP 1 1 SELECT TOP 1 1
FROM dbo.UserVerification FROM Auth.UserVerification
WHERE UserAccountID = @UserAccountId WHERE UserAccountID = @UserAccountId
""", """,
new { UserAccountId = user.Id }, new { UserAccountId = user.Id },
@@ -459,7 +459,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
new CommandDefinition( new CommandDefinition(
""" """
SELECT TOP 1 1 SELECT TOP 1 1
FROM dbo.UserVerification FROM Auth.UserVerification
WHERE UserAccountID = @UserAccountId WHERE UserAccountID = @UserAccountId
""", """,
new { UserAccountId = userAccountId }, new { UserAccountId = userAccountId },
@@ -475,7 +475,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
await connection.ExecuteAsync( await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
INSERT INTO dbo.UserVerification (UserAccountId, VerificationDateTime) INSERT INTO Auth.UserVerification (UserAccountId, VerificationDateTime)
VALUES (@UserAccountId, GETDATE()) VALUES (@UserAccountId, GETDATE())
""", """,
new { UserAccountId = userAccountId }, new { UserAccountId = userAccountId },
@@ -489,7 +489,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
} }
} }
/// <summary>Removes the <c>dbo.UserVerification</c> row for a user, if one exists.</summary> /// <summary>Removes the <c>Auth.UserVerification</c> row for a user, if one exists.</summary>
private static Task RemoveVerificationRowAsync( private static Task RemoveVerificationRowAsync(
DbConnection connection, DbConnection connection,
Guid userAccountId, Guid userAccountId,
@@ -497,7 +497,7 @@ public sealed class DapperUserStore(ISqlConnectionFactory connectionFactory)
) => ) =>
connection.ExecuteAsync( connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
"DELETE FROM dbo.UserVerification WHERE UserAccountID = @UserAccountId", "DELETE FROM Auth.UserVerification WHERE UserAccountID = @UserAccountId",
new { UserAccountId = userAccountId }, new { UserAccountId = userAccountId },
cancellationToken: cancellationToken cancellationToken: cancellationToken
) )

View File

@@ -22,7 +22,7 @@ public class UserListRepository(ISqlConnectionFactory connectionFactory)
UserAccountID, UserAccountID,
Username, Username,
FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, RowVersion FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, RowVersion
FROM dbo.UserAccount FROM Auth.UserAccount
WHERE UserAccountID = @UserAccountId WHERE UserAccountID = @UserAccountId
""", """,
new { UserAccountId = id } new { UserAccountId = id }
@@ -40,7 +40,7 @@ public class UserListRepository(ISqlConnectionFactory connectionFactory)
return await connection.QueryAsync<UserAccount>( return await connection.QueryAsync<UserAccount>(
""" """
SELECT UserAccountID, Username, FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, RowVersion SELECT UserAccountID, Username, FirstName, LastName, Email, CreatedAt, UpdatedAt, DateOfBirth, RowVersion
FROM dbo.UserAccount FROM Auth.UserAccount
ORDER BY CreatedAt DESC ORDER BY CreatedAt DESC
OFFSET @Offset ROWS FETCH NEXT @Limit ROWS ONLY OFFSET @Offset ROWS FETCH NEXT @Limit ROWS ONLY
""", """,

View File

@@ -25,7 +25,7 @@ public class UserProfileRepository(ISqlConnectionFactory connectionFactory)
return await connection.ExecuteScalarAsync<Guid>( return await connection.ExecuteScalarAsync<Guid>(
new CommandDefinition( new CommandDefinition(
""" """
INSERT INTO dbo.UserProfile (UserAccountID, Biography) INSERT INTO Social.UserProfile (UserAccountID, Biography)
OUTPUT INSERTED.UserProfileID OUTPUT INSERTED.UserProfileID
VALUES (@UserAccountId, @Biography) VALUES (@UserAccountId, @Biography)
""", """,
@@ -47,7 +47,7 @@ public class UserProfileRepository(ISqlConnectionFactory connectionFactory)
new CommandDefinition( new CommandDefinition(
""" """
SELECT UserProfileID SELECT UserProfileID
FROM dbo.UserProfile FROM Social.UserProfile
WHERE UserAccountID = @UserAccountId WHERE UserAccountID = @UserAccountId
""", """,
new { UserAccountId = userAccountId }, new { UserAccountId = userAccountId },
@@ -73,7 +73,7 @@ public class UserProfileRepository(ISqlConnectionFactory connectionFactory)
int updatedRows = await connection.ExecuteAsync( int updatedRows = await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
UPDATE dbo.UserProfile UPDATE Social.UserProfile
SET Biography = @Biography SET Biography = @Biography
WHERE UserAccountID = @UserAccountId WHERE UserAccountID = @UserAccountId
""", """,
@@ -101,7 +101,7 @@ public class UserProfileRepository(ISqlConnectionFactory connectionFactory)
await connection.ExecuteAsync( await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
UPDATE dbo.UserAvatar UPDATE Social.UserAvatar
SET ValidTo = SYSUTCDATETIME() SET ValidTo = SYSUTCDATETIME()
WHERE UserProfileID = @UserProfileId AND ValidTo IS NULL WHERE UserProfileID = @UserProfileId AND ValidTo IS NULL
""", """,
@@ -114,7 +114,7 @@ public class UserProfileRepository(ISqlConnectionFactory connectionFactory)
await connection.ExecuteAsync( await connection.ExecuteAsync(
new CommandDefinition( new CommandDefinition(
""" """
INSERT INTO dbo.UserAvatar (UserAvatarID, UserProfileID, PhotoID) INSERT INTO Social.UserAvatar (UserAvatarID, UserProfileID, PhotoID)
VALUES (@UserAvatarId, @UserProfileId, @PhotoId) VALUES (@UserAvatarId, @UserProfileId, @PhotoId)
""", """,
new new