Recommended

Skip Navigation LinksHome / Articles / View Article

WCF RIA Applications with Telerik OpenAccess ORM Part II: CRUD Operations and Validation

+ Add to SilverlightShow Favorites
1 comments   /   posted by Pencho Popadiyn on Jun 30, 2010
(3 votes)

This article is Part 2 of the series Silverlight Applications with Telerik OpenAccess ORM

  • WCF RIA Applications with Telerik OpenAccess ORM Part I: The Basics
  • WCF RIA Applications with Telerik OpenAccess ORM Part II: Create, Update, Delete and Validation
  • Introducing Telerik OpenAccess Data Service Wizard
  • WCF Data Services with Telerik OpenAccess ORM
  • WCF End Points Services with Telerik OpenAccess ORM
  • Silverlight Applications for Windows Azure with Telerik OpenAccess ORM Part I: Connection to SQL Azure
  • Silverlight Applications for Windows Azure with Telerik OpenAccess ORM Part II: Developing the Silverlight Client and Deploying the Application

1. Go Back at the Beginning

In Part 1, I introduced the basics of WCF RIA Services with Telerik OpenAccess ORM and walked you through the “Hello World” equivalent. Let’s go back to the point when you create a new Domain Service. As you remember, you had to perform several steps to create a Domain Service, such as adding a new reference to the Telerik.OpenAccess.Ria.Extensions.dll, manually adding a query method in the service, and several other pretty nasty steps. The reason was that the Add New Domain Service Class dialog recognizes only DataContexts based on Entity Framework or Linq2Sql. And our domain model won’t be shown in the list with the available data sources.
As I said, the OpenAccess developers are in pace with the new technologies, constantly improving the product. As a proof to my words, just a few hours after the previous article was published, a new build of Telerik OpenAccess ORM was released. When I installed it on my PC, I was pleasantly surprised to discover that there is a new template in Visual Studio!!!

 

This is the Telerik OpenAccess Domain Service template. It helps you to create Telerik OpenAccess Domain Service class for WCF RIA Services applications. Once you select the template and click add, you will be presented with a dialog that lets you select a number of options for your service, including the most important option - what domain model it will expose.

 

First, you should specify a Domain service class name. This is the name of your service. The Enable client access option must be checked. It will add the EnableClientAccessAttribute attribute to your domain service class to indicate that it is visible to the client tier. In the Available DataContext classes drop-down, you should choose among the Telerik OpenAccess Domain Models in your project. Finally Enable all entities that you want to be exposed by the domain service. The Enable Edit option specifies whether the entity will be read-only or not. Once you click OK, your domain service will be created and added to the server project.

 

2. Create, Update, Delete Operations

Basically, in order to perform CRUD operations, your domain service class should expose methods for insert, update, and delete. If you use the Telerik OpenAccess Domain Service template, then those methods will be added automatically. However, if you create a domain service by hand, like it is described in Part 1 of the series, then you have to add those methods manually.

[EnableClientAccess()]
public class NorthwindDomainService : OpenAccessDomainService< NorthwindDbContext >
{
    public NorthwindDomainService() : base()
    {
    }
    public IQueryable<Customer> GetCustomers()
    { 
        return this.DataContext.Customers;
    }       
    public void DeleteCustomers(Customer customer)
    {
        // This is a callback method. The actual Delete is performed internally.
    }
    public void UpdateCustomers(Customer customer)
    {
        // This is a callback method. The actual Update is performed internally.
    }
    public void InsertCustomers(Customer customer)
    {
        // This is a callback method. The actual Insert is performed internally.
    } 
}

In order to create user interface for create, update and delete:

  • In the client project, open MainPage.xaml.
  • Add three Buttons controls – for Save, Add and Delete.
  • The following XAML shows a complete layout along with the existing DataGrid (from the previous part).
    <UserControl x:Class="NorthwindWcfRia.MainPage"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data">
        <Grid x:Name="LayoutRoot"
              Background="White">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition />
            </Grid.RowDefinitions>
            <StackPanel Orientation="Horizontal"
                        Margin="0,3">
                <Button x:Name="btnSave"
                        Content="Save"
                        Click="btnSave_Click" />
                <Button x:Name="btnAdd"
                        Content="Add"
                        Margin="7,0"
                        Click="btnAdd_Click" />
                <Button x:Name="btnDelete"
                        Content="Delete"
                        Click="btnDelete_Click" />
            </StackPanel>
            <data:DataGrid Name="CustomerGrid"
                           Grid.Row="1" />
        </Grid>
    </UserControl>
  • In the code-behind page for MainPage.xaml, add event handlers for the click event of the buttons.
    using System.ServiceModel.DomainServices.Client;
    using System.Windows;
    using System.Windows.Controls;
    using NorthwindWcfRia.Web;
     
    namespace NorthwindWcfRia
    {
        public partial class MainPage : UserControl
        {
            private NorthwindDomainContext dbContext = new NorthwindDomainContext();
            public MainPage()
            {
                InitializeComponent();
                LoadOperation<Customer> loadOperation = dbContext.Load( dbContext.GetCustomersQuery() );
                loadOperation.Completed += ( s, a ) =>
                {
                    CustomerGrid.ItemsSource = dbContext.Customers;
                };
            }
            private void btnSave_Click( object sender, RoutedEventArgs e )
            {
            }
            private void btnAdd_Click( object sender, RoutedEventArgs e )
            {
            }
            private void btnDelete_Click( object sender, RoutedEventArgs e )
            {
            }
        }
    }
  • Note, that in the MainPage constructor all Customers are loaded async and set as ItemsSource for the DataGrid.
  • Add the following code in the btnSave_Click event handler. Its purpose is to submit changes to the DomainService, if such changes exist.
    private void btnSave_Click( object sender, RoutedEventArgs e )
    {
        if ( this.dbContext.HasChanges == false )
            return;
        dbContext.SubmitChanges();
    }
  • In the btnDelete_Click handler add code for retrieving the currently selected Customer and deleting it.
    private void btnDelete_Click( object sender, RoutedEventArgs e )
    {
        if ( this.CustomerGrid.SelectedItem == null )
            return;
        Customer customerToDelete = this.CustomerGrid.SelectedItem as Customer;
        this.dbContext.Customers.Remove( customerToDelete );
    }
  • In the btnAdd_Click event handler a new customer object is created, initialized and passed to the DomainService.
    private void btnAdd_Click( object sender, RoutedEventArgs e )
    {
        Customer newCustomer = new Customer();
        newCustomer.CustomerID = "ABCDE";
        newCustomer.CompanyName = "MyCompany";
        newCustomer.City = "MyCity";
        newCustomer.ContactName = "MyContactName";
        dbContext.Customers.Add( newCustomer );
    }

Now you are ready to create, update and delete customers, and use the DomainContext class to submit changes back to the server.

3. Validation

You can add validation attributes to properties and persistent classes to enforce validation. WCF RIA Services provide several built-in validation attributes that perform common validation checks, and provide the CustomValidationAttribute attribute so you can specify customized validation checks. The default validation attributes in WCF RIA Services are:

  • DateTypeAttribute
  • RangeAtribute
  • RegularExpressionAttribute
  • RequireAttribute
  • StringLengthAttribute

You add the validation attributes to persistent classes in the server project and those validation attributes are propagated to their generated client entity representations. At run time, the validation rules are applied to data from the user. You must add metadata classes to add validation attributes. Note that, when developing a Silverlight application with WCF RIA Services and Telerik OpenAccess ORM, Domain Services automatically generate validation rules by using database attributes such as required fields or maximum string length.

To add a validation attribute, you need to perform the following steps:

  • Add a metadata class for the persistent class. You can find information on how to do that in the distributed Telerik OpenAccess ORM help or in msdn.

On the properties or the persistent class that you want to validate, add the validation attributes that perform validation. The following example shows the RequiredAttribute, RegularExpressionAttribute and StringLengthAttribute attributes applied to the Customer properties.

[MetadataTypeAttribute( typeof( Customer.CustomerMetadata ) )]
public partial class Customer
{
    internal sealed class CustomerMetadata
    {
        public CustomerMetadata()
        {
        }
        public int CustomerID
        {
            get;
            set;
        }
        [Required]
        [StringLength( 10 )]
        public string DrvLicNumber
        {
            get;
            set;
        }
        [StringLength( 50 )]
        public string FullName
        {
            get;
            set;
        }
        [RegularExpression( "abc" )]
        public string Address
        {
            get;
            set;
        }
        // ....
    }
}

  • In the Silverlight application, open the generated code file in the Generated_Code folder, and notice the validation attributes that are applied in the client code.

However, sometimes the standard validation attributes don’t offer enough flexibility. In these scenarios you need to use the CustomValidation attribute as it is shown in the instructions below:

  • Again you need to create a metadata class for the persistent class.
  • Add a shared code file by using the *.shared.cs naming pattern. The code file will contain the custom validation logic.
  • Add a new method that determines whether the data is valid. The method must have the following characteristics:
    • It must be public and static.
    • It must return a ValidationResult to indicate the result of the validation check.

The following example shows a class called CustomerValidation with a method named IsCustomerValid that validates a Customer object. When the data is not valid you should return the error message and the name of the property that failed the validation.

using System.ComponentModel.DataAnnotations;
 
namespace OA.SL4.RIA.Demo.Web
{
    public class CustomerValidator
    {
        public static ValidationResult IsCustomerValid( Customer customerToValidate, ValidationContext context )
        {
            if ( customerToValidate.ZIPCode.EndsWith( "Net" ) == false )
                return new ValidationResult( "ZipCode must end with 'Net'", new string[] { "ZipCode" } );
            else
                return ValidationResult.Success;
        }
    }
}

On the persistent class or property that you want to validate, add the CustomValidationAttribute attribute, passing the type of the validation object and the name of the method that performs the validation.

[CustomValidation( typeof( CustomerValidator ), "IsCustomerValid" )]
[MetadataTypeAttribute( typeof( Customer.CustomerMetadata ) )]
public partial class Customer
{
    internal sealed class CustomerMetadata
    {
        public CustomerMetadata()
        {
        }
    }
}

4. Final Words

In Part1 and Part2 of the series, I introduced the basics of WCF RIA Services and Telerik OpenAccess ORM. That might have seemed too simple, and you can’t really drag and drop your way to real world applications. In that case do not hesitate to ask the OpenAccess Team for advice or to take a look at the product documentation.

That’s it for today. In the next article, I’ll introduce you another great tool coming along with Telerik OpenAccess ORM – this is the Telerik Data Service Wizard.

Share


Comments

Comments RSS RSS
  • RE: WCF RIA Applications with Telerik OpenAccess ORM Part II: CRUD Operations and Validation  

    posted by Tony on Jul 01, 2010 22:36

    Very helpful series. Thanks much!

Add Comment

 
 

   
  
  
   
Please add 4 and 1 and type the answer here:

Join the free SilverlightShow webinar 'Silverlight Behaviors for Designers' on July 14th 2010, 3:00pm EDT.
In this session on adding interactivity UX Designer and Consultant Zhivko Dimitrov will show how to bring your designs to life without writing a single line of code! Find out how to use drag & drop behaviors to control animations, add navigation, and simulate validation states. Read more | Register Now (hide this)