You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

表达式树实现运行时索引器验证数组规则及批量插入失效问题

Fixing Rule Engine Validation Failure with InsertAll() and Runtime Indexers

Let's work through this problem together. The main issues here are twofold: your Test2 rule is targeting the wrong object type, and you're trying to manually handle array indexing when the rule engine can do that for you automatically. The error about the undefined index variable comes from not including that parameter in your condition lambda's parameter list.

What's Going Wrong

  • When you call session.InsertAll(customerData), the rule engine processes each Customer in the array one by one. Your Test1 rule works because it targets Customer directly, matching every inserted object.
  • In Test2, you switched your rule to target RuleEngineRequestModel, but you never inserted that model into the session—you inserted the Customer array. That's why the validation doesn't fire at all.
  • The "variable not defined" error happens because you created an index parameter but didn't include it in the parameters for your Expression.Lambda, so the expression can't resolve it.

The Solution

To validate array elements correctly with InsertAll(), you don't need to manually handle array indexing. Instead, keep your rule focused on individual Customer instances. If you need to validate based on an element's position in the array, attach the index to each Customer or store it in the session context when inserting.

Step 1: Update the Customer Class (If You Need Index Tracking)

Add an Index property to track the position of each customer in the array:

public class Customer {
    public string Name { get; set; }
    public int Age { get; set; }
    public int Index { get; set; } // New property for index tracking
}

Step 2: Fix the Test2 Rule Method

Adjust the rule to target Customer (just like Test1), and add index-based validation if needed:

public List<IRuleDefinition> Test2(RuleEngineEntity rule) {
    RuleBuilder builder = new RuleBuilder();
    builder.Name("DefaultRules");
    try {
        // Target individual Customer instances, not the request model
        var modelPattern = builder.LeftHandSide().Pattern(typeof(Customer), "CustomerCheck");
        var modelParameter = modelPattern.Declaration.ToParameterExpression();

        // Base condition: Age > rule.Value
        var ageProperty = Expression.Property(modelParameter, rule.FieldName);
        var ageCondition = Expression.GreaterThan(ageProperty, Expression.Constant(rule.Value));

        // Optional: Add index-specific validation (e.g., only even indexes)
        var indexProperty = Expression.Property(modelParameter, nameof(Customer.Index));
        var indexCondition = Expression.Equal(
            Expression.Modulo(indexProperty, Expression.Constant(2)), 
            Expression.Constant(0)
        );
        // Combine conditions if needed
        var combinedCondition = Expression.AndAlso(ageCondition, indexCondition);

        // Lambda only needs the Customer parameter (since we're matching each instance)
        LambdaExpression expressionCondition = Expression.Lambda(combinedCondition, modelParameter);
        modelPattern.Condition(expressionCondition);

        // Keep the action targeted at each Customer
        Expression<Action<IContext, Customer, RuleEngineEntity>> action = 
            (ctx, customerCheck, rules) => FireActionAsync(ctx, customerCheck, rules);
        builder.RightHandSide().Action(action);
    } catch (Exception e) {
        Console.WriteLine($"Rule build error: {e.Message}");
    }
    var buildRule = builder.Build();
    return new List<IRuleDefinition> { buildRule };
}

Step 3: Populate Indexes When Creating Customer Data

When building your customer array, set the Index property for each element:

public static void RuleTestWithInsertDataAll() {
    try {
        CustomRuleRepository repository = new CustomRuleRepository();
        List<RuleEngineEntity> rules = new List<RuleEngineEntity>();
        rules.Add(new RuleEngineEntity { FieldName = "Age", Name = "CustomerCheck", Value = 25 });
        repository.LoadRuleForTest2(rules.FirstOrDefault());

        var factory = repository.Compile();
        var session = factory.CreateSession();

        // Create customers with index values
        var customers = new List<Customer> {
            new Customer { Name = "A", Age = 28, Index = 0 },
            new Customer { Name = "B", Age = 26, Index = 1 }
        };

        session.InsertAll(customers.ToArray());
        var isPassed = session.Fire();
    } catch (Exception e) {
        Console.WriteLine(e.Message);
    }
}

Alternative: Track Index Without Modifying Customer Class

If you can't add an Index property to Customer, store the index in the session context when inserting:

// When inserting data
var customerArray = ruleEngineRequestModel.customerData;
for (int i = 0; i < customerArray.Length; i++) {
    var customer = customerArray[i];
    session.Insert(customer);
    // Store index using a unique key for each customer
    session.Context.Set($"Customer_{customer.GetHashCode()}_Index", i);
}

// In your action method
public void FireActionAsync(IContext ctx, Customer customer, RuleEngineEntity rule=null) {
    int index = ctx.Get<int>($"Customer_{customer.GetHashCode()}_Index");
    Console.WriteLine($"{rule.Name} Triggered for customer at index {index}: {customer.Name}");
}

Key Takeaway

InsertAll() handles iterating over your array automatically—your rules should target the individual elements in the array, not the array container. If you need index-specific validation, attach the index to each element or store it in the session context during insertion.

内容的提问来源于stack exchange,提问作者Ghanshyam Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:26:36