Sage Developers' Blog

New Sage 200 Developer Tools Available

without comments

Two new developer tools are available to download from the Sage 200 Developer Centre (login required). We have developed these in response to feedback from members of the Developers Programme to provide timesaving and powerful features covering Sage 200 exception types and data models.

Sage 200 Exception Viewer

The Sage 200 Exception Viewer provides a convenient view of exceptions that are thrown, caught and allowed within the Sage 200 object model and forms, helping you to handle all the relevant exceptions in your code.

Sage200ExceptionViewer

You can search for exceptions by the exception name or error text (making supporting your application easier if a user reports an exception message), or by navigating the exception tree. The tree shows exceptions by Namespace, Class, Method and exception type making it easy to see what exceptions may be thrown by any given area of the object model.

 

Sage 200 Data Model Builder 

The Sage 200 Data Model Builder provides the capabilities of the existing Custom Model Builder tool but also gives greater power over the Data Model extensions that are created and provides convenient tools for generating Transient Data Models.

Sage200DataModelBuilder

The main features of the Data Model Builder

  • Easily search and filter any table in any database whether they are part of the existing data model or not
  • Rename table, view and column names so they appear differently in the Report Designer or Workspaces
  • Create table joins, for instance to make an extended table’s fields appear as if they were part of the standard Sage 200 table when writing reports and workspace queries
  • Extend previously extended tables
  • Save your project so that you can amend it later
  • Create Transient Data Models quickly based on existing classes in a compiled assembly
  • Automatically generate MetaData code to make populating transient data reports quick and easy

These features have been developed in response to feedback we’ve received from our developers. If you have any comments, bugs or feature requests please contact Developer Services. You can also add feedback to the forum post on Sage 200 Developer Tools.

Sage 200 Downloads

Written by david.graham

February 4th, 2013 at 3:37 pm

WCF Services: A Lesson Learned the Hard Way

without comments

Sage 200 R&D are busy building a bank of WCF Services to support our next major product release and we recently fell into a common trap like many before us.

To communicate with a WCF Service you need to create a “client”, also known as a “proxy”, which acts as an intermediary between your application and the service you are contacting. Visual Studio has great tools for automatically creating these proxy classes so you don’t need to worry about serialisation or handling the HTTP requests and responses, you only need to know the name of the method on the service that you wish to call.

A common practice is to create an instance of the proxy class in a using statement so that once the service call has been made, you can get rid of the connection to the service (an expensive resource to leave open) and process the response however you wish. But there is a potentially serious problem that arises when you use this approach.

Automatically generated proxy classes implement IDisposable, that’s why they work in a using statement, but the implementation of Dispose() does not take into consideration those cases where a service has thrown an exception. Dispose() always calls Close() on the connection but you can’t call Close() on a connection which is in a Faulted state – i.e. when an exception has been thrown. When a connection is in the Faulted state you need to call Abort() instead, just calling Close() causes another exception to be thrown and the connection never gets closed. As we found out, it doesn’t take long for you to run out of connections!

While you can get rid of the using statements and put a try-catch block around each service call and make sure you’re calling Abort() in your catch blocks it quickly becomes spaghetti code and it is very easy to forget to do, especially in service-heavy code written by many different teams.

How We Solved It

After some discussion, collaboration and research, we came up with an elegant solution that meant Developers didn’t have to care too much about the lifetime of a service, or need to remember to abort connections when exceptions did occur.

Our solution was a generic extension method that neatly called Close() or Abort() where appropriate and simplified the code that a Developer needs to write to handle the connection lifetime.

As an added bit of complexity, Sage 200 is completely extensible, so our code is written in a very generic way. As a result we don’t use Service References, instead we use the ChannelFactory class to instantiate a proxy based on a given interface (the “contract”). If you’re new to WCF Services, don’t worry about what this means, only that it explains the presence of “new ChannelFactory<TChannel>().CreateChannel()” in the code snippet below!

The generic extension method looks like this (don’t worry, it’s mostly comments):

[snippet id=63037]

And to use this in your code you would write:

[snippet id=63113]

In this example, when you call Foo() and everything goes well, the extension method calls Close() on the connection. When an exception occurs, before handing back control of the program execution to the code that is calling SafeInvoke(), the extension method calls Abort(), which correctly closes the connection.

Also worthy of note is the pattern used in the catch block. If you explicitly catch an exception and then “throw ex;”, the CallStack property of the exception will be unwound and will instead show the call stack at the SafeInvoke method, this effectively hides useful information about what caused the exception, severely hindering debugging. By using catch{ throw; }, all of the original call stack information is retained.

Written by richard.stokoe

February 6th, 2012 at 3:38 pm

Posted in Uncategorized

Sage 200 Labs – Creating a Button Panel content part

without comments

This latest Sage 200 Labs is designed to add a little functionality into Workspaces similar to the legacy desktop. By creating a content part that allows buttons to be added and handles Form Actions, these Button Panels can recreate the horizontal and vertical bars we see elsewhere.

https://my.sage.co.uk/UK/communities/developers/developer-centres/sage-200/Labs/button-panel-content-part.aspx

Written by david.graham

December 16th, 2011 at 11:53 am

Posted in Sage 200 Labs

Incorporating images into ‘Getting started with Win Phone 7′

without comments

Overview

In this third instalment we’re going to return some images from a designated directory based on the StockItem we’ve selected from our StockItem list that was generated in our Extending ‘Getting started with Win Phone 7′ article.

This means we need to:

  • Ensure we have some initial images available
  • Add a new image control to our StockItems.xaml page (not shown)
  • Add a new OperationContract to our ServiceContract to get the image and the new service method that takes a string parameter
  • Add client code to consume this new service contract

We’ll continue with the same project we created previously so we can just add in the extra methods required for the steps outlined above.

 

 

Initial requirements

There’s not a great deal to the setup here; we need a directory containing some images for our StockItems.

On the development machine we’ve used there is a StockImages directory on the Sage server (i.e. C:\Sage\StockImages) containing a number of .jpg files that are named corresponding to the StockItem’s name e.g.

The name property on ACS/BLENDER in the Sage200 Demodata is Professional Blender 5 Speed and the corresponding image in the StockImages directory is Professional Blender 5 Speed.jpg.

This StockImages directory has been added as a virtual directory within IIS to ensure we can get at it regardless of whether we’re local or not.

Also, we are currently returning the StockItem’s description rather than its name so we need to slightly amend the public ObservableCollection<Sage200Stock> GetStock(string supplierRef) method we created in the previous article and change the respective property:

    stk.StockDescription = stockData.StockItem.Name; // was Description;

 

You don’t need to change anything else with respect to this amendment.

 

The only other thing you initially need is an image control on the same screen as the StockItemList i.e. on StockItems.xaml.

 

 

 

 

 

 

Adding a new DataContract to our service

We’ve already looked at how to pass information between the client application and the service application so this is going to be pretty similar in that we’re passing across the name of the image we want to display.

The code for the new DataContract is placed in the ServiceContract interface we created in the first article:

code3.1

    [ServiceContract]

    public interface IWinPhone7Service

    {

     …

     …

        // get image(s)

        [OperationContract]

        [WebGet(UriTemplate = "GetImage/{imageName}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]

        System.IO.Stream GetImage(string imageName);

 

As you can see in the method attributes we’re expecting an imageName parameter to be passed across. We’ve used XML Request and Response formats here too (you don’t actually need to specify any if you don’t want to but you may find you’re passing more data across the wire).

 

We also need a method to perform the retrieval of the image within the Service class:

code3.2

    public class WinPhone7Service : IWinPhone7Service

    {

     …

     …

        // get image(s)

        public System.IO.Stream GetImage(string imageName)

        {

            // create a fileStream and pass in the image name we want (all of the

            //  images we have access to have the same name as the stock name)

            System.IO.FileStream fs = null;

            string fileName = string.Format(@”C:\Sage\StockImages\{0}.jpg”, imageName);

 

            // open the required file

            fs = System.IO.File.OpenRead(fileName);

 

            // set the respective content type

            WebOperationContext.Current.OutgoingResponse.ContentType = “image/jpeg”;

 

            // return our fileStream

            return fs;

        }

 

Here we’ve set up a FileStream to retrieve the image and set the ContentType to image/jpeg.

 

That’s all the code needed for the service side of things.

 

 

Client code to consume the new DataContract

 

We need to add a new method and its associated OpenReadCompleted event to the Client side StockItems class.

 

Using the stkListBox_SelectionChanged event allows us to grab the name of the StockItem and pass that back to our service via the getImage method (which accepts a string as a parameter). Remember to change the server address in the Uri because it’s highly unlikely that yours wil be http://localhost:53857

code3.3

    public partial class StockItems : PhoneApplicationPage

    {

     …

     …

        // get image for selected stockItem

        private void stkListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)

        {

            // get the data object that represents the current selected item

            Sage200Stock stockItem = (sender as ListBox).SelectedItem as Sage200Stock;

 

            string imageName = stockItem.StockDescription;

            WebClient proxy1 = new WebClient();

            Uri strUriImage = new Uri(“http://localhost:53857/CompareCostsService.svc/getImage/” + imageName);

            proxy1.OpenReadCompleted += new OpenReadCompletedEventHandler(proxy1_OpenReadCompleted);

            proxy1.OpenReadAsync(strUriImage);

        }

 

 

        void proxy1_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)

        {

            System.Windows.Media.Imaging.BitmapImage img = new System.Windows.Media.Imaging.BitmapImage();

            img.SetSource(e.Result);

            image1.Source = img;

        }

    }

 

It’s the service code that directs us to the correct location for the images and appends the required .jpg file extension

final screen 

Written by GavD

October 13th, 2011 at 1:11 pm

Posted in Windows Phone 7

Tagged with ,

Creating jQuery UI Widgets using Reactive JavaScript Extensions (RxJS)

without comments

The Internet is changing from a collection of disparate puddles of information presented in a variety of ways (some proprietary, like Flash, and some free and open) to a semantic network of media (documents, videos, audio, etc). The yet-to-be-finalised technology driving this convergence is HTML5.

Unlike HTML4, which was an XML-based language for describing a document’s presentation and content, HTML5 is a number of related aspects of web development grouped together for ease. These related technologies promote self-describing, reusable and componentised code.

One popular way of creating componentised functionality for websites is to use the free jQuery UI (http://www.jqueryui.com) library, which contains a Widget Factory, allowing web developers to easily create encapsulated functionality that can be “attached” to elements on a webpage so they exhibit this new functionality. This approach also provides a great opportunity for developers to create a view for those people who have JavaScript turned off that then becomes better for those with JavaScript enabled when the widget is attached. This is generally referred to as progressive enhancement.

While jQuery and jQuery UI can be used with browsers that do not yet support HTML5, and those are becoming increasingly rare, they combine very nicely with HTML5’s focus on writing semantic markup. In this article I will show you how to create a simple HTML5 webpage, with appropriate semantic markup, create a jQuery UI widget component, and attach the component to an element on the page.

To make things a little more interesting, I will incorporate a fairly new Microsoft technology called Reactive JavaScript into the jQuery UI widget. Reactive JavaScript, usually abbreviated to RxJS, brings the “subject-observer” design pattern to JavaScript. This pattern essentially describes having a single source of information (the subject) being seen by many viewers or consumers (the observers). The example we will put together will show how to create an RxJS “Observable” that sends a notification to all its “Observers” when the mouse cursor moves across the webpage. The observer (a DOM element we attach our widget to) will be given the X and Y positions of the cursor. This type of continuous stream of information has been recently likened to a “firehose” of notifications, so that is what we will call our webpage.

The Widget (Scripts/firehose.js)

[snippet id=58625]

The Webpage (index.htm)

[snippet id=58626]

This results in a webpage that shows your mouse cursor’s X and Y positions in real-time and in two DIV elements. The top DIV has the firehose widget attached to it. The second DIV is actually subscribing to the Observable that the widget attached to the top element exposes.

You can get the rx.js and rx.jQuery.js files, and plenty more information and samples, from the Reactive Extensions Team blog:

http://blogs.msdn.com/b/rxteam/archive/2010/03/17/reactive-extensions-for-javascript.aspx

Further Reading

If this article has interested you, the KnockoutJS project, which aims to deliver an MVVM (model-view-viewmodel) architecture to plain HTML and JavaScript, is worth looking at: http://knockoutjs.com/

Written by richard.stokoe

September 12th, 2011 at 8:12 pm

Sage 200 Labs – Accessing On-premise Sage 200 Services using Azure

without comments

Hello everyone!!!

I’m very excited about this blog post as it is the introduction to my next Sage 200 Labs project.

https://my.sage.co.uk/UK/communities/developers/developer-centres/sage-200/Labs/accessing-on-premise-sage-200-services-using-azure.aspx

In this new labs project I demonstrate some new techniques that you may find useful when trying to access on-premise data and services from the Cloud or a remote device.

In the download you get:

  1. documentation on howto configure and deploy the application
  2. a Windows Phone 7 (WP7) application that will allow a Sage 200 ERP user to create an expense and capture and upload an image of a receipt for that expense. Don’t worry if you haven’t got a WP7 device, for demo purposes the Emulator bundled with the WP7 Visual Studio Tools SDK will work just fine
  3. a console application that replicates the basic functionality of the WP7 application but with very little user interaction (primary use is to demonstrate service interaction and authentication process)
  4. a custom content part type that will allow a Sage 200 ERP user to view the receipt captured on the device (or within the console application) within the Sage 200 2011 desktop
  5. source code

The best thing about this Labs project is that after some IIS configuration changes, the application will just work alongside your release version of Sage 200 2011 – I have not had to make any changes to the Sage 200 2011 code base for the application to work.

‘Why a phone application, why not a Web application hosted in the Cloud?’

- Well originally I had planned to do a new web application but I wanted to give you a completely new application that could be used alongside the Sage 200 WTE services and components that were shipped with Sage 200 2011. These  services were built specifically to allow users to ‘remotely’ create edit and authorise expenses and timesheets from within the new web application. Giving you another web application would only end up duplicating elements of what you already had in WTE. By giving you a phone application which demonstrated some of the capabilities of device I could add a twist on the existing WTE functionality.

‘Why WP7, why not Android, iPhone or Blackberry?’

The answer is simple …I am a .Net developer with experience of Silverlight so from an OS learning curve perspective WP7 was a no brainer. Secondly, like most, I like new gadgets and programming for WP7 gave me the opportunity of buying a new device.

‘How do you intend to access on-premise data and services from the device?’

The only constraint that the project imposes is that you will need either the Windows 7 or Windows Server 2008 R2 (and above) OS – I will discuss the reasons later. In terms of actually accessing the on-premise services I will be using the Microsoft Windows Azure AppFabric Service Bus (Service Bus). As the Service Bus is likely to play a role in the future architecture of Sage 200 (hybrid and composite applications) I thought it would be a good idea to demonstrate some of its capabilities today in a ‘non-release-to-market’ application.

So, they say a picture paints a thousand words so here is an illustration of the technologies and architectures at play in this Sage 200 Labs project.

Starting from the top the key components are:

  • WP7 Client (full source code is available) – communicates with on-premise services (via the service bus) to authenticate the user, get expense settings and add a new expense. The application utilises the phone’s camera hardware to allow the user to capture an image of their receipt – the image is then uploaded to the Azure Blob storage (a reference to the picture is stored on the expense’s Notes property)
  • Azure AppFabric Service Bus – to make full use of this application you will need an Azure AppFabric subscription. If you are a MSDN subscriber you can usually sign up for a free trial – see the Portal for more information. The phone application does have a ‘standalone’ option for you to try if you don’t want to sign up for the Service Bus.
  • Azure BLOB Storage – convenient (and cheaper than SQL Azure) mechanism to store and manage files in the Cloud. Source code on ‘how-to’ communicate with Blob storage is included within the WP7 client.
  • Windows Server AppFabric and IIS 7.5 – the primary challenge of connecting to on-premise services is activation of the services. In Vishal Chowdhary’s (a Senior Test Lead on the Azure AppFabric team) whitepaper on hosting WCF services with Service Bus endpoints from IIS he points out,
“For the on-premise WCF service to start receiving messages from the Service Bus in the cloud (aka Relay Service), the on-premises service opens an outbound port and creates a bidirectional socket for communication. It connects to the Service Bus, authenticates itself, and starts listening to calls from the relay service before the client sends its requests… IIS/WAS relies on message-based activation & will launch the host only after the first request comes in.”

Consequently, until the first message is received by IIS the service will never establish a connection to the Service Bus; with no connection to the Service Bus, it will never receive a message – a bit of a dilemma. In the whitepaper, Vishal points out two ways to resolve this challenge – in my project I use the Auto-Start feature.

  • Sage 200 WCF Services – the Sage 200 2011 release introduced a new set of WCF services to enable the new Web Timesheets and Expenses Application to communicate with back-office business objects. For the purpose of this project I will be utilising several of these services to authenticate a user and allow them to add a new expense into Sage 200. The source code for these services will not be available but the project does include a new ReceiptAttachment service that demonstrates how to communicate with Blob storage and how to use WCF Behaviour Extensions to Authenticate and Authorise user requests – source code for this service is available.
  • Sage 200 Workspace – in my last Labs project I included a new workspace content part type that orchestrated the communication between a standard list content part type and a Silverlight application. In this project I have included a new content part type that when used in conjunction with a standard list content part type displays the image of the receipt (stored in blob storage) referenced by the expense. The catch here was, obviously the Blob storage is not public therefore it is not simply a case of pointing the image source at the Blob Url, so in this content part I demonstrate how to generate a Shared Access Signature that allows the user, for a limited period, read access permissions to the Blob.

Okay, less of the talk go and try the solution for yourself. The landing page can be found here and includes everything you need to know to get started.

Note, you will need to be a member of the Sage Developer Programme to access this page.

Let me know what you think!!!

Written by Richard Custance

August 22nd, 2011 at 11:16 am

Extending ‘Getting started with Win Phone 7′

without comments

Overview

In this second instalment we’re going to return some stockItems from our Sage 200 database based on the supplier we’ve selected from our initial supplier list that was generated in our Windows Phone 7 development for Sage 200 2011 article.
This means we need to:
  • Add a new page to our project to display stockItems
  • Identify which item we’ve selected
  • Pass a parameter back to our service in order to query the database
  • Retrieve a collection of stockItems supplied by the selected supplier
  • Navigate to our new page in our client app in order to see the stockItems
We’ll continue with the same project we created previously so we can just add in the extra methods required for the steps outlined above.

 

Add a new page

The process for adding a new page is very similar to that of adding a new class to a generic Visual Studio project.
  1. With the WinPhone7Client application open right click the solution name in the Solution Explorer and choose Add Item…
  2. Select Silverlight for Windows Phone from the list of C# templates and give it a name of your choice (we’ve called it StockItems.xaml). See image 2.1 below
    image2.1
    new xaml page
  3. In the GUI from the resulting xaml file add a Button and a ListBox exactly like you did in the Getting started section of the previous article so it looks something like image 2.2 below
    image 2.2
    new page

 

Identifying the selected supplier

As this part of the process is based on the selected item in our list view on the phone device we need to add a new method in our client application.

We’ve also used the same method to navigate to a new page but the code for that will be shown later.

To start with

  1. Open the client application in Visual Studio
  2. On MainPage.xaml, select the ListBox we added (which was called suppsListBox)
  3. In the Properties pane select the Events tab and double click the SelectionChangedEventHandler as seen in the following image
    image2.3
    selection changed event
  4. This generates a new method stub in MainPage.xaml.cs
  5. For now, just enter the following code into this stub
    code2.1

       // get the data object that represents the current selected item    

       Sage200Supplier supp = (sender as ListBox).SelectedItem as Sage200Supplier;

     

    As you can see we’ve declared a new Sage200Supplier object and assigned it the selectedItem as a Sage200Supplier object.

Okay, so we know which supplier we’ve chosen from our supplier list. Now we need to pass that supplier’s AccountReference back to our service application before we use it to query the main Sage 200 database.

 

Passing a parameter from our client to our service

This process can be quite complex depending on what you actually intend to pass across. However, in this instance we’re getting hold of a string object which is relatively straight forward.

There are two distinct parts to this, one is the use of the Navigation service to move between pages on our phone, the other is the generation of the code and URI that allows us to send a specific parameter back to the service application.

The System.Windows.Navigation.NavigationService namespace is required for moving back and forth through different pages on the phone. It’s all static so no need to declare a Navigation object.

So, to navigate to our new StockItems page we need the SupplierReference as a string which we then need to add to a specific Uri. Add the following code to our suppsListBox_SelectionChangedEventHandler in MainPage.xaml.cs

code 2.2

   // this is the code to navigate to a different screen – passing some data

   string parameter = supp.SupplierReference;

   NavigationService.Navigate(new Uri(string.Format(“/StockItems.xaml?parameter={0}”,

     parameter), UriKind.Relative));

 

Having done this our event handler method now looks, in its entirety, like code example code2.3 here:

code2.3

   private void suppsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)

   {

       // get the data object that represents the current selected item    

       Sage200Supplier supp = (sender as ListBox).SelectedItem as Sage200Supplier;          

  

       // this is the code to navigate to a different screen – passing some data

       string parameter = supp.SupplierReference;

       NavigationService.Navigate(new Uri(string.Format(“/StockItems.xaml?parameter={0}”,

           parameter), UriKind.Relative));

   }

 

Now you can see how we’ve created the Uri to get to our new (StockItems.xaml) page while also passing a SupplierReference parameter.

To read that same parameter in the new StockItems page we have access to an OnNavigatedTo event (also from the System.Windows.Navigation.NavigationService) which must be overridden in our class.

In our Navigate method from code2.3 we passed a string which we called ‘parameter’ so we need to use this same name in our OnNavigatedToEvent. Add the following code (code2.4) into our StockItems class

code2.4

   protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)

   {

       base.OnNavigatedTo(e);

       string newparameter = this.NavigationContext.QueryString["parameter"];

   }

 

A ‘Back’ button was also added to this new page and, again, the NavigationService is used to direct us back to the MainPage (i.e. our supplier list)

code2.5

   private void goBackButton_Click(object sender, RoutedEventArgs e)

   {

       // go back to the previous page (as long as it’s still in memory)

       if (NavigationService.CanGoBack)

       {

           NavigationService.GoBack();

       }

   }

 

That’s the parameter being passed from page to page and a brief introduction to the NavigationService but we haven’t yet done anything meaningful with that parameter in respect of passing information to our service application.

In the original Windows Phone 7 development for Sage 200 2011 article we have a method in MainPage.xaml.cs for defining the Uri which points to the GetSuppliers() method on the service side of things. We’ve done the same here for Stock only this time we need to tell the method we’re calling that we’re going to be sending a parameter with the method call (which, in turn, suggests our GetStock() method in the service application accepts a parameter).

Add the following line of code to the OnNavigatedTo() method:

code2.6

   GetStockForSupplier(newparameter);

 

The GetStockForSupplier() method is where we generate the Uri, passing it our required parameter (remember to change the port number from that shown here).

code2.7

   private void GetStockForSupplier(string supplierRef)

   {

       try

       {

           // declare and instantiate a new webClient

           WebClient webClient = new WebClient();

 

           // declare a new Uri getting the respective address

           // Your port number (:53857 below) will not be the same on your machine

           // so change that part accordingly and then add the required parameter

           Uri uri = new Uri(“http://localhost:53857/WinPhone7Service.svc/Stock/” +

               supplierRef);

 

           // add an event handler for the OpenReadCompleted event

           webClient.OpenReadCompleted += new

               OpenReadCompletedEventHandler(OpenReadCompletedStock); 

 

           webClient.OpenReadAsync(uri);

       }

       catch (Exception ex)

       {

           MessageBox.Show(ex.Message);

       }

   }

 

Again, as stated in our previous article, all calls are asynchronous and the WebClient created an event handler which we’ve used to add stock to our internal database.

The following code (code2.8) is almost identical to the OpenReadCompleted event for Suppliers from our previous article.

code2.8

   void OpenReadCompletedStock(object sender, OpenReadCompletedEventArgs e)

   {

       DataContractJsonSerializer jsonSerializer = null;

 

       try

       {

           jsonSerializer = new DataContractJsonSerializer(

               typeof(ObservableCollection<Sage200Stock>));

           Database.Instance.Stock = jsonSerializer.ReadObject(e.Result) as

               ObservableCollection<Sage200Stock>;

 

           // show the stock (if we’ve got some) in a list

           try

           {

               if (Database.Instance.Stock != null)

               {

                   stkListBox.DisplayMemberPath = “StockCode”;

                   stkListBox.ItemsSource = Database.Instance.Stock;

               }

               else

               {

                   MessageBox.Show(“no stock…”);

               }

           }

           catch (Exception ex)

           {

               MessageBox.Show(ex.Message);

           }

       }

       catch (Exception ex)

       {

           MessageBox.Show(ex.Message);

       }

   }

 

Note: As stated in the previous article, Sage 200 objects are not serialisable therefore you need to write your own objects (code2.9) and serialise those. A stock class will be required in addition to our previous supplier class and this will need to be available to both the client and service application.

code2.9

    // INotifyPropertyChanged good for silverlight data binding

    [DataContract]

    public class Sage200Stock : INotifyPropertyChanged

    {

    public Sage200Stock() { }

 

    string Code;

    string Description;

    decimal CostPrice;

 

    [DataMember]

    public string StockCode

    {

        get { return Code; }

        set

        {

            Code = value;

            NotifyPropertyChanged(“StockCode”);

        }

    }

 

    [DataMember]

    public string StockDescription

    {

        get { return Description; }

        set

        {

            Description = value;

            NotifyPropertyChanged(“StockDescription”);

        }

    }

 

    [DataMember]

    public decimal StockPrice

    {

        get { return CostPrice; }

        set

        {

            CostPrice = value;

            NotifyPropertyChanged(“StockPrice”);

        }

    }

 

 

    // propertyChanged event

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String propertyName)

    {

        if (null != PropertyChanged)

        {

            PropertyChanged(this,

                new PropertyChangedEventArgs(propertyName));

        }

    }

 

You can add as many properties as required; we’ve tried to keep things as simple as possible here.

 

Retrieve data from the service based on a received parameter value

We initially need to add a new OperationContract to our ServiceContract interface, this will use a WebGet attribute because we don’t intend to update our Sage 200 database.

This new OperationContract is almost identical to the one we created previously for Suppliers only this time we need to deal with the respective parameter (which we’ve named ‘supplierRef’ in this scenario):

code2.10

        [OperationContract]

        [WebGet(UriTemplate = "/Stock/{supplierRef}",  BodyStyle = WebMessageBodyStyle.Bare,

            ResponseFormat = WebMessageFormat.Json)]

        System.Collections.ObjectModel.ObservableCollection<Sage200Stock>

            GetStock(string supplierRef);

 

Our UriTemplate attribute has the supplierRef parameter associated with it and the GetStock() method has the same string parameter.

We now need to write the code that will perform the actual work of reading that supplierRef, getting the respective StockItems that this particular supplier is linked with. We’ve used the process detailed in another article (Using DataModels from code…) to get the StockItems we need because, as you’re probably aware, querying the database for StockItems, via the Sage200 SDK, would involve obtaining all StockItems then filtering that collection, which can be a resource intensive task if you have thousands of StockItems. So code2.11 shows how to obtain just the Supplier’s StockItems by reading the Sage.Data.DataModel instance. These StockItems are then fed into our ObservableCollection of serialisable Stock to pass back to the client.

code2.11

        // get the stockItems that the given supplier supplies

        // we’re only using this code to read data hence the use of the ‘datamodel’ approach

        public ObservableCollection<Sage200Stock> GetStock(string supplierRef)

        {

            // connect to database

            application = new Sage.Accounting.Application();

            application.Connect(“2″, “”);

            application.ActiveCompany = application.Companies[0];

 

            try

            {

                ObservableCollection<Sage200Stock> _stockList =

                    new ObservableCollection<Sage200Stock>();

 

                // create an instnace of the model I want – in this case “Sage 200 Accounts”

                Sage.Data.DataModel model = (new Sage.Data.ModelManagement.DataModelProvider()).

                    CreateNew(“Sage 200 Accounts”, null);

 

                // bind the connection

                bool bound = model.BindConnection(null);

 

                // retrieve the context from the model

                Sage.Accounting.DataModel.DataContext context =

                    (Sage.Accounting.DataModel.DataContext)(model.ModelContext);

 

 

                // get the supplier

                Sage.Accounting.PurchaseLedger.Supplier supp =

                    Sage.Accounting.PurchaseLedger.SupplierFactory.Factory.Fetch(supplierRef);

 

                // The context for the Sage 200 Accounts model contains all of the entities

                //  you’d expect in addition to the calculated fields and projections

                // Here, we’re getting all the stockItems supplied by a given supplier i.e.

                //  the supplier selected from our service app

                var stockSuppliers = context.StockItemSuppliers.Where(

                            s => s.SupplierID == (long)supp.PLSupplierAccount);

 

 

                // iterate through the generated list of anonymous types

                //  returned by the linq expression above

                foreach (var stockData in stockSuppliers)

                {

                    // declare a new stockItem

                    Sage200Stock stk = new Sage200Stock();

 

                    // populate the required data

                    stk.StockCode = stockData.StockItem.Code;

                    stk.StockDescription = stockData.StockItem.Description;

                    stk.StockPrice = stockData.StockItem.AverageBuyingPrice;

 

                    // add each item to our observableCollection

                    _stockList.Add(stk);

                }

 

                return _stockList;

            }

            catch (Exception ex)

            {

                throw new Exception(ex.Message);

            }

            finally

            {

                application.Disconnect();

                application.Dispose();

                application = null;

            }

        }

 

Remember to add the same Stock class, used in the client, to the service application (You may need to add the following using statement using System.ServiceModel.Web; in addition to changing the namespace to match the service application namespace.

We can now run the projects as before and the output is as seen in image2.4 which starts from the point of viewing the list of suppliers:

image2.4

final results

From left to right we have the list of suppliers with the selected supplier circled in red, upon clicking that supplier we get the new screen with a list of supplied stock and the last screen appears after clicking the circled ‘Back’ button from the Supplier’s Stock page.

The UI’s we’ve presented here have had no real work applied to them so the next step would be to provide a much more user centric UI and to take the project further by obtaining costs for the given products from a given comparison website.

Written by GavD

August 3rd, 2011 at 4:05 pm

Posted in Windows Phone 7

Tagged with ,

Getting started with Win Phone 7

with one comment

The following blog is intended to provide some basic information, and code, to get you started with Windows Phone 7 development.

This is by no means an example of ‘Best Practice’ it is more a means of showing how you can use WCF Web Services with JSON serialisation to transfer data from Sage200 to your phone.

This blog includes:

  1. Initial setup and requirements
  2. Development processes
  3. A basic application
  4. Integrating with Sage200
  5. Sage200 surrogate class
  6. Creating the service
  7. Creating the client (the Windows Phone 7 app)

Initial Setup and Requirements

Before you begin writing any code or even contemplate transferring data from Sage 200 to your phone you will need:

  • Sage 200 2011
  • Sage 200 2011 Developer Edition
  • A Phone with the Windows Phone 7 operating system*
  • Windows Phone SDK (Windows Phone Developer Tools)

All of the necessary information regarding the Windows Phone Developer Tools and the respective files can be found on the Microsoft App Hub.

*It isn’t necessary to be a paid up subscriber to see your ‘app’ in a Windows Phone 7 emulator but if and when you wish to publish your app, or indeed see it on an actual phone, then you will need to pay the required costs to Microsoft (at time of writing this is a $99 annual subscription).

There was an off-line installer for the Windows Phone 7 Developer Tools but this appears to have been superseded with a small .exe (vm_web.exe) which then performs all the relevant downloads for you. You must be online throughout the whole process which can take some time (this took almost two hours on a test machine with a typically fast broadband connection), particularly if the process needs to download a version of Visual Studio Express.

The installation of the Windows Phone 7 Developer Tools adds Microsoft Silverlight 4 and Phone emulator add-ins in addition to a number of extra project templates to existing Visual Studio 2010 installations on your development machine.

Whichever machine you develop on must have a compatible Display driver model:

image1
img1_DxDiag

Anything less than WDDM 1.1 will give rise to a never ending message on your emulator:
Windows Phone Emulator is doing a complete OS boot…
If your display driver is compatible you may still see this message, but only very briefly.

Development Processes

The first thing you need to bear in mind is the fact that a phone, in its current incarnation, has a vastly reduced hardware configuration to that of your pc’s especially in terms of RAM and the CPU.

Another is to understand that you will not necessarily have internet and/or network access at all times so we need to compensate for this.

We also need some way of transferring data from the Sage 200 database to a phone in a format that is suitable for the phone to deal with. Like almost all data transfer to a phone you’ll need to use web services or a very similar technology.

In the scenario we’re dealing with it’s not overly important that you’re familiar with web services although a basic understanding will help (and if you’re planning to take this type of development any further then it will be beneficial to gain a much better and broader understanding of web protocols and development).

There are a number of different ways of using web services as well as a number of different types including (but by no means limited to):

  • WCF Data Services (or OData)
  • SOAP and DataSets
  • REST and XML
  • REST and JSON

Some of them could give rise to resource and memory issues but if you head along the RESTful WCF route and use JSON serialization then your app will be as fast and efficient as possible and this is the route we’ve followed in producing this brief overview.

Another major point to note is that Sage 200 objects are not serializable so you will not, by default, be able to transmit those objects ‘across the wire’ to the phone. What’s required in these instances is the use of ‘surrogate’ classes to hold all of the Sage 200 data and it’s these surrogate classes that are marked as serializable, you can then transmit your own classes across the wire.

Any project you create for RESTful WCF Services needs assembly references for System.ServiceModel and System.ServiceModel.Web.

A Basic Windows Phone 7 Application

This section gives a brief introduction to some of the Windows Phone 7 developer tools and goes through a relatively simple “Hello World” example. We’ll use Visual Studio 2010 and the Windows phone 7 emulator. It’s necessary for you to have installed and set up the developer tools already.

When dealing with the emulator you can debug your Visual Studio projects in the same way as any other project and it’s probably useful to set a few breakpoints along the way.

Don’t forget to check your Display driver model using DxDiag.exe in Start | Run (or some other suitable alternative) to ensure you’re WDDM 1.1 compatible or you won’t be able to view your results in the emulator

  1. Open Visual Studio 2010
  2. Choose File | New and then select Project
  3. From the Visual C# templates select Silverlight for Windows Phone and then Windows Phone Application (see image2 below; the important areas are highlighted).
    image2:
    New Win Phone 7 app
  4. Provide a suitable name and location for your application so it looks pretty similar to image2 above
  5. Click OK and you’ll now see an editable Form in the guise of a Windows Phone 7 screen and the associated XAML code (see image3) called MainPage.xaml
    image3
    new app xaml
  6. The UI section can be used in the same manner as a Windows form so you can drop controls on from the Toolbox. Add a TextBox, Button and TextBlock so it looks like image4:
    image4
    toolbox
    You could just as easily edit the xaml code directly instead of using the toolbox. The controls and respective code are boxed in image4
  7. Again, like Windows form development, you can double click on a selected control to get at the code behind so go ahead and double click the button control and you’ll see code1 below
    code1

    public partial class MainPage : PhoneApplicationPage

    {

    // Constructor

    public MainPage()

    {

    InitializeComponent();

    }

    private void button1_Click(object sender, RoutedEventArgs e)

    {

    }

    }

  8. All we’re doing, for this small introduction, is getting whatever text has been entered into textBox1, showing that text in textBlock1 and subsequently clearing the text from textBox1 at the click of button1. Add the necessary code to the button1_Click method so it looks like code2 below
    code2

    private void button1_Click(object sender, RoutedEventArgs e)

    {

    textBlock1.Text = textBox1.Text;

    textBox1.Text = String.Empty;

    }

  9. If you’ve followed the steps above, as written, then you’ll see the same  results shown in image5
    image5
    running HelloWorld app
    From left to right we have the emulator after the initial load, something typed into textBox1 (using the emulator’s keypad) and, in the final image on the right, the results of clicking button1

Integrating with Sage200

In order for us to start passing data between Sage200 and the phone we need some sort of service and, as mentioned earlier, we’ll be using RESTful (Representational State Transfer) WCF (Windows Communication Foundation) and JSON (JavaScript Object Notation) to try and reduce overall data costs.

Although Silverlight doesn’t support JSON Serialization ‘out of the box’ we do get the DataContractJsonSerializer to work with WCF objects that have been encoded with JSON making our job a bit simpler.

We won’t be generating a client-side proxy for your phone via adding a Service Reference or using slsvcutil.exe. Generally, you’d add a service reference (the url in image6) in your client project to access the respective web methods in your service:

image6
running service
Therefore we need to build our own models.  The same objects we build on the server for our WCF Service will be the same ones we copy to our Windows Phone 7 (client) project.

To ensure that our classes (and their properties) are properly serialized for transport over the air, we need to use the DataContract() and DataMember() attributes.

It’s not imperative but if you want your objects to be Silverlight-friendly, for data binding purposes, then implement the INotifyPropertyChanged interface.  You’ll also need to add a PropertyChangedEventHandler to each class firing that event in each property’s setter.  This facilitates new or changed data in a bound control to update your model automatically.

Sage200 surrogate class

There’s not a great deal to this class; we’re adding ‘accessor’ methods for a couple of properties with the NotifyPropertyChanged event and its associated handler.

This type of class is required because, as you’ll remember, Sage 200 objects aren’t serializable so we need an object we can serialize, and this is it:

code3

using System;

using System.Collections.Generic;

using System.Collections.ObjectModel;

using System.ComponentModel;

using System.Linq;

using System.Runtime.Serialization;

using System.ServiceModel;

using System.ServiceModel.Web;

using System.Text;

[DataContract]

public class Sage200Supplier : INotifyPropertyChanged

{

public Sage200Supplier() { }

string AccRef;

string Name;

[DataMember]

public string SupplierReference

{

get { return AccRef; }

set

{

AccRef = value;

NotifyPropertyChanged(“SupplierReference”);

}

}

[DataMember]

public string SupplierName

{

get { return Name; }

set

{

Name = value;

NotifyPropertyChanged(“SupplierName”);

}

}

// propertyChanged event

public event PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged(String propertyName)

{

if (null != PropertyChanged)

{

PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

}

}

}

As you can see in code3 we’re defining our class with a DataContract attribute and each property with a DataMember attribute. The class also implements the INotifyPropertyChanged interface.

This defines a Model and can be copied into the Windows Phone 7 (client) application too so that the client knows how to deal with the data it receives.

Creating the service

Initially we need to create a new WCF Service Library application. This one isn’t specific to a Windows Phone app, it’s just the service side of things.

image7
service project
We need to begin with a public Interface (see code4 below).  This is our Service Contract that exposes one or more Operation Contracts. You don’t need to worry about the actual creation of the interface because, when you create a new Visual Studio project in this way it generates the interface for you in addition to adding default contract attributes where necessary.

In this scenario we’ll be retrieving data, this means using a GET request.  The WebGet attribute allows us to specify this (if we wanted to Insert, Update or Delete data in Sage200 via this service we’d need to use the WebInvoke attribute instead).

We’ll also use a UriTemplate which allows us to point to REST friendly URIs rather than calling web methods that are buried inside a single URI. We’re getting a list of Suppliers so the UriTemplate = “/Suppliers.”  We can set BodyStyle == Bare which prevents extra XML wrapping of our parameters and return values.  For the ResponseFormat property we set the WebMessageFormat to Json instead of XML in order to send the minimum amount of data across the wire.

We’re then adding a GetSuppliers() method that returns an ObservableCollection<T> of Supplier objects. An ObservableCollection represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.

code4

using System;

using System.Collections.Generic;

using System.Collections.ObjectModel;

using System.ComponentModel;

using System.Linq;

using System.Runtime.Serialization;

using System.ServiceModel;

using System.ServiceModel.Web;

using System.Text;

namespace WinPhone7Service

{

[ServiceContract]

public interface IWinPhone7Service

{

[OperationContract]

[WebGet(UriTemplate = "/Suppliers", BodyStyle = WebMessageBodyStyle.Bare,

ResponseFormat = WebMessageFormat.Json)]

System.Collections.ObjectModel.ObservableCollection<Sage200Supplier> GetSuppliers();

}

}

We’ve deleted the default OperationContracts that the project declares for us and added our own GetSuppliers() method with the attributes detailed on the previous page.

Note: Don’t forget to add the code for our Sage200Supplier surrogate class into this project.

That’s our interface written so the next step is to get the data out of Sage200 and this is where our ObservableCollection comes in. We also need to connect to the Sage200 database before we can retrieve any data.

In our service class add:

code5

using System;

using System.Collections.Generic;

using System.Collections.ObjectModel;

using System.ComponentModel;

using System.Linq;

using System.Runtime.Serialization;

using System.ServiceModel;

using System.ServiceModel.Web;

using System.Text;

using System.Web.Configuration;

namespace WinPhone7Service

{

public class WinPhone7Service : IWinPhone7Service

{

Sage.Accounting.Application application = null;

public ObservableCollection<Sage200Supplier> GetSuppliers()

{

// connect to database

application = new Sage.Accounting.Application();

application.Connect(“2″, “”);

application.ActiveCompany = application.Companies[0];

// get all overseas suppliers

Sage.Accounting.PurchaseLedger.Suppliers suppliers =

Sage.Accounting.PurchaseLedger.SuppliersFactory.

Factory.FetchNonBaseCurrencySuppliers();

// pass the suppliers into our observable collection

try

{

ObservableCollection<Sage200Supplier> _supplierList = new

ObservableCollection<Sage200Supplier>();

if (!suppliers.IsEmpty)

{

foreach (Sage.Accounting.PurchaseLedger.Supplier supplier in suppliers)

{

Sage200Supplier supp = new Sage200Supplier();

supp.SupplierReference = (string)supplier.Reference;

supp.SupplierName = (string)supplier.Name;

_supplierList.Add(supp);

}

}

return _supplierList;

}

catch (Exception ex)

{

throw new Exception(ex.Message);

}

finally

{

application.Disconnect();

application.Dispose();

application = null;

}

}

}

}

You’ll also need to add and possibly rejig the Web.config file for this service. It’s the <system.serviceModel> section that may need editing on your setup. We’re just setting the endpoint’s binding to webHttpBinding and the respective (IService1) contract. We’re also setting the endpoint behaviour to REST:

code6

<system.serviceModel>

<services>

<service name=WinPhone7Service.Service1Behaviour>

<endpoint address=“” behaviorConfiguration=REST binding=webHttpBinding

 contract=WinPhone7Service.IService1>

</endpoint>

<!–<endpoint address=”mex” binding=”mexHttpBinding” contract=”IMetadataExchange”/>–>

</service>

</services>

<behaviors>

<serviceBehaviors>

<behavior name= WinPhone7Service.Service1Behavior>

<!– To avoid disclosing metadata information, set the value below to false and remove

the metadata endpoint above before deployment –>

<serviceMetadata httpGetEnabled=false/>

<!– To receive exception details in faults for debugging purposes, set the value below

to true.  Set to false before deployment to avoid disclosing exception information

 –>

<serviceDebug includeExceptionDetailInFaults=false/>

</behavior>

</serviceBehaviors>

<endpointBehaviors>

<behavior name=REST>

<webHttp />

</behavior>

<behavior name=HelpBehavior>

<webHttp helpEnabled=true />

</behavior>

</endpointBehaviors>

</behaviors>

<serviceHostingEnvironment multipleSiteBindingsEnabled=true />

</system.serviceModel>

</configuration>

We can now compile and run this service.

Note: This service must be running while you run the Windows Phone 7 app in the emulator (or on the phone).

Creating the Windows Phone 7 application (client)

Create a new Windows Phone 7 application in Visual Studio 2010 in the same way as described earlier with image2.

Start off by adding the same Sage200 surrogate class (code3) we added to our Service application. This is so the Phone application knows how to deal with the data we send across to it. Ensure you change the Namespace though as this class needs your client’s Namespace. There’s also no need for the System.ServiceModel.Web using statement. Also, in order to support the DataContract() and DataMember() attributes, we need to add a reference to System.Runtime.Serialization.

We haven’t mentioned it yet but to avoid the need to perform multiple web requests we’re going to store the initial list of suppliers in the phone’s own database.

Add a new class to your project called Database and enter the following:

code7

using System;

using System.Net;

using System.Windows;

using System.Collections.Generic;

using System.Collections.ObjectModel;

using System.Runtime.Serialization.Json;

using System.IO.IsolatedStorage;

namespace CompareCostsClient

{

sealed class Database

{

//Declare Instance

private static readonly Database instance = new Database();

//Private Constructor

private Database() { }

//The entry point into this Database

public static Database Instance

{

get

{

return instance;

}

}

//Declare Private Variables

private ObservableCollection<Sage200Supplier> supplierTable = null;

//Customer Table

public ObservableCollection<Sage200Supplier> Suppliers

{

get { return supplierTable; }

set { supplierTable = value; }

}

}

}

 

The code comments in code7 pretty much explain what’s going on here but this is why the Sage200Supplier class is needed first.

You can now add some controls to the phone’s UI, we’ve added two buttons and a ListBox. The two buttons both deal with the phone’s internal database; the first button gets the suppliers and adds them to the database while the second button queries the internal database and shows those suppliers in a list.

In Visual Studio 2010, on the MainPage.xaml we have the following:

image8
display running app
The parts circled in red (in image8) are the three controls and their respective .xaml references in the ContentPanel. The background .png has also been changed but this isn’t necessary at all.

Double click the button labelled “Get Suppliers” and enter the following:

code8

private void getSuppBtn_Click(object sender, RoutedEventArgs e)

{

try

{

WebClient webClient = new WebClient();

Uri uri = new Uri(“http://localhost:53857/CompareCostsService.svc/Suppliers”);

webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(OpenReadCompletedSuppliers);

webClient.OpenReadAsync(uri);

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

}

}

Change the Uri to suit your environment, it’s highly unlikely you’ll have the same port number as defined above (in code8).

All calls are asynchronous and the WebClient created an event handler (OpenReadCompletedEventHandler) so, in order to add the Sage200 suppliers to our internal database we use that event:

Code9

void OpenReadCompletedSuppliers(object sender, OpenReadCompletedEventArgs e)

{

DataContractJsonSerializer jsonSerializer = null;

try

{

jsonSerializer = new DataContractJsonSerializer(typeof(ObservableCollection<Sage200Supplier>));

Database.Instance.Suppliers = jsonSerializer.ReadObject(e.Result) as ObservableCollection<Sage200Supplier>;

// show the suppliers (if we’ve got some) in a list

try

{

if (Database.Instance.Suppliers != null)

{

MessageBox.Show(“All suppliers have been added to the internal database”);

}

else

{

MessageBox.Show(“There are no overseas suppliers”);

}

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

}

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

}

}

The next part is purely to display the contents of our phone’s internal database in the ListBox we added to the UI

Code10

private void viewSuppsBtn_Click(object sender, RoutedEventArgs e)

{

try

{

if (Database.Instance.Suppliers != null)

{

suppsListBox.DisplayMemberPath = “SupplierReference”;

suppsListBox.ItemsSource = Database.Instance.Suppliers;

}

else

{

MessageBox.Show(“There are no overseas suppliers”);

}

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

}

}

You can now compile and run the phone application ensuring your target is the Windows Phone 7 Emulator:

image9
run to emulator
This will produce the following:

Image10
running client
From left to right we have the initial launch window, the output from clicking the ‘Get Suppliers’ button and lastly the output from clicking the ‘View Suppliers’ button.

Written by GavD

July 12th, 2011 at 12:37 pm

Posted in Windows Phone 7

Tagged with ,

Using Data Models From Code To Read Sage 200 Data Efficiently

with 2 comments

A common pattern when integrating with Sage 200 is to write custom SQL queries in order to read large volumes of data quickly. This can be done by creating views or stored procedures on the database, or by assembling SQL commands in code (for example in an add-on assembly).

This method is often chosen in preference to reading data via the Business Objects because it is fast and memory efficient. In particular, creating a large collection of complicated Business Objects can use a lot of memory and this overhead is unnecessary if the goal of the operation is simply to read a set of data from Sage 200 into an integrating application or system.

Using SQL to access the database directly has advantages, but it also has some problems, namely:

However, there is another approach that is both fast and memory efficient and which provides access to calculated fields as well as automatically providing access to the relevant links between tables and entities.

This approach is to use a Data Model to access the data. Data Models provide the data sources for the Sage 200 Report Designer and also for Desktop Workspaces and the Sage 200 Mobile solution. A Data Model is an assembly that provides a representation of entities and collections of entities that can be queried in familiar ways.

A simple model might be a layer over the database, providing a one-to-one mapping between tables in the database and objects in the assembly.

A more sophisticated model might add calculated fields or even create whole new entities or wrappers in order to present the data in a more useful way.

Below is an example of how to access a model from code.

[snippet id=55825]

Why not try this out with your own data and compare the performance against a direct to SQL query? You should find that a query via the model will typically only be a little slower than a direct to SQL query and has the advantages of access to calculated fields, simpler queries due to known joins and references being automatically resolved and insulation from changes to the raw database schema.

Note that this code snippet was written in LinqPad and makes use of the Dump() extension method. The code makes its own connection to the application which would be unnecessary if it was running as an assembly inside the context of the application.

The following are the required assembly references for this example:

Sage.Common.DynamicLinq.dll
Sage.Common.LinqExpandable.dll
Sage.QueryExtensions.dll
Sage.Common.LinqExtensions.dll
Sage.Common.dll
Sage.ObjectStore.dll
Sage.Accounting.PersistentObjects.dll
Sage.Utils.dll
Sage.Accounting.Common.PersistentObjects.dll
Sage.Accounting.Common.dll
Sage.Data.dll
Sage.Accounting.DataModel.dll
Sage.Data.ModelManagement.dll
Sage.Accounting.Financials.dll

… and these are the namespace imports

Sage.Accounting.Common
Sage.Accounting.Financials
Sage.Common
Sage.Common.LinqExtensions
Sage.ObjectStore
Sage.Accounting.DataModel
Sage.Data.ModelManagement
Sage.Data

Written by John Hulme

June 28th, 2011 at 9:16 am

Posted in Uncategorized

Windows Phone 7 Development Competition

without comments

Just a quick reminder that it is not too late to enter our Windows Phone 7 Development Competition.

All the necessary details can be found here and the closing date is the 8th July.

Please note all entrants must be existing members of the Sage Developers Programme.

Good luck!

Written by Richard Custance

June 27th, 2011 at 11:39 am

Posted in Windows Phone 7

Tagged with ,