/DB

Project structure

Recommended layout for a project that uses Socigy.OpenSource.DB, including the DB class library, SQL procedure files, and generated output.

updated 3 May 20263 min readv0.1.82

There are no hard requirements on directory structure, but isolating DB models in a dedicated class library is strongly recommended. It lets multiple consumers (API, background workers, test projects) reference the same typed models without pulling in unrelated dependencies.

MyApp.sln
MyApp.sln
├── MyApp.DB/ <- class library for DB models
│ ├── MyApp.DB.csproj
│ ├── socigy.json <- migration and codegen config (project root)
│ ├──
│ │ ├── User.cs <- [Table] partial class
│ │ └── UserRole.cs <- [FlaggedEnum] enum
│ ├──
│ │ └── Product.cs
│ └──
│ └── Procedures/ <- .sql files for procedure mapping
│ └── GetUserById.sql
└──
└── MyApp.API.csproj

The DB project file

The DB class library references Socigy.OpenSource.DB. If you use Procedure mapping, declare .sql files as <AdditionalFiles> so the source generator can read them at build time:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Socigy.OpenSource.DB" Version="0.1.82" />
  </ItemGroup>

  <!-- Only needed for procedure mapping -->
  <ItemGroup>
    <AdditionalFiles Include="Socigy\Procedures\**\*.sql" />
  </ItemGroup>

  <!-- Optionally emit generated files into the project tree for inspection -->
  <PropertyGroup>
    <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
  </PropertyGroup>
</Project>
NOTE
The AdditionalFiles glob is only required if you use procedure mapping. It can be omitted for projects that only use table-based queries.
TIP
Setting <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> copies generated files from obj/Generated/ into $(IntermediateOutputPath)/generated/ so IDEs can index them more reliably. It is optional.

Model class requirements

Every class that maps to a database table must meet two conditions:

  1. Decorated with [Table("table_name")] — tells the generator which SQL table this class represents.
  2. Declared partial — allows the generator to add members (query methods, IDbTable implementation, Columns constants) in a companion generated file.
// Correct — generator will augment this class
[Table("products")]
public partial class Product { ... }

// Wrong — generator will skip this class; no query methods will be emitted
[Table("products")]
public class Product { ... }

The class can be in any namespace. Nesting inside another class is not supported.


Generated files

The source generator writes one .g.cs file per annotated class. The files are placed under the intermediate output path:

obj/{Configuration}/net{version}/generated/Socigy.OpenSource.DB.SourceGenerator/Socigy.OpenSource.DB.SourceGenerator.Program/

For example, a Debug build targeting net10.0 uses:

obj/Debug/net10.0/generated/Socigy.OpenSource.DB.SourceGenerator/Socigy.OpenSource.DB.SourceGenerator.Program/

To have the IDE index these files reliably, add <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> to your .csproj.

You never edit these files directly — they are recreated on every build. Each generated file contains:

  • The IDbTable interface implementation (GetTableName(), GetColumns(), GetPrimaryColumns(), GetColumn(), GetDbColumnName())
  • Static factory methods: Query(), Insert(), Update(), Delete()
  • Instance shortcut methods: user.Insert(), user.Update(), user.Delete()
  • Column name constants (see below)

Static column name constants

The generator emits a {PropertyName}ColumnName constant directly on each model class for every mapped property, using the snake_case database column name:

User.UsernameColumnName   // => "username"
User.CreatedAtColumnName  // => "created_at"
User.IdColumnName         // => "id"

These are useful when building dynamic SQL fragments or logging query details without hard-coding string literals.


Keeping obj/ out of source control

Generated files should not be committed. Add obj/ to your .gitignore:

obj/
bin/

The generator re-creates all output on the next dotnet build, so nothing is lost by excluding it.