This is a refresh of an older blog that demonstrates Telerik OpenAccess ORM working together with Ado.net Data Services and SilverLight. This time we updated the client-side a bit, using our RadControls for SilverLight. Since some of the steps are basically the same as in the previous example don’t be surprised if you find something familiar.

 

We are continuously investing into better LINQ support for our product, and this is just we need to plug into the Ado.net Data Services framework.

 

Now let’s get to the application!

Firstly we have to build our data model.

To do so add a library project to the solution. The library project will host our data model and that way we will have a better separation of concerns.

After we have the library project in the solution we have to build our model using the Open Access tool. For the purpose of this example we will reverse map all tables from the Northwind database.

To do so first enable the class library to use OpenAccess. This can be easily done by our Enable Project Wizard.

After the project gets “Open Access enhanced” we can start the Reverse Mapping wizard (Main Menu > Telerik>OpenAccess > Reverse Mapping (Table to Classes)). Switch to the advanced tab and expand the Tables node. Expand the OrderDetails class and click on the order field. Check the Create one to many list check box. This will add an collection of type OrderDetails to your Order class. We will use this collection for easier cascading delete later. From this step forward the add-in will guide you.

When you reverse map your classes it’s often the case that the Data services won’t be able to recognize the keys for few of the entities in the data model.  In order to "help" the data service recognize this keys you will need to use the DataServiceKey attribute on top of your class. Here is an example of how the code should look like:

[DataServiceKey(new string[]{"OrderID","ProductID"})]
   
public partial class OrderDetail : INotifyPropertyChanging, INotifyPropertyChanged
       
[Telerik.OpenAccess.FieldAlias("orderID")]
       
public int OrderID
       
{
           
get { return orderID; }
           
set
           
{
               
OnPropertyChanging("OrderID");
               
this.orderID = value;
               
OnPropertyChanged("OrderID");
           
}
       
}

Note that all of our classes have been generated using a modified templates that have INotifyPropertyChanging and INotifyPropertyChanged implemented by default. You can find those templates here.

After we generated the entities we have to provide a data context implementation for our OADataService data service. Add a class named OADataContext.cs in your Model project.

What do we need inside the class to provide all resources needed for the data service? Actually the ADS team allowed us to have quite broad implementation of the class: What we really need are properties that implement the IQueryable interface thus exposing the underlying data in a standard way to the ADS communications stack above. So for the Order entities we put a property like:

public IQueryable<Order> Orders
       
{
           
get
           
{
               
return this.GetAll<Order>();
           
}
       
}

Note that the Orders class has property of type that is not automatically considered as a resource set by ADO .NET Data Services. In fact, without some more information it is really hard for the Data Services to automatically expose a new resource set through a resource container. The only solution as for now is to expose Customer class as well. Note that you will also need to specify the DataServiceKey attribute for Customer as well.(You will need to do this for all properties that are from custom types).

The scope variable is actually an instance of IObjectScope – Open Access implements the actual data context through this interface. So to start providing data we need a couple of lines of code and they look like:

public partial class OADataContext : IDisposable
{
   
// Fields
    IObjectScope scope = null;

   
public OADataContext()
   
{
       
this.scope = this.ProvideScope();
   
}

   
public OADataContext(IObjectScope scope)
   
{
       
this.scope = scope;
   
}

   
public virtual IObjectScope Scope
   
{
       
get
       
{
           
if (this.scope == null)
           
{
               
// Attempt to get the Scope
                this.scope = this.ProvideScope();
           
}
           
return this.scope;
       
}
   
}

   
public IQueryable<Product> Products
   
{
       
get
       
{
           
return this.scope.Extent<Product>();
       
}
   
}

   
protected virtual IObjectScope ProvideScope()
   
{
       
IObjectScope scope = ObjectScopeProvider1.GetNewObjectScope();
       
scope.TransactionProperties.AutomaticBegin = true;
       
return scope;
   
}
   
#region IDisposable Members

   
public void Dispose()
   
{
       
if (scope != null)
       
{
           
scope.Dispose();
           
scope = null;
       
}
   
}
   
#endregion
}

Then we have to update the file we generated for our OADataService (it generates with compilation errors, and I believe they did it on purpose :) )
Having a data context means that we will modify the OADataService file like this:

 

[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class OADataService : DataService<OADataContext>
{
   
protected override void HandleException(HandleExceptionArgs args)
   
{
       
base.HandleException(args);
   
}

   
// This method is called only once to initialize service-wide policies.
    //We overide it to enable all CRUD operations by setting EntitySetRights.All
    public static void InitializeService(IDataServiceConfiguration config)
   
{
       
config.SetEntitySetAccessRule("*", EntitySetRights.All);
   
}
}

You should note the following:
- You have to refer the Model project from the web site or you will not be able to access the OADataContext type.
- The WCF attribute [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)] is very helpful when troubleshooting the service – without it you will not be able to gather enough information about the errors that may arise.
- the OADataContext source code is already distributed with the product installer as of version 2008.3 1205.
 Note: After Q2 release the OpenAccessDataContext will be available as a separate assembly that can be used out of the box.
In the next post I will guide you how not only to feed data to the client, but also to implement all CRUD operations on the server based on Open Access O/R tool.


Related Posts

Comments