Skip to content
/ Facet Public

Source generator that instantly scaffolds DTOs, typed LINQ projections, and ViewModels without any runtime overhead.

License

Notifications You must be signed in to change notification settings

Tim-Maes/Facet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

88 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Facet

NuGet Downloads License: MIT

"One part of a subject, situation, object that has many parts."

Facet is a C# source generator that lets you define lightweight projections (DTOs, API models, etc.) directly from your domain models — without writing boilerplate.

It generates partial classes, records structs or record structs with constructors, optional LINQ projections, and even supports custom mappings — all at compile time, with zero runtime cost.

What is Facetting?

Facetting is the process of defining focused views of a larger model at compile time.

Instead of manually writing separate DTOs, mappers, and projections, Facet allows you to declare what you want to keep — and generates everything else.

You can think of it like carving out a specific facet of a gem:

  • The part you care about
  • Leaving the rest behind.

Why Facetting?

  • Reduce duplication across DTOs, projections, and ViewModels
  • Maintain strong typing with no runtime cost
  • Stay DRY (Don't Repeat Yourself) without sacrificing performance
  • Works seamlessly with LINQ providers like Entity Framework

Key features

  • ✅ Generate classes, records, structs or record structs from existing types
  • ✅ Exclude fields/properties you don't want (create a Facetted view of your model))
  • ✅ Include public fields (optional)
  • ✅ Auto-generate constructors for fast mapping
  • ✅ LINQ projection expressions (Expression<Func<TSource,TTarget>>)
  • ✅ Custom mapping via IFacetMapConfiguration

Quick Start

1. Install

dotnet add package Facet

2. Define facet

using Facet;

public class Person
{
    public string Name { get; set; }
    public string Email { get; set; }
    public int Age { get; set; }
}

// Generate a DTO that excludes Email
[Facet(typeof(Person), exclude: nameof(Person.Email))]
public partial class PersonDto { }

This generates a PersonDto with only Name and Age, and a constructor that copies values.

3. Use your generated facets

var person = new Person { Name = "Alice", Email = "a@b.com", Age = 30 };
var dto = new PersonDto(person);

LINQ projection support:

var query = dbContext.People
    .Select(PersonDto.Projection)
    .ToList();

Advanced scenarios

Records

[Facet(typeof(Person), Kind = FacetKind.Record)]
public partial record PersonRecord;

Struct & Record Struct

[Facet(typeof(MyStruct), Kind = FacetKind.Struct, IncludeFields = true)]
public partial struct MyStructDto;

[Facet(typeof(MyRecordStruct), Kind = FacetKind.RecordStruct)]
public partial record struct MyRecordStructDto;

Custom mapping

Eg. you need to compile extra fields

public class UserMapConfig : IFacetMapConfiguration<User, UserDto>
{
    public static void Map(User source, UserDto target)
    {
        target.FullName = $"{source.FirstName} {source.LastName}";
    }
}

[Facet(typeof(User), Configuration = typeof(UserMapConfig))]
public partial class UserDto;

This lets you add derived properties, formatting, etc.

Facet.Extensions for LINQ/EF Core async

Install Facet.Extensions for one-line mapping helpers:

dotnet add package Facet.Extensions

Then:

using Facet.Extensions;

// Single object
var dto = person.ToFacet<Person, PersonDto>();

// Lists
var dtos = people.SelectFacets<Person, PersonDto>();

// IQueryable deferred projection
var query = dbContext.People.SelectFacet<Person, PersonDto>();

And with EF Core:

var dtos = await dbContext.People.ToFacetsAsync<Person, PersonDto>();

var single = await dbContext.People.FirstFacetAsync<Person, PersonDto>();

Facet - Define less, project more.

About

Source generator that instantly scaffolds DTOs, typed LINQ projections, and ViewModels without any runtime overhead.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages