SQL - Progettazione di una tabella dei valori di soglia

1

Ho bisogno di progettare una tabella SQL da utilizzare per "soglia" o valori speciali, che in generale avrebbero le seguenti proprietà: - chiave - valore - comparatore (inferiore e superiore all'inizio, preferibilmente con la possibilità di aggiungere ulteriori tipi di comparatori o regole in futuro)

Come esempio di caso di utilizzo di base, questi valori soglia verrebbero utilizzati per generare un evento se alcuni parametri nel sistema superano una soglia.

Con questo in mente, gradirei qualsiasi feedback o input su come precocamente andare su questo. In passato ho visto un compito simile sia utilizzando una tabella di ricerca contenente i tipi dei comparatori, sia memorizzando un tipo di formula in una colonna e successivamente analizzandola usando NCalc (.NET) o qualcosa di simile. Entrambi gli approcci hanno degli inconvenienti: la tabella di ricerca non sembra molto pratica e l'analisi delle cose sembra molto instabile.

Qualche suggerimento su ciò che sarebbe sensato in questo scenario sarebbe molto apprezzato. Non sono un esperto nella progettazione di DB, quindi qualsiasi input sarà prezioso.

    
posta Petar Ivanov 08.05.2015 - 07:53
fonte

1 risposta

2

Per la progettazione di un database, tutto ciò che serve è sinistra, operatore e destra.

Qualcosa del genere:

X > 10

Una tabella come questa:

RuleSetID   PropertyName    Operand TargetValue 
1            Weight          LessThan   200

Quindi puoi usare System.Linq.Expressions namespace per creare dinamicamente espressioni per la valutazione.

Per ulteriori informazioni su questa funzione di framework .Net, visita questo link:

link

Sono supportati tutti i tipi di operatori, maggiori di, minori di ecc.

Ora, un po 'di codice per compilare le espressioni:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using RulesEngine.Model;
using System.Diagnostics;

namespace RulesEngine.Engine
{
    public class ExpressionBuilder
    {
        public Func<T, bool> Compile<T>(Rule rule, Type type)
        {
            try
            {
                var param = Expression.Parameter(type);
                Expression expression = BuildExpression<T>(rule, param);
                return Expression.Lambda<Func<T, bool>>(expression, param).Compile();
            }
            catch (Exception exception)
            {
                //We would want to log this failure so the rule can be corrected.
                Debug.WriteLine(exception.ToString()); 
                //Return an expresssion that would always return false
                Expression<Func<T, bool>> defaultLambda = x => false;
                return defaultLambda.Compile();
            }

        }

        private Expression BuildExpression<T>(Rule rule, ParameterExpression param)
        {
            var left = MemberExpression.Property(param, rule.PropertyName);
            var propertyType = typeof(T).GetProperty(rule.PropertyName).PropertyType;
            ExpressionType binaryExpressionType;

            if (ExpressionType.TryParse(rule.Operand, out binaryExpressionType))
            {
                var right = Expression.Constant(Convert.ChangeType(rule.TargetValue, propertyType));
                return Expression.MakeBinary(binaryExpressionType, left, right);
            }
            else
            {
                var methodName = propertyType.GetMethod(rule.Operand);
                var parameterType = methodName.GetParameters()[0].ParameterType;
                var right = Expression.Constant(Convert.ChangeType(rule.TargetValue, parameterType));
                return Expression.Call(left, methodName, right);
            }
        }
    }
}

Una regola sarebbe una classe per contenere la definizione dal database.

using System;
using System.Collections.Generic;
using System.Linq;

namespace RulesEngine.Model
{
    public class Rule
    {
        public string PropertyName { get; private set; }
        public string Operand { get; private set; }
        public string TargetValue { get; private set; }

        public Rule(string propertyName, string operand, string targetValue)
        {
            PropertyName = propertyName;
            Operand = operand;
            TargetValue = targetValue;
        }
    }
}

Ora creiamo un oggetto per contenere i dati dell'istanza. (Sostituisci foo con i dati della tua istanza di soglia).

public class Foo
{
    public string Name { get; private set; }
    public int Weight { get; private set; }
    public int Size { get; private set; }

    public Foo(string name, int weight, int size)
    {
        Name = name;
        Weight = weight;
        Size = size;
    }
}

E infine mettendo tutto insieme ... confrontando i dati dell'istanza con la regola.

private static void RunExample()
        {
            var rule = new Rule("Weight","Equal", "100");
            var foo = new Foo("FooName", 100, 200);


            var expressionBuilder = new ExpressionBuilder();
            Func<Foo, bool> fooRule = expressionBuilder.Compile<Foo>(rule, foo.GetType());

            Console.WriteLine("Is weight equal to 100 for foo?" + fooRule(foo)); //true
        }

Dal momento che è generico, puoi utilizzarlo come un mini motore di regole che può prendere qualsiasi dato di istanza e confrontarlo con un insieme di regole per restituire vero / falso.

    
risposta data 08.05.2015 - 18:19
fonte

Leggi altre domande sui tag