Telerik OpenAccess Classic

Telerik OpenAccess ORM Send comments on this topic.
How to: Use ObjectContainer as an alternative of the ObjectScope in ASP .NET with web services
Programmer's Guide > OpenAccess ORM Classic (Old API) > OpenAccess Tasks > Working with Objects > How to: Use ObjectContainer as an alternative of the ObjectScope in ASP .NET with web services

Glossary Item Box

This documentation article is a legacy resource describing the functionality of the deprecated OpenAccess Classic only. The contemporary documentation of Telerik OpenAccess ORM is available here.

The example that is demonstrated in this article  is using as a starting point the “Sofia Car Rental” application that is developed in our Getting Started chapter of the OpenAccess documentation. It is recommended to read the “Getting Started” section of the Telerik OpenAccess ORM documentation before proceeding with this article.

Scenario:

The administrator of “Sofia Car Rental” has a page where he/she is able to modify the available “Car” objects and also add or delete ones. The administrator role requires to do this in a disconnected manner so the changes are made internally and then brought to public in a batch when decided so. For that purpose the admin page loads the “Car” objects from a Web Service which transfers them in an ObjectContainer. The changes that the administrator makes are reflected only in ObjectContainer and that way the other pages that interact with the customers remain unchanged. All changes become visible when the administrator sends the set of changes from the ObejctContainer back to the server, using another method of the web service. This method reflects the changes in the “SofiaCarRental” database and also refreshes the ObjectContainer itself preventing it from containing inconsistent and obsolete data.

Implementation:

First thing to implement is the GetAllCars() method of the web service which returns a ChangeSet content and this is what gets loaded in the initialization of the container.

C# Copy Code
[WebMethod]
public Telerik.OpenAccess.ObjectContainer.ChangeSet GetAllCars()
{

   ObjectContainer.ChangeSet ccData =
null;
   IObjectScope os = ObjectScopeProvider1.GetNewObjectScope();

   os.Transaction.Begin();
   
try
   {
       
string resultName = "Cars";
       
string query = "SELECT * FROM CarExtent AS x";
       IQuery qry = os.GetOqlQuery(query);
       IQueryResult qres = qry.Execute();

       ObjectContainer oc =
new ObjectContainer();

       Telerik.OpenAccess.IObjectCollector objCollector =
       
new FetchGroupCollector(FetchGroupCollector.DefaultFetchGroup);

       
if (qres != null)
       {
           oc.CopyFrom(os, resultName, qres, objCollector);
       }
       
else
       {
           
oc.CopyFrom(os, resultName, qres, null);

       }
           ccData = oc.GetContent();
   }
   
finally
   {
       
os.Transaction.Rollback();
       os.Dispose();
   }
   
return ccData;
}  
VB .NET Copy Code
<WebMethod> _
Public Function GetAllCars() As Telerik.OpenAccess.ObjectContainer.ChangeSet
 Dim ccData As ObjectContainer.ChangeSet = Nothing
 Dim os As IObjectScope = ObjectScopeProvider1.GetNewObjectScope()
 os.Transaction.Begin()
 Try
  Dim resultName As String = "Cars"
  Dim query As String = "SELECT * FROM CarExtent AS x"
  Dim qry As IQuery = os.GetOqlQuery(query)
  Dim qres As IQueryResult = qry.Execute()
  Dim oc As New ObjectContainer()
  Dim objCollector As Telerik.OpenAccess.IObjectCollector = New FetchGroupCollector(FetchGroupCollector.DefaultFetchGroup)
  If qres IsNot Nothing Then
   oc.CopyFrom(os, resultName, qres, objCollector)
  Else
   oc.CopyFrom(os, resultName, qres, Nothing)
  End If
   ccData = oc.GetContent()
 Finally
  os.Transaction.Rollback()
  os.Dispose()
 End Try
 Return ccData
End Function

First an object scope is obtained from to the “SofiaCarRental” database and all the car objects are fetched from the database. After that an ObjectContainer instance is created and then it gets filled with the result of the previous query from the object scope. The CopyFrom() method of the container is a way of filling the ObjectContainer with objects.

The method returns a ChangeSet which represent the content of this container. That is the content that gets applied by the ObjectContainer in the Admin page.

Below is the code of the Page_Load method in the Admin page where the ObjectContainer gets initialized and filled with the necessary content.

C# Copy Code
protected void Page_Load(object sender, EventArgs e)
{
   
if (Session["container"] == null)
   {
       ObjectContainer container =
new ObjectContainer();
       CarRentalAdministratorService service =
new CarRentalAdministratorService();
       container.Apply(service.GetAllCars());
       Session[
"container"] = container;
   }
   
else
   {
       
ObjectContainer container = (ObjectContainer)Session["container"];
   }
}  
VB .NET Copy Code
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
 If Session("container") Is Nothing Then
  Dim container As New ObjectContainer()
  Dim service As New CarRentalAdministratorService()
  container.Apply(service.GetAllCars())
  Session("container") = container
 Else
  Dim container As ObjectContainer = CType(Session("container"), ObjectContainer)
 End If
End Sub

NOTE: ObjectContainer should be used carefully in large web sites since it is stored in Session. If there are too many objects in the container it can become too “heavy” and it is not a good practice to store large amount of data in the Session state as it slows down the server.

The Admin web page contains a RadGrid for interactive execution of all the CRUD operations against the container and a Button which submits the changes made by the administrator to the database server. There are few event handlers that should be implemented to make all these operations possible.

First we should hook up for the NeedDatasource event of the RadGrid. Here is the code of the method that is invoked on this event:

C# Copy Code
protected void RadGrid1_NeedDataSource(object source, Telerik.Web.UI.GridNeedDataSourceEventArgs e)
{
   ObjectContainer container = (ObjectContainer)Session[
"container"];
   RadGrid1.DataSource = LoadCars(container);
}

private IList LoadCars(Telerik.OpenAccess.ObjectContainer container)
{
   
return container.NamedList("Cars");
}   
VB .NET Copy Code
Protected Sub RadGrid1_NeedDataSource(ByVal source As Object, ByVal e As Telerik.Web.UI.GridNeedDataSourceEventArgs)
 Dim container As ObjectContainer = CType(Session("container"), ObjectContainer)
 RadGrid1.DataSource = LoadCars(container)
End Sub
Private Function LoadCars(ByVal container As Telerik.OpenAccess.ObjectContainer) As IList
 Return container.NamedList("Cars")
End Function

The objects in the object container are grouped in named lists. The only named list in this case is only the “Cars” named list. When calling the container.NamedList() method of the container with a name of a specific list as a parameter it returns an IList collection from all the objects that are part of it. That collection is used to bind the RadGrid to.
Next are the Insert, Delete and Update commands of the RadGrid:

C# Copy Code
protected void RadGrid1_DeleteCommand(object source, Telerik.Web.UI.GridCommandEventArgs e)
{
    
string carID = ((GridDataItem)e.Item).GetDataKeyValue("CarID").ToString();
    ObjectContainer container = (ObjectContainer)Session[
"container"];
    container.Transaction.Begin();
    Car car = (Car)container.GetObjectById(Database.OID.ParseObjectId(
typeof(Car), carID));
    container.Remove(car);
    container.NamedList(
"Cars").Remove(car);
    container.Transaction.Commit();
}

protected void RadGrid1_UpdateCommand(object source, GridCommandEventArgs e)
{
    
string carID = ((GridEditFormItem)e.Item).ParentItem.GetDataKeyValue("CarID").ToString();
    ObjectContainer container = (ObjectContainer)Session[
"container"];
    container.Transaction.Begin();
    Car car = (Car)container.GetObjectById(Database.OID.ParseObjectId(
typeof(Car), carID));
    ((GridEditableItem)e.Item).UpdateValues(car);
    container.Transaction.Commit();

}

protected void RadGrid1_InsertCommand(object source, GridCommandEventArgs e)
{
   ObjectContainer container = (ObjectContainer)Session[
"container"];
   container.Transaction.Begin();
   Car newCar =
new Car();
   ((GridEditableItem)e.Item).UpdateValues(newCar);
   container.Add(newCar);
   container.NamedList(
"Cars").Add(newCar);
   container.Transaction.Commit();
}
VB .NET Copy Code
Protected Sub RadGrid1_DeleteCommand(ByVal source As Object, ByVal e As Telerik.Web.UI.GridCommandEventArgs)
Dim carID As String = (CType(e.Item, GridDataItem)).GetDataKeyValue("CarID").ToString()
Dim container As ObjectContainer = CType(Session("container"), ObjectContainer)
container.Transaction.Begin()
Dim car As Car = CType(container.GetObjectById(Database.OID.ParseObjectId(GetType(Car), carID)), Car)
container.Remove(car)
container.NamedList("Cars").Remove(car)
container.Transaction.Commit()
End Sub
Protected Sub RadGrid1_UpdateCommand(ByVal source As Object, ByVal e As GridCommandEventArgs)
Dim carID As String = (CType(e.Item, GridEditFormItem)).ParentItem.GetDataKeyValue("CarID").ToString()
Dim container As ObjectContainer = CType(Session("container"), ObjectContainer)
container.Transaction.Begin()
Dim car As Car = CType(container.GetObjectById(Database.OID.ParseObjectId(GetType(Car), carID)), Car)
CType(e.Item, GridEditableItem).UpdateValues(car)
container.Transaction.Commit()
End Sub
Protected Sub RadGrid1_InsertCommand(ByVal source As Object, ByVal e As GridCommandEventArgs)
Dim container As ObjectContainer = CType(Session("container"), ObjectContainer)
container.Transaction.Begin()
Dim newCar As New Car()
CType(e.Item, GridEditableItem).UpdateValues(newCar)
container.Add(newCar)
container.NamedList("Cars").Add(newCar)
container.Transaction.Commit()
End Sub

The button that calls the Web Service method which updates the database and refreshes the ObjectContainer has the following code listening on its Click event:

C# Copy Code
protected void Button1_Click(object sender, EventArgs e)
{
   ObjectContainer container = (Telerik.OpenAccess.ObjectContainer)Session[
"container"];
   ObjectContainer.ChangeSet changedData = container.GetChanges(Telerik.OpenAccess.ObjectContainer.Verify.Changed);
   CarRentalAdministratorService service =
new CarRentalAdministratorService();
   container.Apply(service.SyncCars(changedData));
}  
VB .NET Copy Code
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs)
 Dim container As ObjectContainer = CType(Session("container"), Telerik.OpenAccess.ObjectContainer)
 Dim changedData As ObjectContainer.ChangeSet = container.GetChanges(Telerik.OpenAccess.ObjectContainer.Verify.Changed)
 Dim service As New CarRentalAdministratorService()
 container.Apply(service.SyncCars(changedData))
End Sub

The important part of this code is the SyncCars method of the Web Service. This method takes a ChangeSet as a parameter, updates the database with the changes made in the container and than returns a fresh ChangeSet to the container which the container applies and that way its objects also remain in a consistent state.

The implementation of this web method is like:

C# Copy Code
[WebMethod]
public ObjectContainer.ChangeSet SyncCars(ObjectContainer.ChangeSet changes)
{
    
try
    {
        
ObjectContainer.ChangeSet ccData = null;
        IObjectScope os = ObjectScopeProvider1.GetNewObjectScope();
        
try
        {
            
ccData = ObjectContainer.CommitChanges(changes, Telerik.OpenAccess.ObjectContainer.Verify.Changed, os, true, true);
        }
        
finally
        {
            
os.Dispose();
        }
        
return ccData;
    }
    
catch (Exception exc)
    {
        
string msg = exc.Message;
        
throw exc;
    }
}  
VB .NET Copy Code
<WebMethod> _
Public Function SyncCars(ByVal changes As ObjectContainer.ChangeSet) As ObjectContainer.ChangeSet
  Try
   Dim ccData As ObjectContainer.ChangeSet = Nothing
   Dim os As IObjectScope = ObjectScopeProvider1.GetNewObjectScope()
   Try
    ccData = ObjectContainer.CommitChanges(changes, Telerik.OpenAccess.ObjectContainer.Verify.Changed, os, True, True)
   Finally
    os.Dispose()
   End Try
   Return ccData
  Catch exc As Exception
   Dim msg As String = exc.Message
   Throw exc
  End Try
End Function

 The final interactive web page has the following look:

There is little additional logic that prompts the administrator of how many records are Altered/Inserted/Deleted in this disconnected mode as that is the number of the outdated records on the database server as well as marking which those records are.