如何在Elsa工作流中构建自定义循环活动



我正在尝试创建一个自定义活动,该活动最终将执行复杂的数据库查询或API调用,以获取一组记录并对其进行循环。我确信它可以通过内置的流控制活动来完成,但我想让那些不知道或不在乎foreach循环是什么的非程序员可以使用它,所以把很多功能放在一个盒子里是很好的。

我的第一次尝试是从ForEach继承,并在让OnExecute做它的事情之前进行一些初始化,但结果感觉有点糟糕。

public class FancyForEach : ForEach
{
private bool? Initialized
{
get
{
return GetState<bool?>("Initialized");
}
set
{
SetState(value, "Initialized");
}
}
protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context)
{
if (Initialized != true)
{
Items = GetThingsFromDatabase();
Initialized = true;
}
return base.OnExecute(context);
}
protected List<DatabaseThings> GetThingsFromDatabase()
{
// Fancy stuff here, including paging eventually.
}
}

似乎在活动中的某个地方实例化ForEach而不是从中继承会更干净一些,但我无法找到实现这一点的方法。我想一个不错的解决方案是为每条记录触发另一个工作流,但我宁愿不这样做,再次让非程序员更容易理解。

有人能就实现这一目标的最佳方式提出建议吗?这是我使用Elsa的第一个项目,所以也许我从一个完全错误的方向来处理它!

如果我理解正确,您的活动负责加载数据并在数据上循环,而活动的用户应该能够指定每次迭代中发生的事情。

如果是这样的话,那么你可能会实现这样的东西:

[Activity(
Category = "Control Flow",
Description = "Iterate over a collection.",
Outcomes = new[] { OutcomeNames.Iterate, OutcomeNames.Done }
)]
public class FancyForEach : Activity
{
private bool? Initialized
{
get => GetState<bool?>();
set => SetState(value);
}

private IList<DatabaseThings>? Items
{
get => GetState<IList<DatabaseThings>?>();
set => SetState(value);
}

private int? CurrentIndex
{
get => GetState<int?>();
set => SetState(value);
}

protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context)
{
if (Initialized != true)
{
Items = GetThingsFromDatabase();
Initialized = true;
}

var collection = Items.ToList();
var currentIndex = CurrentIndex ?? 0;
if (currentIndex < collection.Count)
{
var currentValue = collection[currentIndex];
var scope = context.CreateScope();
scope.Variables.Set("CurrentIndex", currentIndex);
scope.Variables.Set("CurrentValue", currentValue);
CurrentIndex = currentIndex + 1;
context.JournalData.Add("Current Index", currentIndex);
// For each iteration, return an outcome to which the user can connect activities to.
return Outcome(OutcomeNames.Iterate, currentValue);
}
CurrentIndex = null;
return Done();
}

protected List<DatabaseThings> GetThingsFromDatabase()
{
// Fancy stuff here, including paging eventually.
}
}

此示例将数据库项加载到内存中一次,然后以工作流状态(通过Items(存储此列表,这可能是可取的,也可能不是可取的,因为这可能会根据每条记录的大小和记录的数量显著增加工作流实例的大小。

一种更具可扩展性的方法是每次迭代只加载一个项目,跟踪加载的当前索引,并将其递增(即页面大小为1的分页(。

最新更新