Skip to content

Configure Entities

quyvu edited this page Oct 13, 2026 · 2 revisions

Configure Entities & Profiles

Use FluentAPI to define entity configurations and DTO profiles — the core building blocks of FxMap.

Core Concepts

IDistributedKey

A marker interface that identifies an entity group. Both the entity config and the DTO profile reference the same key to establish the mapping contract.

EntityConfigureOf

Defines which entity exposes which properties, and links it to a distributed key. Lives on the data-provider side.

ProfileOf

Defines which properties on a DTO should be auto-populated, and from which distributed key. Lives on the consumer side.

Loose Coupling Option

You can reference distributed keys by string name instead of type for complete decoupling between services.

Step 1: Define a Distributed Key

A distributed key is a simple marker interface — it acts as a shared contract between the entity config and the profile.

// Define one key per entity group
public sealed class UserDistributedKey : IDistributedKey;
public sealed class ProductDistributedKey : IDistributedKey;
public sealed class OrderDistributedKey : IDistributedKey;

Tip: Both EntityConfigureOf<T> and ProfileOf<T> support two overloads — UseDistributedKey<TKey>() and UseDistributedKey(string key). Both sides must use the same overload with the same values for the mapping to work.

Step 2: Configure the Entity

Inherit from EntityConfigureOf<T> and override Configure() to describe the entity:

public class UserConfig : EntityConfigureOf<User>
{
    protected override void Configure()
    {
        // Primary key used for lookups
        Id(x => x.Id);
 
        // Default property returned when no expression is specified
        DefaultProperty(x => x.Name);
 
        // Link this entity to a distributed key
        UseDistributedKey<UserDistributedKey>();
 
        // Expose a property under a custom name
        ExposedName(x => x.Email, "UserEmail");
    }
}

EntityConfigureOf Methods

  • Id(x => x.Id) — the primary key property used for lookups

  • DefaultProperty(x => x.Name) — returned when no expression is specified in the profile

  • UseDistributedKey() — links this config to a distributed key (generic overload)
    UseDistributedKey(string key) — same but uses a string key for full assembly decoupling, such as UserDistributedKey or a dotted name like MyApp.Keys.UserKey; both sides must use the same string

  • ExposedName(x => x.Email, "UserEmail") — exposes a property under an alias for consumer use

Step 3: Configure the Profile

Inherit from ProfileOf<T> to describe how to populate a DTO:

public class UserResponseProfile : ProfileOf<UserResponse>
{
    protected override void Configure()
    {
        UseDistributedKey<UserDistributedKey>()
            // Which property on the DTO holds the ID to look up
            .Of(x => x.UserId)
            // Map to Name (uses DefaultProperty from entity config)
            .For(x => x.UserName)
            // Map to Email using expression
            .For(x => x.UserEmail, "Email")
            // Navigation property
            .For(x => x.CountryName, "Country.Name")
            // Aggregation
            .For(x => x.TotalSpent, "Orders:sum(Total)")
            // Projection
            .For(x => x.UserDetails, "{Id, Name, Address.City as CityName}");
    }
}

UseDistributedKey Overloads

Both EntityConfigureOf<T> and ProfileOf<T> support two overloads of UseDistributedKey:

Generic Overload (shared assembly)

// EntityConfigureOf<T>
public class UserConfig : EntityConfigureOf<User>
{
    protected override void Configure()
    {
        Id(x => x.Id);
        DefaultProperty(x => x.Name);
        UseDistributedKey<UserDistributedKey>(); // ✅ type-safe
    }
}
 
// ProfileOf<T>
public class OrderResponseProfile : ProfileOf<OrderResponse>
{
    protected override void Configure()
    {
        UseDistributedKey<UserDistributedKey>() // ✅ type-safe
            .Of(x => x.UserId)
            .For(x => x.UserName);
    }
}

String Overload (no shared assembly)

// EntityConfigureOf<T>
public class UserConfig : EntityConfigureOf<User>
{
    protected override void Configure()
    {
        Id(x => x.Id);
        DefaultProperty(x => x.Name);
        UseDistributedKey("UserDistributedKey"); // ✅ no type ref
    }
}
 
// ProfileOf<T>
public class OrderResponseProfile : ProfileOf<OrderResponse>
{
    protected override void Configure()
    {
        UseDistributedKey("UserDistributedKey") // ✅ no type ref
            .Of(x => x.UserId)
            .For(x => x.UserName);
    }
}

Important: The entity config and the consumer profile must use the same overload to communicate. If the entity config uses UseDistributedKey<TKey>(), the profile must also use the generic overload. If the entity config uses UseDistributedKey(string key), the profile must also use the string overload with the same key values.

Multiple Entities Example

A complete microservices setup with multiple entity configurations:

// Distributed keys
public sealed class UserDistributedKey : IDistributedKey;
public sealed class ProvinceDistributedKey : IDistributedKey;
public sealed class CountryDistributedKey : IDistributedKey;
 
// Entity configs (data-provider side)
public class UserConfig : EntityConfigureOf<User>
{
    protected override void Configure()
    {
        Id(x => x.Id);
        DefaultProperty(x => x.Name);
        UseDistributedKey<UserDistributedKey>();
        ExposedName(x => x.Email, "UserEmail");
    }
}
 
public class ProvinceConfig : EntityConfigureOf<Province>
{
    protected override void Configure()
    {
        Id(x => x.Id);
        DefaultProperty(x => x.Name);
        UseDistributedKey<ProvinceDistributedKey>();
    }
}
 
public class CountryConfig : EntityConfigureOf<Country>
{
    protected override void Configure()
    {
        Id(x => x.Id);
        DefaultProperty(x => x.Name);
        UseDistributedKey<CountryDistributedKey>();
    }
}

Best Practices

One Key Per Entity

Create one IDistributedKey per logical entity. Multiple profiles can share the same key.

Organize by Domain

Keep entity configs close to your domain models. Keep profiles close to your DTOs. Register them by assembly using AddEntitiesFromAssemblyContaining<> and AddProfilesFromAssemblyContaining<>.

Sealed Keys

Declare distributed keys as sealed to prevent inheritance and improve performance.

Remember to Register

After creating your configs and profiles, register them usingAddEntitiesFromAssemblyContaining<> andAddProfilesFromAssemblyContaining<>inside AddFxMap(...).


Source: https://fxmapper.net/docs/configure-entities/ — the website is always the most up to date version.

Clone this wiki locally