SchedulingChanges#
One set of edits to a live Project: tasks, links, resources and assignments to add, update or remove. Project.Apply commits it, Project.Preview tries it on a copy, and each Candidate passed to Project.Evaluate carries one. Project.SuggestAssignments returns one in SuggestResult.Changes.
Create one with new SchedulingChanges(), where every bucket is empty, and add records to the buckets the edit needs.
Declaration#
public sealed class SchedulingChanges : IDeepCloneable<SchedulingChanges>
{
public string? BaselineId { get; set; }
public Changes<TaskData, TaskUpdate> Tasks { get; set; } = new();
public Changes<LinkAdd, LinkUpdate> Links { get; set; } = new();
public Changes<ResourceData, ResourceUpdate> Resources { get; set; } = new();
public Changes<AssignmentData, AssignmentUpdate> Assignments { get; set; } = new();
public SchedulingChanges DeepClone();
public override string ToString();
}
SchedulingChanges doesn't implement IEquatable<SchedulingChanges>, so Equals compares references.
Constructors#
SchedulingChanges()#
public SchedulingChanges()
Creates an empty change set: BaselineId is null and every bucket has empty Add, Update and Remove lists.
Properties#
| Property | Type | Default | Description |
|---|---|---|---|
BaselineId |
string? |
null |
Baseline token the edits were made against. null skips the check. |
Tasks |
Changes<TaskData, TaskUpdate> |
new() |
Tasks to add, update or remove by id. |
Links |
Changes<LinkAdd, LinkUpdate> |
new() |
Links to add, update or remove by id. |
Resources |
Changes<ResourceData, ResourceUpdate> |
new() |
Resources to add, update or remove by id. |
Assignments |
Changes<AssignmentData, AssignmentUpdate> |
new() |
Assignments to add, update or remove by id. |
BaselineId#
public string? BaselineId { get; set; }
The baseline the edits expect. Take the token from the latest ScheduleResult.BaselineId. When it isn't null and doesn't name the project's current baseline, Apply, Preview and Evaluate throw a ProjectException with Code == ProjectError.StaleBaseline. Tokens are opaque: don't compare them across runs.
Tasks, Links, Resources, Assignments#
public Changes<TaskData, TaskUpdate> Tasks { get; set; } = new();
public Changes<LinkAdd, LinkUpdate> Links { get; set; } = new();
public Changes<ResourceData, ResourceUpdate> Resources { get; set; } = new();
public Changes<AssignmentData, AssignmentUpdate> Assignments { get; set; } = new();
One bucket per record kind. Each bucket holds Add, Update and Remove lists; see Changes<TAdd, TUpdate>.
A change set has no calendar bucket. Calendars can't be added or edited through SchedulingChanges; that takes a full Solve(data, …).
Operation order#
Operations run in a fixed order, not in the order they were added. Kinds run in the order tasks, links, resources, assignments. Within a kind:
| Kind | Order |
|---|---|
Tasks |
Remove, Add, Update |
Links |
Remove, Update, Add |
Resources |
Remove, Add, Update |
Assignments |
Remove, Update, Add |
Within a list, records run in list order. Each operation is identified by its bucket, list and index, such as tasks.update[0], in AppliedOperation.Path and RejectedOperation.Path.
Methods#
DeepClone#
public SchedulingChanges DeepClone()
Returns a copy that shares no list or nested record with this instance.
ToString#
public override string ToString()
Returns a debug dump of all five properties.
Example#
Move a task, add a link and check the edit against the current baseline.
using Plen;
var monday = Moment.FromYmdHm(2026, 8, 10, 8, 0) ?? throw new InvalidOperationException("invalid date");
var wednesday = Moment.FromYmdHm(2026, 8, 12, 8, 0) ?? throw new InvalidOperationException("invalid date");
var data = new ProjectData
{
Tasks =
[
new TaskData(1) { StartDate = monday, Duration = 1.0 },
new TaskData(2) { StartDate = monday, Duration = 2.0 },
],
};
var project = new Project();
var solved = project.Solve(data, new SolveOptions());
var changes = new SchedulingChanges { BaselineId = solved.BaselineId };
changes.Tasks.Update.Add(new TaskUpdate(1) { StartDate = wednesday });
changes.Links.Add.Add(new LinkAdd { Source = 1, Target = 2 });
var report = project.Apply(changes);
foreach (var op in report.Rejected)
Console.WriteLine($"rejected {op.Path}: {op.Message}");
Related#
Project.Apply- commits a change setProject.Preview- tries a change set on a copyApplyReport- the outcome of each operation- Editing a project - building and applying change sets
- Previewing changes - seeing what an edit would do