[Canonical page](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/project-data/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# ProjectData

One snapshot of a project: the scheduling config plus the lists of calendars, tasks, links, resources and assignments. Build one with `new ProjectData()` and an object initializer, then pass it to [`Project.Solve`](<https://docs.dhtmlx.com/planning-engine/net/api/project-solve.md>), [`Project.Analyze`](<https://docs.dhtmlx.com/planning-engine/net/api/project-analyze.md>) or [`Engine.Schedule`](<https://docs.dhtmlx.com/planning-engine/net/api/engine-schedule.md>). Each list keeps input order.

## Declaration

```csharp
public sealed class ProjectData : IDeepCloneable<ProjectData>
{
    public SchedulingConfig Config { get; set; } = new();
    public List<CalendarData> Calendars { get; set; } = [];
    public List<TaskData> Tasks { get; set; } = [];
    public List<LinkData> Links { get; set; } = [];
    public List<ResourceData> Resources { get; set; } = [];
    public List<AssignmentData> Assignments { get; set; } = [];

    public ProjectData DeepClone();
    public override string ToString();
}
```

`ProjectData` doesn't implement `IEquatable<ProjectData>`, so `Equals` compares references.

## Constructors

### ProjectData()

```csharp
public ProjectData()
```

Creates an empty snapshot: default [`SchedulingConfig`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/scheduling-config.md>) and empty lists.

## Properties

| Property | Type | Default | Description |
|---|---|---|---|
| `Config` | [`SchedulingConfig`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/scheduling-config.md>) | `new()` | Project-wide scheduling settings. |
| `Calendars` | `List<`[`CalendarData`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/calendar-data.md>)`>` | empty | Working calendars that tasks and resources reference by `CalendarId`. An empty list means only the built-in `"global"` calendar (Mon-Fri, 08:00-12:00 and 13:00-17:00). |
| `Tasks` | `List<`[`TaskData`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/task-data.md>)`>` | empty | Tasks, summaries and milestones. |
| `Links` | `List<`[`LinkData`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/link-data.md>)`>` | empty | Dependency links between tasks. |
| `Resources` | `List<`[`ResourceData`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/resource-data.md>)`>` | empty | Resources that assignments book. |
| `Assignments` | `List<`[`AssignmentData`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/assignment-data.md>)`>` | empty | Task-to-resource bookings. |

### Config

```csharp
public SchedulingConfig Config { get; set; } = new();
```

Scheduling settings for the whole project: constraints, direction, calendars, duration unit, project bounds and root id. See [`SchedulingConfig`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/scheduling-config.md>).

### Calendars

```csharp
public List<CalendarData> Calendars { get; set; } = [];
```

Calendars by id. A calendar with id `"global"` replaces the built-in default calendar. Each `CalendarId` on a task or resource must name a calendar in this list or `"global"`.

### Tasks

```csharp
public List<TaskData> Tasks { get; set; } = [];
```

Every task of the project, flat. The hierarchy comes from each task's `Parent`, which must name another task in this list. A `Parent` equal to [`Config.RootId`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/scheduling-config.md#rootid>) means no parent.

### Links

```csharp
public List<LinkData> Links { get; set; } = [];
```

Dependency links. A link whose `Source` or `Target` isn't in `Tasks` is dropped and reported as a [`Note.DroppedLink`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/note.md>) in the result.

### Resources

```csharp
public List<ResourceData> Resources { get; set; } = [];
```

Resources with their capacity and calendar.

### Assignments

```csharp
public List<AssignmentData> Assignments { get; set; } = [];
```

Bookings of a resource on a task. Each `Task` and `Resource` must name an entry in `Tasks` and `Resources`.

## Methods

### DeepClone

```csharp
public ProjectData DeepClone()
```

Returns a copy that shares no list or nested record with this instance.

**Returns** - a new `ProjectData` with deep copies of `Config` and of every list item.

### ToString

```csharp
public override string ToString()
```

Returns a debug dump of all six properties.

## Validation

The calls that take a `ProjectData` validate it as a whole. In strict mode (the default, set by [`ProjectOptions.Validation`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/project-options.md>)) they throw an [`InputException`](<https://docs.dhtmlx.com/planning-engine/net/api/core/errors/input-exception.md>) whose `Path` uses the JSON field names, for example `tasks[3].constraint_date`. Checks that span the lists:

| Rule | Path |
|---|---|
| Ids are unique within `Calendars`, `Tasks`, `Links`, `Resources` and `Assignments` | `calendars[i]`, `tasks[i].id`, `links[i].id`, `resources[i].id`, `assignments[i].id` |
| A task's `Parent` names a task in `Tasks`, and parents form no cycle | `tasks[i].parent` |
| A summary has its own dates or at least one dated child | `tasks[i]` |
| A `CalendarId` on a task or resource names a calendar | `tasks[i].calendar_id`, `resources[i].calendar_id` |
| An assignment's `Task` and `Resource` name existing records | `assignments[i].task`, `assignments[i].resource` |

Field-level rules (dates, durations, lags, capacities, pauses, worktime) are listed on each record's page. In repair mode a duplicate id replaces the earlier record and keeps its position; see [`Validation`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/validation.md>).

## Example

```csharp
using Plen;

var data = new ProjectData
{
    Config = new SchedulingConfig { DurationUnit = TimeUnit.Day },
    Tasks =
    {
        new TaskData("design") { StartDate = Moment.FromYmdHm(2026, 3, 2, 8, 0), Duration = 3 },
        new TaskData("build") { StartDate = Moment.FromYmdHm(2026, 3, 2, 8, 0), Duration = 5 },
    },
    Links =
    {
        new LinkData { Id = "l1", Source = "design", Target = "build" },
    },
};

ScheduleResult result = Engine.Schedule(data, new SolveOptions());
```

## Related

- [`Project.Solve`](<https://docs.dhtmlx.com/planning-engine/net/api/project-solve.md>) - schedules the snapshot
- [`Engine.Schedule`](<https://docs.dhtmlx.com/planning-engine/net/api/engine-schedule.md>) - one-shot scheduling
- [`SchedulingConfig`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/scheduling-config.md>) - the project-wide settings
- [`Validation`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/validation.md>) - strict and repair modes
- [Project data](<https://docs.dhtmlx.com/planning-engine/net/scheduling/project-data.md>) - describing a plan
