> ## Documentation Index
> Fetch the complete documentation index at: https://easyaf.nimbleapps.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Getting Started with EasyAF

> Get up and running quickly is as easy as 1-2-3.

EasyAF is a set of libraries you can drop into any .NET project, and a CLI that scaffolds a full application. Start with Core. Reach for the CLI when you want the whole stack.

## Use EasyAF.Core

`EasyAF.Core` is the shared primitives: observable objects, intervals, identity, and audit interfaces. Add it to a class library, console app, Blazor project, or WPF app. Nothing else in EasyAF is required.

### Step 1: Install the package

```bash theme={"dark"}
dotnet add package EasyAF.Core
```

### Step 2: Observable objects

`EasyObservableObject` implements `INotifyPropertyChanged` with strongly typed `Set` helpers. Use it anywhere you need change notification — XAML binding, Blazor, or a view-model that should raise events only when the value actually changes.

```csharp theme={"dark"}
using CloudNimble.EasyAF.Core;

public class Person : EasyObservableObject
{
    private string _name;
    private int _age;

    public string Name
    {
        get => _name;
        set => Set(nameof(Name), ref _name, value);
    }

    public int Age
    {
        get => _age;
        set => Set(nameof(Age), ref _age, value);
    }
}
```

`DbObservableObject` adds change tracking for entities you round-trip to an API. Call `TrackChanges`, edit properties through `Set`, then send a delta of only what changed:

```csharp theme={"dark"}
var customer = GetCustomer();
customer.TrackChanges(deepTracking: true);

customer.Name = "New Name";
customer.Orders[0].Status = "Shipped";

if (customer.IsGraphChanged)
{
    var delta = customer.ToDeltaPayload(true);
    await UpdateCustomer(delta);
    customer.AcceptChanges(true);
}
```

See the [Observable Objects](https://easyaf.nimbleapps.cloud/guides/observable-objects.md) guide for cloning, rejecting changes, and graph traversal.

### Step 3: Intervals

`Interval<T>` is **time per occurrence** — how long between events — with `PerHour` / `PerDay` / `PerYear` converting that into a frequency.

```csharp theme={"dark"}
using CloudNimble.EasyAF.Core;

// One widget every 1.5 hours
var production = new Interval<double>(1.5, IntervalType.Hours);

decimal perHour = production.PerHour();   // 0.67
decimal perDay  = production.PerDay();    // 16
decimal perYear = production.PerYear();   // 5840
```

`MoneyInterval<T>` is the same math for money: an amount that occurs on an interval, converted to any other period.

```csharp theme={"dark"}
// $100 every 1.5 hours
var wage = new MoneyInterval<double>(100m, 1.5, IntervalType.Hours);

decimal perHour = wage.PerHour();   // 66.67
decimal perDay  = wage.PerDay();    // 1600.00
decimal perYear = wage.PerYear();   // 584000.00

var salary = new MoneyInterval<double>(75000m, 1, IntervalType.Years);
string display = salary.ToString(); // "$75,000.00 / 1 year"
```

`RatioInterval<T>` and `PercentageInterval<T>` do the same for conversion rates and percents. The [Interval Calculations](https://easyaf.nimbleapps.cloud/guides/interval-calculations.md) guide covers those.

Core also ships `IIdentifiable<T>`, audit interfaces (`ICreatedAuditable`, `ICreatorTrackable<T>`, …), and `Ensure` argument guards. You can stop here and use those types in any project.

## Scaffold an EasyAF application

When you want entities, managers, and a Restier API generated from a database, the CLI builds the solution EasyAF expects.

### Step 1: Install the CLI

```bash Major Releases theme={"dark"}
dotnet tool install EasyAF --global
```

```bash Previews theme={"dark"}
dotnet tool install EasyAF --global --prerelease
```

The tool command is `dotnet easyaf`.

### Step 2: Create a solution

From an empty folder:

```bash theme={"dark"}
dotnet easyaf new CloudNimble.Contoso
```

That creates a `.slnx` with the projects EasyAF expects, already referenced and packaged:

| Project | Role |
| - | - |
| `CloudNimble.Contoso.Core` | Entities and shared types (`EasyAF.Core`) |
| `CloudNimble.Contoso.Data` | EF Core DbContext (`EasyAF.Data.EFCore`) |
| `CloudNimble.Contoso.Business` | Managers (`EasyAF.Business.EFCore`) |
| `CloudNimble.Contoso.Api` | Restier OData host (`EasyAF.Restier.EFCore`) |
| `CloudNimble.Contoso.MessageBus.*` | Publish, dispatch, and a runtime host |
| `CloudNimble.Contoso.Tests.*` | Breakdance test projects |

Useful flags:

```bash theme={"dark"}
# Target .NET 10 instead of .NET 11
dotnet easyaf new CloudNimble.Contoso -f 10

# Skip the API or the message bus
dotnet easyaf new CloudNimble.Contoso --no-api
dotnet easyaf new CloudNimble.Contoso --no-messagebus

# Create the solution in a different folder
dotnet easyaf new CloudNimble.Contoso -o ./src
```

`new` only creates and links projects. It does not restore, build, or connect a database.

### Step 3: Connect a database

Point EasyAF at SQL Server or PostgreSQL. The connection string can be a real string (stored in user secrets) or a pointer into `appsettings.json`:

```bash SQL Server theme={"dark"}
dotnet easyaf init -c "appsettings.json:ConnectionStrings:DefaultConnection" -x ContosoContext -p SqlServer
```

```bash PostgreSQL theme={"dark"}
dotnet easyaf init -c "appsettings.json:ConnectionStrings:DefaultConnection" -x ContosoContext -p PostgreSQL
```

`init` writes `{ContextName}.edmx.config` in the `.Data` project and sets EasyAF project types on the solution. When you are joining an existing EasyAF repo, use `dotnet easyaf setup` to store a local connection string instead.

### Step 4: Generate from your schema

Scaffold the EDMX from the database, then generate C# for every layer:

```bash theme={"dark"}
dotnet easyaf database generate --context-name ContosoContext
dotnet easyaf code generate all
```

Code generation produces:

* Core entities that implement EasyAF interfaces (`IIdentifiable<T>`, `ICreatedAuditable`, `IHumanReadable`, …)
* A DbContext in `.Data`
* A manager per entity in `.Business`
* Restier API surface in `.Api`

Generate a single layer when you need to:

```bash theme={"dark"}
dotnet easyaf code generate core
dotnet easyaf code generate business
dotnet easyaf code generate api
```

### Step 5: Work with a manager

Generated entities compose EasyAF interfaces. A typical product looks like this:

```csharp theme={"dark"}
using CloudNimble.EasyAF.Core;

public class Product : IIdentifiable<Guid>,
                       ICreatedAuditable,
                       IUpdatedAuditable,
                       IHumanReadable
{
    public Guid Id { get; set; }
    public string DisplayName { get; set; }
    public string SKU { get; set; }
    public DateTimeOffset DateCreated { get; set; }
    public DateTimeOffset? DateUpdated { get; set; }
}
```

Managers wrap CRUD, fill audit fields, and give you lifecycle hooks. Customize a generated manager (or write one) like this:

```csharp theme={"dark"}
using CloudNimble.EasyAF.Business;
using CloudNimble.SimpleMessageBus.Publish;

public class ProductManager : EntityManager<ContosoContext, Product>
{
    public ProductManager(ContosoContext context, IMessagePublisher publisher)
        : base(context, publisher)
    {
    }

    public override async Task OnInsertingAsync(Product entity)
    {
        await base.OnInsertingAsync(entity);

        if (string.IsNullOrWhiteSpace(entity.SKU))
        {
            entity.SKU = GenerateSku();
        }
    }
}
```

Call it from your API or another manager:

```csharp theme={"dark"}
public class CatalogService
{
    private readonly ProductManager _products;

    public CatalogService(ProductManager products)
    {
        _products = products;
    }

    public async Task<Product> AddProductAsync(string displayName)
    {
        var product = new Product { DisplayName = displayName };
        await _products.InsertAsync(product, save: true);
        return product;
    }
}
```

`InsertAsync` sets `Id`, `DateCreated`, and any creator/updater fields the entity implements. You do not write that boilerplate yourself.

### Step 6: Run the API

```bash theme={"dark"}
dotnet run --project CloudNimble.Contoso.Api
```

The Restier host exposes your entities over OData. Browse `$metadata` and query collections the same way you would any Restier API.

## Next Steps

> [card] [Observable Objects](https://easyaf.nimbleapps.cloud/guides/observable-objects.md)
>
> Property change notification and delta payloads

> [card] [Interval Calculations](https://easyaf.nimbleapps.cloud/guides/interval-calculations.md)
>
> Frequency, money, ratios, and percentages over time

> [card] [Table Design](https://easyaf.nimbleapps.cloud/guides/table-design.md)
>
> Composable interfaces for keys, audit fields, and naming

> [card] [Business Layer](https://easyaf.nimbleapps.cloud/guides/business-layer.md)
>
> Manager hierarchy, lifecycle hooks, and CRUD


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.