Mapping Artificial Types
Artificial types are types that are not present in the model itself but are defined during runtime.
This walkthrough demonstrates you how to create a new artificial type and customize it, as follows:
- Mapping new artificial types
- Mapping artificial properties
- Mapping artificial association
-
Updating database schema runtime
To complete this tutorial, you must have a basic understanding of the Telerik Data Access Fluent Mapping API.
The MappingConfiguration class provides extension methods for working with artificial types. In order to use them, you need to use/import the Telerik.OpenAccess.Metadata.Fluent.Artificial namespace.
Currently one of the limitations of Telerik Data Access is that you cannot have a Telerik Data Access project running without at least one persistent type defined. This basically means that you have to have a plain CLR type that is part of your model in order to run a Telerik Data Access project. There is no way to run Telerik Data Access entirely on artificial types. The simplest solution in this case is to add a dummy class to your model and create a new configuration. In this tutorial the following dummy class will be used:
public class TestClass
{
public int ID { get; set; }
}
Public Class TestClass
Private _iD As Integer
Public Property ID() As Integer
Get
Return _iD
End Get
Set(ByVal value As Integer)
_iD = value
End Set
End Property
End Class
Of course, if you are mixing CLR types with artificial types, like in the Mixing CLR Types and Artificial Properties tutorial, then everything should work without adding dummy classes.
Creating a New Artificial Type
In the following example two artificial types are created - FluentModel.Product and FluentModel.Category. Then, by using the generic HasArtificialPrimitiveProperty<T> method, primary keys for the Product and Category types are created. There are few things you should take care of when you configure artificial types:
- The class name should not match any class name in the given namespace.
- You have to define a new primary key property for that class.
public class FluentModelMetadataSource : FluentMetadataSource
{
protected override IList<MappingConfiguration> PrepareMapping()
{
List<MappingConfiguration> configurations = new List<MappingConfiguration>();
MappingConfiguration productConfiguration = new MappingConfiguration( "Product", "FluentModel" );
productConfiguration.HasArtificialPrimitiveProperty<int>( "Id" ).IsIdentity();
MappingConfiguration categoryConfiguration = new MappingConfiguration( "Category", "FluentModel" );
categoryConfiguration.HasArtificialPrimitiveProperty<int>( "Id" ).IsIdentity();
MappingConfiguration<TestClass> testConfiguration = new MappingConfiguration<TestClass>();
testConfiguration.MapType();
testConfiguration.HasProperty( x => x.ID ).IsIdentity();
configurations.Add( testConfiguration );
configurations.Add( productConfiguration );
configurations.Add( categoryConfiguration );
return configurations;
}
}
Public Class FluentModelMetadataSource
Inherits FluentMetadataSource
Protected Overrides Function PrepareMapping() As _
System.Collections.Generic.IList(Of Telerik.OpenAccess.Metadata.Fluent.MappingConfiguration)
Dim configurations As List(Of MappingConfiguration) = New List(Of MappingConfiguration)()
Dim productConfiguration As New MappingConfiguration("Product", "FluentModel")
productConfiguration.HasArtificialPrimitiveProperty(Of Integer)("Id").IsIdentity()
Dim categoryConfiguration As New MappingConfiguration("Category", "FluentModel")
categoryConfiguration.HasArtificialPrimitiveProperty(Of Integer)("Id").IsIdentity()
Dim testConfiguration As New MappingConfiguration(Of TestClass)()
testConfiguration.MapType()
testConfiguration.HasProperty(Function(x) x.ID).IsIdentity()
testConfiguration.FieldNamingRules.AddPrefix = "_"
configurations.Add(testConfiguration)
configurations.Add(productConfiguration)
configurations.Add(categoryConfiguration)
Return configurations
End Function
End Class
Creating Artificial Properties
In the previous section, you already saw how to declare a primary key property for artificial types. Let's continue by declaring several artificial properties for the Product and Category types.
productConfiguration.HasArtificialStringProperty( "ProductName" );
productConfiguration.HasArtificialPrimitiveProperty<int>( "Price" );
categoryConfiguration.HasArtificialStringProperty( "CategoryName" );
categoryConfiguration.HasArtificialStringProperty( "Description" );
categoryConfiguration.HasArtificialProperty<byte[]>( "CategoryImage" );
productConfiguration.HasArtificialStringProperty("ProductName")
productConfiguration.HasArtificialPrimitiveProperty(Of Integer)("Price")
categoryConfiguration.HasArtificialStringProperty("CategoryName")
categoryConfiguration.HasArtificialStringProperty("Description")
categoryConfiguration.HasArtificialProperty(Of Byte())("CategoryImage")
The HasArtificialStringProperty extension method is used when you want to create a new string artificial property. The same could be achieved if you use the generic HasArtificialPrimitiveProperty<T>: productConfiguration.HasArtificialPrimitiveProperty<string>("Name");. For the declaration of any other primitive property such as int, double, bool, etc., the generic HasArtificialPrimitiveProperty<T> extension method should be used. The HasArtificialProperty<T> extension method should be used only when the artificial property could not be declared by the other methods exposed by the Fluent Mapping API.
Creating Artificial Associations
You can create associations between the artificial types by using the HasArtificialAssociation and HasArtificialCollectionAssociation extension methods. For this tutorial, a new one-to-many association will be created between the Product and the Category types.
productConfiguration.
HasArtificialAssociation( "Category", categoryConfiguration.ConfiguredType ).
WithOppositeCollection( "Products" );
categoryConfiguration.
HasArtificialCollectionAssociation( "Products", productConfiguration.ConfiguredType ).
WithOpposite( "Category" );
productConfiguration.
HasArtificialAssociation("Category", categoryConfiguration.ConfiguredType).
WithOppositeCollection("Products")
categoryConfiguration.
HasArtificialCollectionAssociation("Products", productConfiguration.ConfiguredType).
WithOpposite("Category")
The previous code will add a new reference property named Category which is of type Category to the Product type. Respectively a collection of Products will be added to the Category type.
You can specify the name of the foreign key column by using the ToColumn method. For example:
productConfiguration.HasArtificialAssociation("Category", categoryConfiguration.ConfiguredType)
.WithOppositeCollection("Products").ToColumn("CategoryId");
productConfiguration.HasArtificialAssociation("Category", categoryConfiguration.ConfiguredType).WithOppositeCollection("Products").ToColumn("CategoryId")
Note that you don't need to create an additional artificial property named CategoryId. Telerik Data Access will create automatically this column in the database.
The artificial associations are discussed in the Artificial Associations section.
Updating the Database Schema Runtime
Once you have an OpenAccessContext and artificial types defined, you can easily update the database schema runtime by using the methods exposed by the FluentModelContext class.
The UpdateSchema method is available in the FluentModelContext class only if you have used the Telerik Data Access Fluent Library Visual Studio template to generate the FluentLibrary project. For more information, see How to: Create/Migrate Your Database.
using ( FluentModelContext dbContext = new FluentModelContext() )
{
dbContext.UpdateSchema();
}
Using dbContext As New FluentModelContext()
dbContext.UpdateSchema()
End Using