2011-08-08 6 views
0

Dans mon (C# + SQL Server) application, l'utilisateur sera en mesure de définir des règles sur des données telles que:Appliquer des règles aux données

ITEM_ID = 1 
OR (ITEM_NAME LIKE 'something' AND ITEM_PRICE > 123 
AND (ITEM_WEIGHT = 456 OR ITEM_HEIGHT < 789)) 

L'ensemble des éléments pour la validation sera toujours différent, mais ils ne sont pas un énorme nombre. Cependant, le nombre de règles est élevé (disons, 100000).

Comment puis-je vérifier quelles règles validées (compte tenu également de la performance du compte) un ensemble de nombres donné?

+0

Alors vous allez vérifier 100 000 règles à chaque validation ...? – Chains

+2

La question est un peu vague, vos "règles" ne sont qu'une série de clauses WHERE, n'est-ce pas? Qu'est-ce que vous essayez exactement de tester (que chaque clause renvoie 0?). En outre, vous avez dit que vous avez plus de 1000 règles (où clauses), est-ce que votre objectif est de les exécuter toutes et de vérifier qu'elles donnent toutes 0 résultats? Comment voulez-vous/prévoyez-vous gérer les échecs? – Zachary

+0

Est-ce qu'on parle de contraintes ou de conditions dans la clause where? –

Répondre

1

Vous pouvez utiliser certains moteurs d'analyse de Microsoft pour T-SQL. Vous pouvez les trouver dans les assemblages Microsoft.Data.Schema.ScriptDom.dll et Microsoft.Data.Schema.ScriptDom.Sql.dll.

TSql100Parser parser = new TSql100Parser(false); 

IList<ParseError> errors; 
Expression expr = parser.ParseBooleanExpression(
     new StringReader(condition), 
     out errors 
    ); 

if (errors != null && errors.Count > 0) 
{ 
    // Error handling 
    return; 
} 

Si vous n'obtenez aucune erreur, la chaîne est une expression de filtre valide. Bien qu'il puisse y avoir des expressions nuisibles.

Si vous le souhaitez, vous pouvez exécuter l'expression à travers votre propre visiteur pour détecter les constructions indésirables (telles que les sous-requêtes). Mais sachez que vous devrez remplacer la plupart des 650 surcharges, pour Visit(...) et ExplicitVisit(...). Les classes partielles seraient bien ici.

Lorsque vous êtes satisfait, pourrait alors construire une déclaration SELECT complète, avec toutes les expressions:

var schemaObject = new SchemaObjectName(); 
schemaObject.Identifiers.Add(new Identifier {Value = "MyTable"}); 

var queryExpression = new QuerySpecification(); 
queryExpression.FromClauses.Add(
    new SchemaObjectTableSource {SchemaObject = schemaObject}); 

// Add the expression from before (repeat as necessary) 
Literal zeroLiteral = new Literal 
{ 
    LiteralType = LiteralType.Integer, 
    Value = "0", 
}; 
Literal oneLiteral = new Literal 
{ 
    LiteralType = LiteralType.Integer, 
    Value = "1", 
}; 
WhenClause whenClause = new WhenClause 
{ 
    WhenExpression = expr, // <-- here 
    ThenExpression = oneLiteral, 
}; 
CaseExpression caseExpression = new CaseExpression 
{ 
    ElseExpression = zeroLiteral, 
}; 
caseExpression.WhenClauses.Add(whenClause); 
queryExpression.SelectElements.Add(caseExpression); 

var selectStatement = new SelectStatement {QueryExpression = queryExpression}; 

...et tournez tout dans une chaîne:

var generator = new Sql100ScriptGenerator(); 
string query; 
generator.GenerateScript(selectStatement, out query); 

Console.WriteLine(query); 

Sortie: pour exécuter quelques

SELECT CASE WHEN ITEM_ID = 1 
       OR (ITEM_NAME LIKE 'something' 
        AND ITEM_PRICE > 123 
        AND (ITEM_WEIGHT = 456 
          OR ITEM_HEIGHT < 789)) THEN 1 ELSE 0 END 
FROM MyTable 

Si cette expression est trop grand pour manipuler, vous pouvez toujours diviser les règles en morceaux, au temps.


Bien que, pour être autorisé à redistribuer les fichiers Microsoft.Data.Schema.ScriptDom.*.dll, vous devez posséder une licence de Visual Studio Team System (Est-ce inclus dans au moins VS Pro/Édition Intégrale?)

Lien: http://blogs.msdn.com/b/gertd/archive/2008/08/22/redist.aspx

2

Cela ressemble à vos "règles" ou conditions doivent être effectuées en C# à la place.

Si vous allez réellement introduire 100 000 OR et AND dans la clause WHERE de votre instruction SQL, vous allez avoir beaucoup de mal à dimensionner votre application. Je ne peux qu'imaginer le désordre des index dont vous auriez besoin pour avoir un ensemble arbitraire de 100 000 conditions à appliquer à l'ensemble de données et chaque permutation fonctionne bien. Au lieu de cela, je voudrais exécuter une requête de sélection de base et lire chaque ligne et le filtrer en C# à la place. Ensuite, vous pouvez suivre les conditions/règles qui ne passent pas pour chaque ligne en appliquant chaque règle individuellement et en effectuant un suivi de réussite/échec. Bien sûr, si vous interrogez une très grande table, alors la performance pourrait devenir un problème, mais vous avez déclaré que "L'ensemble des éléments à valider ... ne sont pas un nombre énorme" donc je suppose qu'il serait être relativement rapide pour ramener toutes les données de la table et exécuter vos règles dans le code, ou appliquer un filtrage fondamental à l'avant, puis un filtrage plus spécifique dans le code.


Par curiosité, comment sont les utilisateurs qui entrent dans ces « règles », comme:

ITEM_ID = 1 
OR (ITEM_NAME LIKE 'something' AND ITEM_PRICE > 123 
AND (ITEM_WEIGHT = 456 OR ITEM_HEIGHT < 789)) 

S'il vous plaît s'il vous plaît s'il vous plaît me disent qu'ils ne pénètrent pas dans les requêtes réelles SQL (sous forme de texte) et vous êtes juste leur assemblant, comme:

var sql = "select * from myTable where "; 
foreach(var rule in rules) 
    sql += rule; 

Peut-être une sorte d'interface utilisateur règle constructeur qui construit ces instructions SQL prospectifs?

Questions connexes