LinkUpdate#

A partial edit of one existing link. Only the properties you set change; the rest keep their current values. Add it to SchedulingChanges.Links.Update (see SchedulingChanges) and pass the change set to Project.Apply, Project.Preview or Project.Evaluate. Create one with new LinkUpdate(id) and set the properties to change in an object initializer.

Declaration#

namespace Plen;

public sealed class LinkUpdate : IDeepCloneable<LinkUpdate>

Constructors#

LinkUpdate(Id)#

[SetsRequiredMembers]
public LinkUpdate(Id id)

Creates an update for the link with this id. Every other property is Patch<T>.Missing, so the update changes nothing until a property is set.

Parameters

Name Type Description
id Id Id of the link to edit. A string, int or double converts to Id implicitly.

The class has no parameterless constructor.

Properties#

Each editable property is a Patch<T>. A plain value converts to Patch<T> implicitly, so Lag = 2.0 sets the lag. The table shows what Patch<T>.Null does to each property. The properties mean the same as on LinkData.

Property Type Patch<T>.Null
Id Id Not a patch. Selects the link to edit.
Source Patch<Id> Rejected: a link always has a source.
Target Patch<Id> Rejected: a link always has a target.
LinkType Patch<LinkType> Resets to LinkType.Fs.
Lag Patch<double> Resets to 0.0.
LagUnit Patch<TimeUnit> Clears the unit, so Lag is read in SchedulingConfig.DurationUnit.

Id#

public required Id Id { get; set; }

Id of an existing link. The update edits that link and can't change its id.

Source, Target#

public Patch<Id> Source { get; set; }
public Patch<Id> Target { get; set; }

A value moves that end of the link to another task. If the new task doesn't exist or is unscheduled, the update is still applied, but the link is dropped from scheduling and its id is listed in ApplyReport.Effects.DroppedLinks.

Id to Patch<Id> is a single implicit conversion, but int or string to Patch<Id> isn't. Write Source = (Id)3 or Source = Patch<Id>.Of(3).

LinkType#

public Patch<LinkType> LinkType { get; set; }

Which end of Source drives which end of Target.

Lag#

public Patch<double> Lag { get; set; }

Working time between the two ends, in the link's lag unit. Negative values are allowed. The value must be finite.

LagUnit#

public Patch<TimeUnit> LagUnit { get; set; }

Unit of Lag for this link only.

Methods#

DeepClone#

public LinkUpdate DeepClone()

Returns a copy with the same property values.

ToString#

public override string ToString()

Returns a readable rendering of every property, for logging.

LinkUpdate doesn't override Equals; two instances compare by reference.

Errors#

An invalid update doesn't throw. It's listed in ApplyReport.Rejected as a RejectedOperation with Path = "links.update[i]", and the link stays as it was. An update is rejected when:

  • Id names no link in the project: unknown link id
  • Source or Target is Patch<Id>.Null: required field cannot be null
  • Lag is NaN or infinite: lag must be finite

A rejection sets ApplyReport.NeedsResync. See Project.Apply for what that means for later calls.

Example#

Turn link "a" into a start-to-start link with a two-hour lag and leave its tasks as they are:

using Plen;

var start = Moment.FromYmdHm(2026, 4, 6, 8, 0)
    ?? throw new InvalidOperationException("invalid date");

var data = new ProjectData
{
    Tasks =
    [
        new TaskData(1) { StartDate = start, Duration = 2.0 },
        new TaskData(2) { StartDate = start, Duration = 1.0 },
    ],
    Links = [new LinkData { Id = "a", Source = 1, Target = 2 }],
};

var project = new Project();
var options = new SolveOptions();
var solved = project.Solve(data, options);

var changes = new SchedulingChanges { BaselineId = solved.BaselineId };
changes.Links.Update.Add(new LinkUpdate("a")
{
    LinkType = LinkType.Ss,
    Lag = 2.0,
    LagUnit = TimeUnit.Hour,
});

var report = project.Apply(changes);
foreach (var rejected in report.Rejected)
{
    Console.WriteLine($"{rejected.Path}: {rejected.Message}");
}

var result = project.Solve(null, options);
foreach (var update in result.Updates)
{
    Console.WriteLine(update);
}