EF et le testeur fou
Je me suis amusé à faire des tests idiots avec l'Entity Framework.
A partir de la table Product de Northwind, j'ai réalisé l'héritage suivant :
<EntityType Name="Product">
<Key>
<PropertyRef Name="ProductID" />
</Key>
<Property Name="ProductID" Type="Int32" Nullable="false" />
<Property Name="ProductName" Type="String" Nullable="false" MaxLength="40" Unicode="true" FixedLength="false" />
<Property Name="SupplierID" Type="Int32" />
<Property Name="CategoryID" Type="Int32" />
<Property Name="QuantityPerUnit" Type="String" MaxLength="20" Unicode="true" FixedLength="false" />
<Property Name="UnitPrice" Type="Decimal" Precision="19" Scale="4" />
<Property Name="UnitsInStock" Type="Int16" />
<Property Name="UnitsOnOrder" Type="Int16" />
</EntityType>
<EntityType Name="ProductReorder0" BaseType="NorthwindModel3.Product" >
<Property Name="Discontinued" Type="Boolean" Nullable="false" />
</EntityType>
<EntityType Name="DiscontinuedProduct" BaseType="NorthwindModel3.Product" >
<Property Name="ReorderLevel" Type="Int16" Nullable="true" />
</EntityType>
avec le mapping suivant :
<EntityTypeMapping TypeName="IsTypeOf(NorthwindModel3.ProductReorder0)">
<MappingFragment StoreEntitySet="Products" >
<ScalarProperty Name="Discontinued" ColumnName="Discontinued" />
<ScalarProperty Name="UnitsOnOrder" ColumnName="UnitsOnOrder" />
<ScalarProperty Name="UnitsInStock" ColumnName="UnitsInStock" />
<ScalarProperty Name="UnitPrice" ColumnName="UnitPrice" />
<ScalarProperty Name="QuantityPerUnit" ColumnName="QuantityPerUnit" />
<ScalarProperty Name="CategoryID" ColumnName="CategoryID" />
<ScalarProperty Name="SupplierID" ColumnName="SupplierID" />
<ScalarProperty Name="ProductName" ColumnName="ProductName" />
<ScalarProperty Name="ProductID" ColumnName="ProductID" />
<Condition ColumnName="ReorderLevel" Value="0" />
</MappingFragment>
</EntityTypeMapping>
<EntityTypeMapping TypeName="IsTypeOf(NorthwindModel3.DiscontinuedProduct)">
<MappingFragment StoreEntitySet="Products" >
<ScalarProperty Name="ReorderLevel" ColumnName="ReorderLevel" />
<ScalarProperty Name="UnitsOnOrder" ColumnName="UnitsOnOrder" />
<ScalarProperty Name="UnitsInStock" ColumnName="UnitsInStock" />
<ScalarProperty Name="UnitPrice" ColumnName="UnitPrice" />
<ScalarProperty Name="QuantityPerUnit" ColumnName="QuantityPerUnit" />
<ScalarProperty Name="CategoryID" ColumnName="CategoryID" />
<ScalarProperty Name="SupplierID" ColumnName="SupplierID" />
<ScalarProperty Name="ProductName" ColumnName="ProductName" />
<ScalarProperty Name="ProductID" ColumnName="ProductID" />
<Condition ColumnName="Discontinued" Value="true" />
</MappingFragment>
</EntityTypeMapping>
<EntityTypeMapping TypeName="NorthwindModel3.Product">
<MappingFragment StoreEntitySet="Products">
<ScalarProperty Name="ProductID" ColumnName="ProductID" />
<ScalarProperty Name="UnitsOnOrder" ColumnName="UnitsOnOrder" />
<ScalarProperty Name="UnitsInStock" ColumnName="UnitsInStock" />
<ScalarProperty Name="UnitPrice" ColumnName="UnitPrice" />
<ScalarProperty Name="QuantityPerUnit" ColumnName="QuantityPerUnit" />
<ScalarProperty Name="CategoryID" ColumnName="CategoryID" />
<ScalarProperty Name="SupplierID" ColumnName="SupplierID" />
<ScalarProperty Name="ProductName" ColumnName="ProductName" />
<Condition ColumnName="Discontinued" Value="false" />
</MappingFragment>
</EntityTypeMapping>
Concrètement, le test que je voulais faire est : que se passe-t-il si l'ObjectContext ne sait pas qu'elle type il doit instancier ? En effet, dans le cas de Northwind, j'ai des produits avec ReoderLevel = 0 et Discontinued = true. Donc que doit-il instancier ? un ProductReorder0 ou un DiscontinuedProduct ?
Bien entendu, j'ai une erreur sur mon edm, cependant, le compilateur n'utilisant que le code généré par mon edm, l'erreur n'est pas blocante.
Voici les tests que j'ai effectué :
using (var context = new NorthwindEntities())
{
var q = context.Products.OfType<DiscontinuedProduct>();
foreach (var p in q)
if (p.GetType() != typeof(Product))
Console.WriteLine(p.GetType());
}
using (var context = new NorthwindEntities())
{
var q = context.Products.OfType<ProductReorder0>();
foreach (var p in q)
if (p.GetType() != typeof(Product))
Console.WriteLine(p.GetType());
}
using (var context = new NorthwindEntities())
{
var q1 = context.Products.OfType<DiscontinuedProduct>();
foreach (var p in q1)
if (p.GetType() != typeof(Product))
Console.WriteLine(p.GetType());
var q2 = context.Products.OfType<ProductReorder0>();
foreach (var p in q2)
if (p.GetType() != typeof(Product))
Console.WriteLine(p.GetType());
}
using (var context = new NorthwindEntities())
{
var q = context.Products;
foreach (var p in q)
if (p.GetType() != typeof(Product))
Console.WriteLine(p.GetType());
}
Dane les deux premiers cas, cela se passe très bien, ce qui est très intéressant. Cela signifie en effet que le OfType n'influe pas que sur la requête sql généré mais aussi sur l'instanciation des entités.
Dans le troisième cas, lorque l'on va exécuter q2, on va avoir une exception. En effet, les 3 types sont liés au même EntitySet. Chaque entité a une EntityKey qui doit être unique pour l'EntitySet. Dans le troisième cas, le premier Produit avec Discontinued = true et ReorderLevel = 0 génèrera donc une exception.
Dans le quatrième cas, j'ai également une exception car il ne sait pas quoi instancier.
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :