J'ai une fonction d'agrégation SQL CLR qui déclenche sporadiquement une exception System.NullReferenceException
lorsqu'elle est exécutée sur le même ensemble de données. Le but de l'agrégat personnalisé est à:La fonction d'agrégat personnalisée lance par intermittence NullReferenceException
Retour dernière (x, y) où x est une colonne
DATETIME
et y est une colonneINTEGER
.La valeur de la colonne y pour la valeur la plus récente de la colonne
x
sera renvoyée.
L'ensemble de données d'être touché par la requête est un sous-ensemble de 142,145 lignes d'une table de rangée 2.931.563, à l'agrégation résultant en (quand il fonctionne) 141,654 rangées étant retournés.
Le code de la fonction d'agrégation CLR est la suivante:
using System.Data.SqlTypes;
using System.Runtime.InteropServices;
using Microsoft.SqlServer.Server;
[StructLayout(LayoutKind.Sequential)]
[SqlUserDefinedAggregate(Format.Native, IsInvariantToDuplicates = true, IsInvariantToNulls = true, IsInvariantToOrder = true, IsNullIfEmpty = true, Name = "Latest")]
public class Latest
{
private SqlDateTime latestDateTime;
private SqlInt32 latestValue;
public void Init()
{
latestDateTime = SqlDateTime.Null;
latestValue = SqlInt32.Null;
}
public void Accumulate(SqlDateTime recordDateTime, SqlInt32 value)
{
if (latestDateTime.IsNull)
{
latestDateTime = recordDateTime;
latestValue = value;
}
else
{
if (recordDateTime > latestDateTime)
{
latestDateTime = recordDateTime;
latestValue = value;
}
}
}
public void Merge(Latest value)
{
if ((value.latestDateTime < latestDateTime) || (latestDateTime.IsNull))
{
latestValue = value.latestValue;
latestDateTime = value.latestDateTime;
}
}
public SqlInt32 Terminate()
{
return latestValue;
}
};
Pour autant que je peux dire qu'il n'y a nulle part dans la fonction qui peut se traduire par une référence null, en supposant que SQL Server suit le contract outlined on MSDN (même si c'est beaucoup plus probable que je me trompe que SQL Server!). Donc, en bref, qu'est-ce qui me manque ici?
Pour clarifier:
- Je crois que je l'ai rencontré les exigences du contrat pour une SqlUserDefinedAggregate (toutes les méthodes nécessaires mises en œuvre)
- Le code initialise toutes les variables membres dans la méthode
Init
(encore une fois partie de l'implémentation du contrat) pour s'assurer que si SQL réutilise (comme c'est permis) une instance de l'agrégat pour un groupe différent, il est nettoyé et non nul. - Il est clair que j'ai manqué une nuance du contrat que j'ai Je suis attendu à rencontrer car je ne vois pas de raison pour l'exception NullReferenceException à lancer. Qu'est-ce que j'ai raté?
Ceci est une classe partielle, y at-il un autre code? Il y a des valeurs nulles sur la colonne x pour le sous-ensemble? – Max
Aucune idée de la raison pour laquelle 'partial' est présent puisqu'il n'y a qu'un seul fichier qui définit cette classe. Bien que cela rende nos commentaires un peu bizarres, je vais supprimer le partial du code pour aider à la clarté :) – Rob
Le seul suspect que l'on puisse voir à distance est value.latestDateTime (dans le void Merge). S'il est possible que la valeur soit nulle, je pense que cela pourrait déclencher l'erreur de référence nulle. –