Comparaisons de valeurs Null
Une valeur null dans la source de données indique que la valeur est inconnue. Dans les requêtes LINQ to Entities, vous pouvez vérifier les valeurs Null afin que certains calculs ou certaines comparaisons soient effectués uniquement sur les lignes qui ont des données valides, ou non Null. Toutefois, la sémantique Null CLR peut différer par rapport à la sémantique Null de la source de données. La plupart des bases de données utilisent une version de logique à trois valeurs pour gérer les comparaisons de valeurs Null. Autrement dit, une comparaison avec une valeur Null n'a pas la valeur true ou false ; elle a la valeur unknown. Il s'agit souvent d'une implémentation de valeurs ANSI Null, mais ce n'est pas toujours le cas.
Par défaut dans SQL Server, la comparaison Null-égale-Null retourne une valeur Null. Dans l'exemple suivant, les lignes dans lesquelles Region a la valeur Null sont exclues du jeu de résultats, et l'instruction Transact-SQL retournerait 0 ligne.
-- Find orders and customers with no regions.
SELECT a.[CustomerID]
FROM [Northwind].[dbo].[Customers] a
JOIN [Northwind].[dbo].[Orders] b ON a.Region = b.ShipRegion
WHERE a.Region IS Null
C'est très différent de la sémantique Null CLR, où la comparaison Null-égale-Null retourne true.
La requête LINQ suivante est exprimée dans le CLR, mais elle est exécutée dans la source de données. Étant donné que rien ne garantit que la sémantique CLR sera respectée au niveau de la source de données, le comportement attendu est indéterminé.
Using NwEntities As New NorthwindEntities()
Dim customers As ObjectQuery(Of Customers) = NwEntities.Customers
Dim orders As ObjectQuery(Of Orders) = NwEntities.Orders
Dim query = _
From c In customers _
Join o In orders On c.Region Equals o.ShipRegion _
Where c.Region = Nothing _
Select c.CustomerID
For Each customerID In query
Console.WriteLine("Customer ID: ", customerID)
Next
End Using
using (NorthwindEntities NwEntities = new NorthwindEntities())
{
ObjectQuery<Customers> customers = NwEntities.Customers;
ObjectQuery<Orders> orders = NwEntities.Orders;
IQueryable<string> query = from c in customers
join o in orders on c.Region equals o.ShipRegion
where c.Region == null
select c.CustomerID;
foreach (string customerID in query)
{
Console.WriteLine("Customer ID: {0}", customerID);
}
}
Sélecteurs de clé
Un sélecteur de clé est une fonction utilisée dans les opérateurs de requête standard pour extraire une clé d'un élément. Dans la fonction du sélecteur de clé, une expression peut être comparée avec une constante. La sémantique Null CLR est exposée si une expression est comparée à une constante Null ou si deux constantes Null sont comparées. La sémantique Null du magasin est exposée si deux colonnes contenant des valeurs Null dans la source de données sont comparées. Les sélecteurs de clé, qui se trouvent dans un grand nombre des opérateurs de requête standard de tri et de regroupement, tels que GroupBy, sont utilisés pour sélectionner les clés sur lesquelles trier ou regrouper les résultats de la requête.
Propriété Null sur un objet Null
Dans Entity Framework, les propriétés d'un objet Null sont Null. Lorsque vous essayez de référencer une propriété d'un objet Null dans le CLR, vous recevez un objet NullReferenceException. Lorsqu'une requête LINQ implique une propriété d'un objet Null, cela peut provoquer un comportement incohérent.
Par exemple, dans la requête suivante, le cast en NewProduct
est effectué dans la couche de l'arborescence de commandes, ce qui peut rendre Null la propriété Introduced
. Si la base de données a défini des comparaisons de valeurs Null de sorte que la comparaison DateTime ait la valeur true, la ligne sera incluse.
Using AWEntities As New AdventureWorksEntities()
Dim dt As DateTime = New DateTime()
Dim query = AWEntities.Product _
.Where(Function(p) _
((DirectCast(p, NewProduct)).Introduced > dt)) _
.Select(Function(x) x)
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
DateTime dt = new DateTime();
var query = AWEntities.Product
.Where(p => (p as NewProduct).Introduced > dt)
.Select(x => x);
}