March 2010 - Posts

How to have a sequential logic with asynchronous?

Asynchronous is often very useful:

  • to avoid freezing the application during the process
  • to be able to cancel a process during its execution

However, the use of asynchronous is more complex and algorithms become more difficult to understand.

Nevertheless, this approach is used more and more.

Only asynchronous mode is supported by Silverlight to call web services!

Imagine the following exercise:

We want to call a service one and only once, put the result in cache and then use the cache.

With a synchronous mode, no problem:

static class Service
{
    private static string _value;
    public static string Value
    {
        get 
        {
            if (_value == null)
                using (ServiceClient service = new ServiceClient())
                {
                    _value = service.GetData(0);
                }
            return _value; 
        }
    }
}

To call it, we can simply write this (in a Console application):

Console.WriteLine(Service.Value);

Ok. Nothing difficult here.

// In this post, I will have to version: one with lambda expressions and one without.

Now, imagine that we want to do the same as previously with asynchronous mode.

To do it, we will use an event based logic:

public static class Service
{
    public static void Init()
    {
        using (ServiceClient service = new ServiceClient())
        {
            service.GetDataCompleted += (sender, e) =>
            {
                if (e.Cancelled)
                    return;
                if (e.Error != null)
                    throw e.Error;
                Value = e.Result;
                if (ValueInitialized != null)
                    ValueInitialized();
            };
            service.GetDataAsync(0);
        }
   
  
    public static string Value { get; private set; } 

   
public static event Action ValueInitialized;
}

public static class Service
{
    public static void Init()
    {
        using (ServiceClient service = new ServiceClient())
        {
            service.GetDataCompleted += service_GetDataCompleted;
            service.GetDataAsync(0);
        }
   

    private static void service_GetDataCompleted(object sender, GetDataCompletedEventArgs e)
    {
        if (e.Cancelled)
            return;
        if (e.Error != null)
            throw e.Error;
        Value = e.Result; 
        if (ValueInitialized != null)
            ValueInitialized();
    }

 

    public static string Value { get; private set; } 
  
    public static event Action ValueInitialized;
}

Now the call is only this:

Service.ValueInitialized += () => Console.WriteLine(Service.Value);
Service.Init();

Service.ValueInitialized += Service_ValueInitialized;
Service.Init();

 

private static void Service_ValueInitialized()
{
    Console.WriteLine(Service.Value);
}

Now, we want to get Service.Value without knowing if it’s already loaded. How to do it?

First, we have to determine if Value is already loaded or not.

To do it, we will add a boolean property IsInitialized:

public static class Service
{
    public static void Init()
   
        if (IsInitialized)
            return;
        using (ServiceClient service = new ServiceClient())
        {
            service.GetDataCompleted += (sender, e) =>
            {
                if (e.Cancelled)
                    return;
                if (e.Error != null)
                    throw e.Error;
                Value = e.Result;

                IsInitialized = true;
                if (ValueInitialized != null)
                    ValueInitialized();
            };
            service.GetDataAsync(0);
        }
   
  
    public static string Value { get; private set; } 

    public static bool IsInitialized { get; private set; } 

   
public static event Action ValueInitialized;
}

public static class Service
{
    public static void Init()
   
        if (IsInitialized)
            return;
        using (ServiceClient service = new ServiceClient())
        {
            service.GetDataCompleted += service_GetDataCompleted;
            service.GetDataAsync(0);
        }
   

    private static void service_GetDataCompleted(object sender, GetDataCompletedEventArgs e)
    {
        if (e.Cancelled)
            return;
        if (e.Error != null)
            throw e.Error;
        Value = e.Result; 

        IsInitialized = true
        if (ValueInitialized != null)
            ValueInitialized();
    }


    public static string Value { get; private set; } 

    public static bool IsInitialized { get; private set; }
  
    public static event Action ValueInitialized;
}

If we look at my initial “specifications”, we want to be sure that the service is called only once. Because of multi-threading, we can call the service more than once.

To fix it, we will call the service in the static constructor:

public static class Service

    static Service()
    {
        using (ServiceClient service = new ServiceClient())
        {
            service.GetDataCompleted += (sender, e) =>
            {
                if (e.Cancelled)
                    return;
                if (e.Error != null)
                    throw e.Error;
                Value = e.Result;

                         IsInitialized = true;
                         if (ValueInitialized != null)
                    ValueInitialized();
            };
            service.GetDataAsync(0);
        }
   
  
    public static string Value { get; private set; } 

    public static bool IsInitialized { get; private set; }


   
public static event Action ValueInitialized;
}

public static class Service
{
    static Service()
    {
        using (ServiceClient service = new ServiceClient())
        {
            service.GetDataCompleted += service_GetDataCompleted;
            service.GetDataAsync(0);
        }
   

    private static void service_GetDataCompleted(object sender, GetDataCompletedEventArgs e)
    {
        if (e.Cancelled)
            return;
        if (e.Error != null)
            throw e.Error;
        Value = e.Result;  
        IsInitialized = true;  
        if (ValueInitialized != null)
            ValueInitialized();
    }

 

    public static string Value { get; private set; } 

    public static bool IsInitialized { get; private set; } 

  
    public static event Action ValueInitialized;
}

To get the Service.Value, we can now use the following code:

Action valueInitialized = () => Console.WriteLine(Service.Value);
if (Service.IsInitialized)
    valueInitialized();
else
    Service.ValueInitialized += valueInitialized;

if (Service.IsInitialized)
    Service_ValueInitialized();
else
    Service.ValueInitialized += Service_ValueInitialized;

private static void Service_ValueInitialized()
{
    Console.WriteLine(Service.Value);
}

However, this isn’t enough. Indeed, because of multi-threading, we can have the following case: the main thread is running. It gets IsInitialized (false) then it’s suspended. Then, the asynchronous thread is running. It sets IsInitialized = true and raises ValueInitialized event. The main thread is running again, wait from ValueInitialized even which was already raised…

01: Action valueInitialized = () => Console.WriteLine(Service.Value);
04: if (Service.IsInitialized)
        valueInitialized();
    else
11:    Service.ValueInitialized += valueInitialized;

02: using (ServiceClient service = new ServiceClient())
    {
        service.GetDataCompleted += (sender, e) =>
        {
05:        if (e.Cancelled)
               return;
06:        if (e.Error != null)
               throw e.Error;
07:        Value = e.Result;

08:                  IsInitialized = true;
09:                  if (ValueInitialized != null)
10:            ValueInitialized();
        };

03:     service.GetDataAsync(0);
    }

So we have to do something for this case:

public static class Service

    static Service()
    {
        using (ServiceClient service = new ServiceClient())
        {
            service.GetDataCompleted += (sender, e) =>
            {
                if (e.Cancelled)
                    return;
                if (e.Error != null)
                    throw e.Error;
                Value = e.Result; 
                lock (LockObject)
                {
                    IsInitialized = true;
                    if (ValueInitialized != null)
                        ValueInitialized();

                }

            };
            service.GetDataAsync(0);
        }
   


   
private static object _lockObject = new object();
    public static object LockObject
    {
        get { return _lockObject; }
    }

              
    public static string Value { get; private set; } 

    public static bool IsInitialized { get; private set; }


   
public static event Action ValueInitialized;
}

public static class Service
{
    static Service()
    {
        using (ServiceClient service = new ServiceClient())
        {
            service.GetDataCompleted += service_GetDataCompleted;
            service.GetDataAsync(0);
        }
   

    private static void service_GetDataCompleted(object sender, GetDataCompletedEventArgs e)
    {
        if (e.Cancelled)
            return;
        if (e.Error != null)
            throw e.Error;
        Value = e.Result;  
        lock (LockObject)
        {
            IsInitialized = true;
            if (ValueInitialized != null)
                ValueInitialized();
        }
   


   
private static object _lockObject = new object();
    public static object LockObject
    {
        get { return _lockObject; }
    }

 
    public static string Value { get; private set; }  

    public static bool IsInitialized { get; private set; }  
   
    public static event Action ValueInitialized;
}

Action valueInitialized = () => Console.WriteLine(Service.Value);
if (Service.IsInitialized)
    valueInitialized ();
lock (Service.LockObject)
{
    if (Service.IsInitialized)
        valueInitialized ();
    else
        Service.ValueInitialized += valueInitialized;
}

if (Service.IsInitialized)
    Service_ValueInitialized();
lock (Service.LockObject)
{
    if (Service.IsInitialized)
        Service_ValueInitialized();
    else
        Service.ValueInitialized += Service_ValueInitialized;
}

private static void Service_ValueInitialized()
{
    Console.WriteLine(Service.Value);
}

// The double test on Service.IsInitialized is useful to avoid useless lock.

However, from an architecture point of view, this code is bad! Indeed, it’s a real issue that classes have to know my Service class code (in order to know the lock logic). Moreover, we can have the same code many times in the solution. So we have to factorize it in Service class.

public static class Service
{
    static Service()
    {
        using (ServiceClient service = new ServiceClient())
        {
            service.GetDataCompleted += (sender, e) =>
            {
                if (e.Cancelled)
                    return;
                if (e.Error != null)
                    throw e.Error;
                Value = e.Result;
                lock (_lockObject)
                {
                    IsInitialized = true;
                    if (ValueInitialized != null)
                        ValueInitialized();
                }
            };
            service.GetDataAsync(0);
        }
   
 

    private static object _lockObject = new object(); 
  
    public static string Value { get; private set; } 
  
    private static bool IsInitialized { get; set; } 
  
    public static void DoWhenInitialized(Action action)
   
        if (action == null)
            return;


        if (IsInitialized)
        {
            action();
            return;
        }

        lock (_lockObject)
        {
            if (IsInitialized)
                action();
            else
                ValueInitialized += action;
        }
   
  
    public static event Action ValueInitialized;
}

public static class Service
{
    static Service()
    {
        using (ServiceClient service = new ServiceClient())
        {
            service.GetDataCompleted += service_GetDataCompleted;
            service.GetDataAsync(0);
        }
   
 
    private static void service_GetDataCompleted(object sender, GetDataCompletedEventArgs e)
    {
        if (e.Cancelled)
            return;
        if (e.Error != null)
            throw e.Error;
        Value = e.Result;
        lock (_lockObject)
        {
            IsInitialized = true;
            if (ValueInitialized != null)
                ValueInitialized();
        }
   

    private static object _lockObject = new object(); 
  
    public static string Value { get; private set; } 
  
    private static bool IsInitialized { get; set; }

    public static void DoWhenInitialized(Action action)
    {
        if (action == null)
            return;
 


        if (IsInitialized)
        {
            action();
            return;
        }

        lock (_lockObject)
        {
            if (IsInitialized)
                action();
            else
                ValueInitialized += action;
        }
   
  

    public static event Action ValueInitialized;
}

The call is now only the following:

Service.DoWhenInitialized(() => Console.WriteLine(Service.Value));

Service.DoWhenInitialized(Service_ValueInitialized);

private static void Service_ValueInitialized()
{
    Console.WriteLine(Service.Value);
}

The last point is very important: don’t forget to remove handler on your events!

So the last version of my code is the following:

public static class Service
{
    static Service()
    {
        using (ServiceClient service = new ServiceClient())
        {
            EventHandler<GetDataCompletedEventArgs> serviceGetDataCompleted = null;
            serviceGetDataCompleted = (sender, e) =>
            {
                service.GetDataCompleted -= serviceGetDataCompleted;
                if (e.Cancelled)
                    return;
                if (e.Error != null)
                    throw e.Error;
                Value = e.Result;
                lock (_lockObject)
                {
                    IsInitialized = true;
                    if (ValueInitialized != null)
                        ValueInitialized();
                }
            };
            service.GetDataCompleted += serviceGetDataCompleted;
            service.GetDataAsync(0);
        }
    }   

    private static object _lockObject = new object(); 
  
    public static string Value { get; private set; } 
  
    private static bool IsInitialized { get; set; } 
  
    public static void DoWhenInitialized(Action action)
    {

        if (action == null)
            return;

        if (IsInitialized)
        {
            action(); 
            return;
        }

        lock (_lockObject)
        {
            if (IsInitialized)
                action();
            else
            {
                Action valueInitialized = null;
                valueInitialized = () =>
                   
{
                        ValueInitialized -= valueInitialized;
                        action(); 
                    };
 
                ValueInitialized += valueInitialized;
            }
        }
    }  
   
    private static event Action ValueInitialized;
}

public static class Service
{
    static Service()
    {
        using (ServiceClient service = new ServiceClient())
        {
            EventHandler<GetDataCompletedEventArgs> serviceGetDataCompleted = null;
            serviceGetDataCompleted = (sender, e) =>
            {
                service.GetDataCompleted -= serviceGetDataCompleted;
                if (e.Cancelled)
                    return;
                if (e.Error != null)
                    throw e.Error;
                Value = e.Result;
                lock (_lockObject)
                {
                    IsInitialized = true;
                    if (ValueInitialized != null)
                        ValueInitialized();
                }
            };
            service.GetDataCompleted += serviceGetDataCompleted;
            service.GetDataAsync(0);
        }
   
 
    private static object _lockObject = new object(); 
 
    public static string Value { get; private set; } 
 
    private static bool IsInitialized { get; set; } 
 
    public static void DoWhenInitialized(Action action)
    {
        if (action == null)
            return;

        if (IsInitialized)
        {
            action(); 
            return;
        }

        lock (_lockObject)
        {
            if (IsInitialized)
                action();
            else 
                ValueInitialized += new ActionClass { Action = action }.Service_ValueInitialized;  
        }
   
 
 
    private static event Action ValueInitialized; 
 
    private class ActionClass
    {
        public Action Action { get; set; } 
 
        public void Service_ValueInitialized()
        {
            ValueInitialized -= Service_ValueInitialized;
            if (Action != null)
                Action();
        }
    }

}

//It’s so painful without lambda…

Enjoy [:)]

Posted by Matthieu MEZIL | with no comments
Filed under: , ,

How to map a View on a collection of Complex Type?

With EF, when we want to use views, we have to map them on Entity Type.

The problem is the fact that Entity Type must have a key. In EF, we have Complex Type which doesn’t have Entity Key but we can’t map views on Complex Type.

However, with EF4, we can map SSDL Function on Complex Types. SSDL Function is used for Stored Procedures but we also can define ourselves the query to execute in the SSDL.

By default, EF uses all non nullable columns as key when we haven’t got any key in our DB (which is true with Views).

So my idea is to use SSDL Function in order to map views on Complex Type.

First, we will import a View from Database. In my sample, Invoices from Northwind.

Then I open the edmx in xml and I delete all CSDL Invoice Entity Type keys.

Then I open the edmx with the designer. I select all Invoice properties, right click and Refactor into New Complex Type.

Then I delete Invoice Entity Type and refuse to also delete Invoices SSDL Type.

I rename my new Complex Type to Invoice.

Then I open the edmx in xml.

Copy the SQL query of the generated EntitySet Invoices:

<EntitySet Name="Invoices" EntityType="MyNorthwindEFModel.Store.Invoices" store:Type="Views" store:Schema="dbo" store:Name="Invoices">
  <DefiningQuery>
    SELECT 
    [Invoices].[ShipName] AS [ShipName], 
    [Invoices].[ShipAddress] AS [ShipAddress], 
    [Invoices].[ShipCity] AS [ShipCity], 
    [Invoices].[ShipRegion] AS [ShipRegion], 
    [Invoices].[ShipPostalCode] AS [ShipPostalCode], 
    [Invoices].[ShipCountry] AS [ShipCountry], 
    [Invoices].[CustomerID] AS [CustomerID], 
    [Invoices].[CustomerName] AS [CustomerName], 
    [Invoices].[Address] AS [Address], 
    [Invoices].[City] AS [City], 
    [Invoices].[Region] AS [Region], 
    [Invoices].[PostalCode] AS [PostalCode], 
    [Invoices].[Country] AS [Country], 
    [Invoices].[Salesperson] AS [Salesperson], 
    [Invoices].[OrderID] AS [OrderID], 
    [Invoices].[OrderDate] AS [OrderDate], 
    [Invoices].[RequiredDate] AS [RequiredDate], 
    [Invoices].[ShippedDate] AS [ShippedDate], 
    [Invoices].[ShipperName] AS [ShipperName], 
    [Invoices].[ProductID] AS [ProductID], 
    [Invoices].[ProductName] AS [ProductName], 
    [Invoices].[UnitPrice] AS [UnitPrice], 
    [Invoices].[Quantity] AS [Quantity], 
    [Invoices].[Discount] AS [Discount], 
    [Invoices].[ExtendedPrice] AS [ExtendedPrice], 
    [Invoices].[Freight] AS [Freight]
    FROM [dbo].[Invoices] AS [Invoices]
  </DefiningQuery>
</EntitySet>

Then delete this EntitySet and its Entity Type (SSDL) Invoices.

Then, add the following SSDL Function:

<Function Name="GetInvoices" IsComposable="false">
  <CommandText>
    SELECT
    [Invoices].[ShipName] AS [ShipName],
    [Invoices].[ShipAddress] AS [ShipAddress],
    [Invoices].[ShipCity] AS [ShipCity],
    [Invoices].[ShipRegion] AS [ShipRegion],
    [Invoices].[ShipPostalCode] AS [ShipPostalCode],
    [Invoices].[ShipCountry] AS [ShipCountry],
    [Invoices].[CustomerID] AS [CustomerID],
    [Invoices].[CustomerName] AS [CustomerName],
    [Invoices].[Address] AS [Address],
    [Invoices].[City] AS [City],
    [Invoices].[Region] AS [Region],
    [Invoices].[PostalCode] AS [PostalCode],
    [Invoices].[Country] AS [Country],
    [Invoices].[Salesperson] AS [Salesperson],
    [Invoices].[OrderID] AS [OrderID],
    [Invoices].[OrderDate] AS [OrderDate],
    [Invoices].[RequiredDate] AS [RequiredDate],
    [Invoices].[ShippedDate] AS [ShippedDate],
    [Invoices].[ShipperName] AS [ShipperName],
    [Invoices].[ProductID] AS [ProductID],
    [Invoices].[ProductName] AS [ProductName],
    [Invoices].[UnitPrice] AS [UnitPrice],
    [Invoices].[Quantity] AS [Quantity],
    [Invoices].[Discount] AS [Discount],
    [Invoices].[ExtendedPrice] AS [ExtendedPrice],
    [Invoices].[Freight] AS [Freight]
    FROM [dbo].[Invoices] AS [Invoices]
  </CommandText>
</Function>

Now, I open the edmx with the designer.

In the model browser window, in Northwind.Store / Stored Procedures, right click on your GetInvoies / Add Function Import.

Specify that this function returns a collection of Complex Type Invoice.

Here we are.

I can now use my Invoices view mapped on my Complex Type.

using (var context = new NorthwindEntities())
{
    List<Invoice> invoices = context.GetInvoices().ToList();
}

 

However, this solution isn’t perfect because we can’t use L2E on Invoices with this way.

Hope that helps.

CSDL Function

In my previous post (in French), I used a CSDL Function in order to have a DateDiff using the DB current date from the LINQ To Entities query.

In this post, I want to calculate the OrderDetail amount with:

(double)od.Quantity * (double)od.UnitPrice * (1D - od.Discount)

We can add a property to OrderDetail class but in this case, we can’t use it in a L2E query.

So my idea is to use a CSDL Function instead.

First, we will add the function in the edmx:

<Function Name="GetAmount" ReturnType="Double">
  <Parameter Name="orderDetail" Type="Self.OrderDetail" />
  <DefiningExpression>
    CAST(orderDetail.Quantity AS Edm.Double) * CAST(orderDetail.UnitPrice AS Edm.Double) * (1 - orderDetail.Discount)
  </DefiningExpression>
</Function>

Then we will add the following extension method:

public static class OrderDetailExtension
{
    [EdmFunction("MyNorthwindEFModel", "GetAmount")]
    public static double GetAmount(this OrderDetail orderDetail)
    {
        return (double)orderDetail.Quantity * (double)orderDetail.UnitPrice * (1D - orderDetail.Discount);
    }
}

Now we can write this query:

var q = from e in context.Employees
        let sold = e.Orders.Sum(o => o.OrderDetails.Sum(od => (double)od.Quantity * (double)od.UnitPrice * (1D - od.Discount)))
        orderby sold descending 
        select new { Employee = e, Sold = sold };

like this:

var q = from e in context.Employees
        let sold = e.Orders.Sum(o => o.OrderDetails.Sum(od => od.GetAmount()))
        orderby sold descending
        select new { Employee = e, Sold = sold };