Blogs

Gary's Blog

June 2008 - Posts

  • Business Logic in XAF

    XAFBusLog

    At the end of the previous video Oliver and I were off to try and sell our super dooper blogging system to the highest bidder, tune in to this video to see how that worked out for us (hint: we’re here doing another video!). Anyway, in this video we look at where business logic should be implemented in an XAF application and where that logic should be called from.

    Technorati tags: ,
    Digg This
  • Blogging with XAF

    XAFBlogging

    If you’ve been following the videos that Oliver and I have been doing you will, by now, have a good introduction to the XAF product. In this video we are going to take things to the next level by showing you the development of a simplistic, but functioning blogging engine. Having done that, Oliver and I will quietly slip away from Developer Express and try to make our fortunes selling our new product to the Silicon Valley VCs; stick around and watch the next video in the series to see how that works out for us. :-)

    Technorati tags: ,
    Digg This
  • Persistent Classes in XAF

    XAF1

    Having looked at XPO in previous videos, it’s time to have a look at XPO’s big brother, or XAF as we like to call it. XAF is built upon XPO but takes things to the next level by not only allowing you to create and persist business objects, but by having XAF interrogate the structure of those objects, it can create a UI (in both winforms and webforms) to support basic create, read, update and delete functionality. In this video we introduce you to XAF and demonstrate the creation of a persistent object and it’s supporting UI.

    Technorati tags: ,
    Digg This
  • XPO Demonstration Part 2

    XPODemo2

    If you watched the first part of this demonstration you’ll obviously be interested in how our plan, to have an army of “Garys” do our work for us, is coming along. If so, check out the latest video here. Um, I suppose there’s also a chance that you are interested in creating one to many relationships and how to change the default persistence database in XPO, if that happens to be true, you should check out the video too.

    Technorati tags: ,
    Digg This
  • XPO Demonstration Part 1

    XPODemo1

    Continuing our series of videos on XPO and XAF, Oliver and I look at how to persist a class to the database and how to read it back, and just in case that’s not exciting enough for you, we also hatch a plan to populate the world with “Gary” clones that work whilst we sip Kamikazes on a sun soaked beach. To see how that works out for us, view the latest video here.

    Technorati tags: ,
    Digg This
  • XPO the Philosophy

    ORMPhilPart1Currently Oliver and I are across in the Glendale office working with our videographer Jeff (hey how come Jeff doesn’t have a blog?!) creating some videos around XPO and XAF. In the first of the videos we’ve produced, I’m chatting to Oliver about the philosophy behind ORMs in general and XPO in particular. If you are not put off by the thought of looking at Oliver and me for 15 minutes then you can watch the video here.

    Technorati tags: ,
    Digg This
  • Application Scalability Using XPO #2

    In my previous post I introduced the topic of database scalability using XPO. In that post we looked at a simple method of partitioning customers between two database servers, one covering customers in the north and the other covering customers in the south. In that post we had the simplistic scenario of clients only being interested in customers either in the north or the south and so they were set up (via connection string) to look only at those servers.

    Whilst being sufficient to introduce the topic, there will only be a few scenarios whereby you can partition your data and your client applications in the same way. In most situations your client applications will want to access both servers to store and fetch customer information, and they will have to know which server to access based on information only available at runtime. So how is this achieved?

    Looking at the following graphic you can see that Customers have been horizontally partitioned into two databases (CustomersA-M and CustomersN-Z). You will also see that there is an Index server who’s purpose it is to serve a connection string to the required server based on the last name of the customer.

    Servers

    In the above schema the Index database has a CustomerIndex table with the following structure:-

    Structure

    Whereby the StartLetter column holds the first letter of the partitioned data and the StopLetter column holds the last letter of the partitioned data. The connection string for the partitioned server is held in the ConnectionString column. So now, when we want to know the connection string of the server for a particular customer we simply take the first letter of their last name and execute:-

    select connectionstring 
    from CustomerIndex 
    where @letter between StartLetter and StopLetter

    Using this schema, it is easy for further partition the data in the future, should that be necessary. It is just a case of provisioning another server, splitting the data evenly across all servers and then updating the Index above.

    Okay, so let’s see an example. The first thing we have to do is to abstract this away from the application developer because they don’t want to know anything about our database scalability solution.  To do that, let’s build a helper class:-

    class DBHelper {
        public static string GetConnectionStringForCustomer(string customerName){
            //GS - Guard against empty strings
            if (customerName == String.Empty) { return String.Empty; }
    
            //GS - Get the first letter of the Customer's last name
            string firstLetter = 
                customerName.Split(" ".ToCharArray())[1].Substring(0, 1);
    
            //GS - Guard against null or empty returns
            if (String.IsNullOrEmpty(firstLetter)) { return String.Empty; }
    
            /* Now that we have the first letter of the customer's last name
             * we can access the index server and find out the connection
             * string of the server to which this customer's details
             * should be saved */
            const string CONN_STRING = 
                "Data Source=.;Initial Catalog=Index;Integrated Security=True";
            string targetConnectionString;
            using (SqlConnection conn = new SqlConnection(CONN_STRING)) {
                using (SqlCommand cmd = new SqlCommand()) {
                    cmd.Connection = conn;
                    cmd.CommandType = CommandType.Text;
                    cmd.CommandText = "SELECT ConnectionString FROM " +
                        "CustomerIndex WHERE @Letter between " +
                        "StartLetter and StopLetter";
                    cmd.Parameters.AddWithValue("@Letter", firstLetter);
                    cmd.Connection.Open();
                    targetConnectionString = 
                        Convert.ToString(cmd.ExecuteScalar());
                    cmd.Connection.Close();
                }
            }
            return String.IsNullOrEmpty(targetConnectionString) ? 
                String.Empty : targetConnectionString;
        }
    }

    Now let’s create a function to call that abstraction:-

    private static void SetDataLayerForCustomer(string custName) {
        //GS - Get the connection string
        string conn =
            DBHelper.GetConnectionStringForCustomer(custName);
    
        //GS - Guard against empty connections string
        if (conn == String.Empty) { 
            throw new Exception("No connection string found!"); 
        }
    
        //GS - Explicitly set the datalayer
        XpoDefault.DataLayer = XpoDefault.GetDataLayer(
            conn, AutoCreateOption.DatabaseAndSchema);
    }

    Having done that, we can use XPO in the normal way:-

    static void Main(string[] args) {
        string custName = "Gary Short";
        CreateCustomerAndOrders(custName);
        ShowOrdersForCustomer(custName);
    }
    private static void CreateCustomerAndOrders(string custName) {
        //GS - Set the datalayer for the customer
        SetDataLayerForCustomer(custName);
        
        //GS - Create a Customer and an Order and persist them
        using (UnitOfWork uow = new UnitOfWork()) {
            Customer customer = new Customer(uow);
            customer.Name = custName;
    
            //GS - Create a few orders
            new Order(uow) { Customer = customer, OrderNumber = 1 };
            new Order(uow) { Customer = customer, OrderNumber = 2 };
            new Order(uow) { Customer = customer, OrderNumber = 3 };
            new Order(uow) { Customer = customer, OrderNumber = 4 };
    
            uow.CommitChanges();
        }
    }
    private static void ShowOrdersForCustomer(string custName) {
        //GS - Set the datalayer for the customer
        SetDataLayerForCustomer(custName);
    
        //GS - Fetch the customer
        using (var uow = new UnitOfWork()) {
            BinaryOperator criteria = new BinaryOperator("Name", custName);
            Customer customer = uow.FindObject<Customer>(criteria);
    
            //GS - Write out data
            Console.WriteLine("Customer: " + custName + 
                " has the following order numbers: ");
            foreach (Order order in customer.Orders) {
                Console.WriteLine("Order Number: " + order.OrderNumber);
            }
        }
    
    }

    If you run this code you will find tables created in the CustomerN-Z database; changing the customer name from “Gary Short” to “Gary Adams” will cause tables to be created in the CustomerA-M database, with no change to the client code. For demonstration purposes I have only attached an Order to the Customer, and a very simple Order at that, but you can see the principle.

    Now that I’ve shown how to work with individual customers and their related data, the question is, how do you work with groups of Customers? How do you answer questions like “show me the customers with orders placed between 2006 and 2007 where the combined value of orders placed is greater than 3M GBP or where a single order value is greater than 120K GBP”? Well, the short answer is, you don’t!

    Okay, so that’s not much help; the slightly longer answer is that if you have so many customers that you are considering a scalability solution then you would never query your OLTP system for report data. The data in the OLTP system would be archived off (perhaps instantly using triggers or in an over night batch job) into a reporting system where you would run queries using your particular reporting solution, Sql Server Reporting Services perhaps.

    So, to sum up then, in this post I’ve shown you how to horizontally partition customer data and how to abstract that away from the application programmer so that they are using XPO in a familiar manner.

    Technorati tags: ,
    Digg This
  • Application Scalability Using XPO

    Let’s say we have an application with the following (highly simplified) object model:-

    ObjectModel

    As you can see we have a Customer and a Customer’s Orders which we wish to persist to the database using XPO. This will work perfectly with 10, 100, 1,000, 10,000 orders say; however, somewhere alone the orders of magnitude your database is going to start to struggle with the numbers of Customers and their Orders. You can scale up your database server of course, but there comes a time when even that will not help. When dealing with database scalability I like to use the sharding pattern. In this pattern a large database is broken up into ever smaller pieces and clients access the required piece or shard.

    In the non scalable solution the following code would be used to serialize the object model:-

    namespace XPOScalabilityExample {
        class Program {
            static void Main(string[] args) {
    
                //GS - Explicitly set the datalayer
                string conn = MSSqlConnectionProvider.GetConnectionString(
                    "(local)", "Customers");
    
                XpoDefault.DataLayer = XpoDefault.GetDataLayer(
                    conn, AutoCreateOption.DatabaseAndSchema);
    
                //GS - Create a Customer and an Order and persist them
                using (UnitOfWork uow = new UnitOfWork())
                {
                    Customer customer = new Customer(uow);
                    customer.Name = "Gary Short";
                    customer.Address = "The Adress";
    
                    Order order = new Order(uow);
                    order.OrderedItem = "A widget";
                    order.OrderedQuantity = 4;
                    order.Price = 342.29M;
    
                    customer.Orders.Add(order);
                    order.Customer = customer;
    
                    uow.CommitChanges();
                }
            }
        }
    }

    To implement sharding, in the first instance, we will partition the database geographically, placing customers in either the north or the south. The code to persist the Customer now looks like the following:-

    namespace XPOScalabilityExample {
        class Program {
            static void Main(string[] args) {
    
                //GS - Explicitly set the datalayer
                string conn = MSSqlConnectionProvider.GetConnectionString(
                    "(local)", "North");
    
                XpoDefault.DataLayer = XpoDefault.GetDataLayer(
                    conn, AutoCreateOption.DatabaseAndSchema);
    
                //GS - Create a Customer and an Order and persist them
                using (UnitOfWork uow = new UnitOfWork())
                {
                    Customer customer = new Customer(uow);
                    customer.Name = "Gary Short";
                    customer.Address = "The Adress";
                    
                    Order order = new Order(uow);
                    order.OrderedItem = "A widget";
                    order.OrderedQuantity = 4;
                    order.Price = 342.29M;
    
                    customer.Orders.Add(order);
                    order.Customer = customer;
    
                    uow.CommitChanges();
                }
            }
        }
    }

    For demonstration purposes I have simulated the switch between servers by switching between databases on the same server, but I’m sure you get the idea. To access Customers in the south you would replace the word “North” with the word “South” in the connection string. Now that you have the idea of sharding we will look at a more advanced example next time.

    Technorati tags: , ,
    Digg This
  • TechEd 2008 - Stories from the Trenches

    I'm back in the hotel after the first day working the booth at TechEd. It was a pretty interesting day chatting to some of our customers and the attendees in general. I also managed to catch up with a familiar face in the guise of Dustin Campbell (late of Dev Express now with Microsoft) who came round to the booth to say hi along with Karen Liu and some of the IDE team. Dustin tells me he's really enjoying the challenges of his new job, and doesn't he look sweet in his smurf outfit (sorry, I mean his blue Microsoft shirt) :-)

    The evening session was even more interesting. Mark was at the booth demonstrating Coderush when Scott Hanselman turned up to heckle give Mark some advice on the content of his presentation. We got chatting and it turns out that Scott's grandparents come from the same small Scottish town where I was brought up. Small world eh? So after today I'm really looking forward to what tomorrow will bring down at the coal face; see you down there!

    Technorati tags:
LIVE CHAT

Chat is one of the many ways you can contact members of the DevExpress Team.
We are available Monday-Friday between 7:30am and 4:30pm Pacific Time.

If you need additional product information, write to us at info@devexpress.com or call us at +1 (818) 844-3383

FOLLOW US

DevExpress engineers feature-complete Presentation Controls, IDE Productivity Tools, Business Application Frameworks, and Reporting Systems for Visual Studio, along with high-performance HTML JS Mobile Frameworks for developers targeting iOS, Android and Windows Phone. Whether using WPF, Silverlight, ASP.NET, WinForms, HTML5 or Windows 8, DevExpress tools help you build and deliver your best in the shortest time possible.

Your Privacy - Legal Statements

Copyright © 1998-2013 Developer Express Inc.
ALL RIGHTS RESERVED
All trademarks or registered trademarks
are property of their respective owners