I try to do some stupid EF tests.
From Northwind Product table, I did following inheritance:
<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>
with this mapping:
<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>
So in fact, what do I want to do?
What happens if ObjectContext don't know which type instanciate? Indeed, with my DB, I have some products with Discontinued=true and ReorderLevel=0. So which type should ObjectContext instanciate? DiscontinuedProduct or ProductReorder0?
Of course, I have an EDM error but, as the compiler only use the generated code, I can work with this.
I execute following code for my test:
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());
}
In the first two cases, there is no exception which is very interesting. This means that the OfType determines not only the sql request but also the entity instanciation.
In the third case, when I execute q2, we will have an exception. Indeed, the 3 entity types are linked to the same EntitySet. Each entity has an EntityKey which must be unique in the EntitySet. In the third case, the first Product with Discontinued = true and ReorderLevel = 0 will throw an exception.
In the last case, we will have an exception because ObjectContext doesn't know which entity type instanciate.