Code Only Scenario
This article is relevant to entity models that utilize the deprecated Visual Studio integration of Telerik Data Access. The current documentation of the Data Access framework is available here.
The Telerik Data Access Visual Designer is designed to help you build Telerik Data Access applications. With the Visual Designer you can create a domain model from an existing database and then graphically visualize and edit your domain model. Or, you can graphically create a domain model first, and then generate a database that supports your model. In either case, you can automatically update your model when the underlying database changes and automatically generate object-layer code for your application.
However, many developers view their code as their model. Ideally these developers just want to write some class and without ever touching a designer or a piece of XML to be able to use those classes with Telerik Data Access. Basically they want to write "Code Only". Fortunately, Telerik Data Access provides a Fluent Mapping API, which is perfect for these scenarios. This topic will introduce you with the Telerik Data Access Fluent Mapping API.
Creating the Project
To create a new Telerik Data Access domain model using the Fluent Mapping API:
- Select File > New Project in Visual Studio.
- In the list of Installed Templates on the left side of the dialog, select Visual C# or Visual Basic.
-
Then select Telerik Data Access Fluent Library. Name the project FluentModel, and then click OK.
-
This template works in the same way as the Telerik Data Access Class Library project template, which is discussed in the Database First Scenario and Model First Scenario topics. The template will create a new class library project and will run the Telerik Data Access New Model Wizard. However, it will create a new model (from an existing database or an empty one) by using the fluent mapping code generation. The first step in the wizard lets you choose the type of model you want to use. In this step, you have the option of generating a model from a database or starting with an empty model. In this article, you will manually create all fluent classes, so select the Empty fluent model option as shown on the figure below.
Click Finish to generate the model.
What Just Happened?
When you click OK, the template will create a new project and will enhance it to work with Telerik Data Access. In addition, it will add the required references and will add several code files.
What Are These Files?
Open the FluentModelMetadataSource class. It derives from the abstract Telerik.OpenAccess.Metadata.Fluent.FluentMetadataSource class. It will serve as a mapping source that uses fluent configuration to create a mapping model. You have to override the abstract PrepareMapping method (its implementation will be described later). The PrepareMapping method will be your entry point for working with the Telerik Data Access FluentMapping API. It is called when the context instance is initializing and a model needs to be obtained. Or in other words the new FluentMetadataSource class will hold the entire configuration for your classes.
Important: The custom FluentMetadataSource class and your POCO classes must be located in the same project.
When you use Fluent Mapping API, your classes have no knowledge about the Telerik Data Access at all. This is a good thing, as it is the desired effect. However, you need to let Telerik Data Access be aware of the classes. Recall that the Telerik Data Access New Domain Model Wizard does not only create the entity classes, but also creates a class that inherits from OpenAccessContext. Of course without code generation no OpenAccessContext is generated for you. To implement a context that is specific to your model and your entities, you simply create a new class that derives from OpenAccessContext and provides properties of type IQueryable<T>.
Open and explore the FluentModel class. The class derives from the OpenAccessContext class. Your FluentModel needs to be connected to the underlying database just like a generated context. To do this, you pass two things to the constructor. First, you pass a connection string to the underlying database. The second parameter is a new instance of the BackendConfiguration class where you specify the backend to be used (in this example - MS SQL database). Another thing you have pay attention to is that there is a third parameter passed to the base constructor - this is an instance of the FluentMetadataSource class that holds the entire configuration for your classes.
Take a look at the declaration of the connection string.
private static string connectionStringName = @"";
Private Shared connectionStringName As String = ""
You are passing a connection string name to the base constructor (not the real connection string). The real connection string is defined in the configuration file (App.config).
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="connectionId"
connectionString="data source=.\sqlexpress;initial catalog=FluentMappingDatabase;
integrated security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
You need to pass the same connection string name to the FluentModel constructor as the one defined in the configuration file, i.e., you need to pass "connectionId". Modify the connection string declaration in the FluentModel class and set the same name:
private static string connectionStringName = @"connectionId";
Private Shared connectionStringName As String = "connectionId"
Building the Model
You are ready to add code.
- Expand the solution explorer.
-
Add a new class named Customer in the FluentModel project and paste in the code below. This code creates a simple customer class that can be mapped to a database table by Telerik Data Access.
public class Customer { public int ID { get; set; } public string Name { get; set; } public DateTime DateCreated { get; set; } public string EmailAddress { get; set; } }
Public Class Customer 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 Private _name As String Public Property Name() As String Get Return _name End Get Set(ByVal value As String) _name = value End Set End Property Private _dateCreated As Date Public Property DateCreated() As Date Get Return _dateCreated End Get Set(ByVal value As Date) _dateCreated = value End Set End Property Private _emailAddress As String Public Property EmailAddress() As String Get Return _emailAddress End Get Set(ByVal value As String) _emailAddress = value End Set End Property End Class
-
Next, open FluentModelMetadataSource.cs, and replace the existing code for the PrepareMapping method with this one. This code configures passes an anonymous type to the MapType method. The properties of the anonymous type will be what Telerik Data Access uses to create columns in the database. The ToTable method tells Telerik Data Access what the customer table should be named in the database.
protected override IList<MappingConfiguration> PrepareMapping() { List<MappingConfiguration> configurations = new List<MappingConfiguration>(); var customerMapping = new MappingConfiguration<Customer>(); customerMapping.MapType(customer => new { ID = customer.ID, Name = customer.Name, EmailAddress = customer.EmailAddress, DateCreated = customer.DateCreated }).ToTable("Customer"); customerMapping.HasProperty(c => c.ID).IsIdentity(); configurations.Add(customerMapping); return configurations; }
Protected Overrides Function PrepareMapping() As System.Collections.Generic.IList(Of MappingConfiguration) Dim configurations As New List(Of MappingConfiguration)() Dim customerMapping = New MappingConfiguration(Of Customer)() customerMapping.MapType(Function(customer) New With { Key .ID = customer.Id, Key .Name = customer.Name, Key .EmailAddress = customer.EmailAddress, Key .DateCreated = customer.DateCreated}).ToTable("Customer") customerMapping.FieldNamingRules.AddPrefix = "_" customerMapping.HasProperty(Function(p) p.Id).IsIdentity() configurations.Add(customerMapping) Return configurations End Function
-
Open FluentModel.cs, add a property exposing the Customers collection. The code below exposes the Customer objects as an IQueryable<Customer> this allows Telerik Data Access to offload queries to the database to do the heavy lifting. It also makes it easy to query entity sets using standard LINQ.
public IQueryable<Customer> Customers { get { return this.GetAll<Customer>(); } }
Public ReadOnly Property Customers() As IQueryable(Of Customer) Get Return Me.GetAll(Of Customer)() End Get End Property
At this point the model is fully configured.
Deploying the Database
You need a project that will consume your data project. You might be asking why you created a separated project for your classes. The answer is simply because you want to compile your classes into a separate and distinct assembly from the UI project.
-
For the sake of simplicity, add to your solution a new Console Application. For example, name the project FluentModelClient.
Make the FluentModelClient project a startup project (right click on the ConsoleApplication in Solution Explorer, and select Set as StartUp Project).
-
Add references to:
- Telerik.OpenAccess.dll
- Telerik.OpenAccess.35.Extensions.dll
- The model project, in the case of this guide - FluentModel.
-
Copy the App.Config file from the FluentModel project and paste it in the FluentModelClient project. The reason for that action is that the FluentModelClient project is the main (executable) project for the application. When you run the application all settings (configurations) are taken from that project. Respectively, the OpenAccessContext will try to retreive the connection string from the config file in the main project. If a such doesn't exist, the initialization of the OpenAccessContext will fail.
-
Open Program.cs in the Console Application. Add the following code for initializing the database.
using Telerik.OpenAccess; namespace FluentModelClient { class Program { static void Main(string[] args) { UpdateDatabase(); } private static void UpdateDatabase() { using (var context = new FluentModel.FluentModel()) { var schemaHandler = context.GetSchemaHandler(); EnsureDB(schemaHandler); } } private static void EnsureDB(ISchemaHandler schemaHandler) { string script = null; if (schemaHandler.DatabaseExists()) { script = schemaHandler.CreateUpdateDDLScript(null); } else { schemaHandler.CreateDatabase(); script = schemaHandler.CreateDDLScript(); } if (!string.IsNullOrEmpty(script)) { schemaHandler.ExecuteDDLScript(script); } } } }
Imports Telerik.OpenAccess Module Module1 Sub Main() UpdateDatabase() End Sub Private Sub UpdateDatabase() Using context = New FluentModel.FluentModel() Dim schemaHandler = context.GetSchemaHandler() EnsureDB(schemaHandler) End Using End Sub Private Sub EnsureDB(ByVal schemaHandler As ISchemaHandler) Dim script As String = Nothing If schemaHandler.DatabaseExists() Then script = schemaHandler.CreateUpdateDDLScript(Nothing) Else schemaHandler.CreateDatabase() script = schemaHandler.CreateDDLScript() End If If Not String.IsNullOrEmpty(script) Then schemaHandler.ExecuteDDLScript(script) End If End Sub End Module
This code creates a new instance of the OpenAccessContext created when building the model using the Fluent Mapping API. It then checks to see if the database exists, if not the database is created, and then the schema is applied. If the database already exists, Telerik Data Access will create and run a migration script against the database. At this point when you run the application Telerik Data Access will update the database based on any changes made in the fluent mapping.
Next Steps
For more information, check out the Code-Only section.