How to Convert a PostgreSQL Schema to C# Models
A step-by-step guide to mapping PostgreSQL CREATE TABLE DDL to C# POCO classes with Entity Framework annotations — including type mapping, nullability, primary keys, and foreign keys.
When you're building a .NET application on top of a PostgreSQL database, one of the most tedious tasks is manually writing C# POCO (Plain Old CLR Object) classes to match your database schema. Every time the schema changes, you risk your C# models going out of sync — leading to runtime errors and hard-to-track bugs.
This guide walks through the complete process of converting a PostgreSQL CREATE TABLE script into C# model classes with proper Entity Framework Core data annotations.
Why Schema-to-Code Generation Matters
Database schemas and application models are two representations of the same data. Keeping them in sync manually is error-prone and time-consuming. A schema-to-code converter eliminates this friction by:
- Generating correct C# property types from SQL column types
- Mapping
NOT NULLconstraints to[Required]or non-nullable types - Handling nullable columns as
Type?(nullable reference types in C# 8+) - Adding
[Key],[Column], and[MaxLength]annotations automatically - Representing foreign keys as navigation properties
PostgreSQL to C# Type Mapping
The most important step is understanding how PostgreSQL types map to C# types. Here are the key mappings:
| PostgreSQL Type | C# Type | Notes |
|---|---|---|
SERIAL | int | [Key] [DatabaseGenerated(Identity)] |
BIGSERIAL | long | [Key] [DatabaseGenerated(Identity)] |
INTEGER | int | |
BIGINT | long | |
BOOLEAN | bool | |
VARCHAR(n) | string | [MaxLength(n)] |
TEXT | string | |
DECIMAL(p,s) | decimal | Use for money fields |
TIMESTAMP | DateTime | |
TIMESTAMP WITH TIME ZONE | DateTimeOffset | Preserves tz offset |
DATE | DateOnly | .NET 6+ |
UUID | Guid | |
JSONB | string | [Column(TypeName="jsonb")] |
BYTEA | byte[] |
Example: Converting a PostgreSQL Schema
Consider this PostgreSQL schema for a simple e-commerce application:
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
phone VARCHAR(30),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
is_active BOOLEAN DEFAULT TRUE
);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
customer_id INT NOT NULL,
total_amount DECIMAL(12, 2) NOT NULL,
status VARCHAR(50) DEFAULT 'pending',
ordered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (customer_id) REFERENCES customers(id)
);
Here is the equivalent C# POCO class with Entity Framework annotations:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("customers")]
public class Customer
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("id")]
public int Id { get; set; }
[Required]
[MaxLength(100)]
[Column("first_name")]
public string FirstName { get; set; } = null!;
[Required]
[MaxLength(100)]
[Column("last_name")]
public string LastName { get; set; } = null!;
[Required]
[MaxLength(255)]
[Column("email")]
public string Email { get; set; } = null!;
[MaxLength(30)]
[Column("phone")]
public string? Phone { get; set; }
[Column("created_at")]
public DateTime CreatedAt { get; set; }
[Column("is_active")]
public bool IsActive { get; set; }
// Navigation property
public ICollection<Order> Orders { get; set; } = [];
}
[Table("orders")]
public class Order
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("id")]
public int Id { get; set; }
[Required]
[Column("customer_id")]
public int CustomerId { get; set; }
[Required]
[Column("total_amount")]
public decimal TotalAmount { get; set; }
[MaxLength(50)]
[Column("status")]
public string? Status { get; set; }
[Column("ordered_at")]
public DateTime OrderedAt { get; set; }
// Navigation property
[ForeignKey(nameof(CustomerId))]
public Customer Customer { get; set; } = null!;
}
Key Rules When Mapping PostgreSQL to C#
1. Nullability
PostgreSQL columns with NOT NULL constraints become required, non-nullable C# properties. Columns without NOT NULL become nullable types (string?, int?, bool?) when you enable C# 8+ nullable reference types — which you should always do in new projects.
2. Primary Keys and Identity Columns
A SERIAL PRIMARY KEY in PostgreSQL becomes an int with [Key] and [DatabaseGenerated(DatabaseGeneratedOption.Identity)] in C#. Use long for BIGSERIAL.
3. Decimal vs Float
Always use decimal (not double or float) for PostgreSQL DECIMAL, NUMERIC, or MONEY columns. The decimal type is exact and won't introduce floating-point rounding errors in financial calculations.
4. DateTime vs DateTimeOffset
TIMESTAMP (without time zone) maps to DateTime. TIMESTAMP WITH TIME ZONE should map to DateTimeOffset to preserve the timezone offset. In .NET 6+, you can also use DateOnly for DATE columns.
5. UUID to Guid
PostgreSQL's UUID type maps directly to C#'s Guid. Entity Framework Core handles the conversion automatically.
Automating the Conversion
Instead of writing these classes by hand, use SchemaForge's free PostgreSQL to C# POCO generator. Paste your CREATE TABLE statements and get production-ready C# classes with all annotations instantly — in your browser, with zero data upload.
The tool handles:
- All PostgreSQL column types → correct C# types
NOT NULL→[Required]attribute and non-nullable typePRIMARY KEY→[Key]and[DatabaseGenerated]VARCHAR(n)→[MaxLength(n)]- Foreign keys → navigation properties
- Multiple tables in one paste
Try it now — free & instant
Use SchemaForge to convert your SQL schema automatically. No upload, no account, no rate limits — everything runs in your browser.
PostgreSQL → C# POCO Generator