Posts

....
Technical Blog for .NET Developers ©

Friday, December 26, 2014

Extension Methods

Extension methods are static methods, in static classes, marked up to be added to existing types without creating a new derived type, or modifying the original type. You can use extension methods to extend a class or interface. This feature was introduced in C# 3.0

In this example we will implement extension methods for two different data types: DateTime, and IEnumerable

This is the implementation of the methods in this example

 
    public static class ExtensionMethods
    {
        public static string ToLetterFormat(this DateTime dateTime)
        {
            return dateTime.ToString("MMMM d',' yyyy");
        }

        public static IEnumerable<string> GetOnlyStrings<T>(this IEnumerable<T> list)
        {
            foreach (var item in list)
            {
                if (item is string)
                    yield return item as string;
            }
        }
    }
        


The markup that makes these extension methods is the keyword this used before the first parameter in the parameter list of the method. This keyword is specific to C#, and it instructs the compiler to add the ExtensionMethodAttribute to the method

The first method produces a result like this:

  
    string letterFormatDate = (DateTime.Today).ToLetterFormat();

    Console.WriteLine(letterFormatDate);
    Console.ReadKey();
        




The second method produces this result:


 
    customList.ForEach(l => Console.WriteLine(l.GetType().ToString()));
    Console.ReadKey();

    List<string> allStringsFromCustomList = customList.GetOnlyStrings().ToList();

    Console.WriteLine(Environment.NewLine);

    allStringsFromCustomList.ForEach(s => Console.WriteLine(s));

    Console.ReadKey();
        





<METHOD SOFTWARE © 2014>

Sunday, September 14, 2014

Entity Framework Change Tracker

With ChangeTracker we can track the state of the entities in the database context, so when our processes work into a context we can work on specific group of entities

In this example we have this diagram and a class which handles the retrieve and insert methods. This is the implementation:



 
        public IEnumerable<GALAXIES> GetKnownGalaxies()
        {
            return (from GALAXIES galaxies in _context.GALAXIES select galaxies);
        }

        public void InsertGalaxy(GALAXIES galaxy)
        {
            _context.GALAXIES.Attach(galaxy);
            _context.Entry(galaxy).State = EntityState.Added;
            _context.GALAXIES.Add(galaxy);
        }
       


Now we add a third method to retrieve only the added galaxies:

     
        public IEnumerable<GALAXIES> GetNewGalaxies()
        {
            return
                (from GALAXIES galaxies in _context.ChangeTracker.Entries()
                     .Where(e => e is GALAXIES && e.State == EntityState.Added)
                     .Select(e => e.Entity as GALAXIES)
                 select galaxies);
        }

        public void InsertNewGalaxy()
        {
            GALAXIES newGalaxy = new GALAXIES()
                {
                    Name = "Cartwheel Galaxy",
                    Distance = (decimal)1.5,
                    Magnitude = (decimal)2.9
                };

            galaxyClass.InsertGalaxy(newGalaxy);
        }
    


The result of the program with this sequence is the next:

     
        var knownGalaxies = galaxyClass.GetKnownGalaxies().ToList();

        knownGalaxies.ForEach(
            x =>
            Console.WriteLine("{0}: {1} distance, {2} magnitude", 
                                x.Name, x.Distance.ToString(),
                                x.Magnitude.ToString()));

        Console.WriteLine(Environment.NewLine);
        Console.ReadKey();

        InsertNewGalaxy();

        var newGalaxies = galaxyClass.GetNewGalaxies().ToList();

        newGalaxies.ForEach(
            x =>
            Console.WriteLine("{0}: {1} distance, {2} magnitude", 
                                x.Name, x.Distance.ToString(),
                                x.Magnitude.ToString()));
    





<METHOD SOFTWARE © 2014>

Sunday, April 20, 2014

LINQ Compiled Queries

The process of converting LINQ queries to SQL statements, involves syntax check, and the construction of the SQL query, this task is performed every time we launch the LINQ query

In compiled queries, the syntax check and construction plan are cached in a static class, so LINQ uses this cached plan from the static class object instead of re-building it in sequent executions

In this example we have the next diagram of LINQ to SQL Classes



We will compile these two queries. A compiled query is stored in a Func delegate, where the first argument must be an instance of DataContext (or derived), and the last argument must be the type returned from the query, you can define up to three arguments in the middle as parameters of the compiled query. You will need to specify these arguments for each compiled query invocation

 
        private static Func<BusinessClassesDataContext, DateTime, IQueryable<B_SALES>>
            SalesByDate = CompiledQuery.Compile(
                (BusinessClassesDataContext ctx, DateTime saleDate) =>
                    (from sl in ctx.GetTable<B_SALES>()
                     where sl.SALEDATE >= saleDate
                     select sl));

        private static Func<BusinessClassesDataContext, int, Decimal>
            SalesAverageByCustomer = CompiledQuery.Compile(
                (BusinessClassesDataContext ctx, int idCustomer) =>
                    (from sl in ctx.B_SALES
                     where sl.B_CUSTOMERS.IdCustomer == idCustomer
                     group sl by sl.Price
                     into sales
                     select sales.Average(sl => sl.Price)).First());
                         


Now the code calling these queries is the next

 
        using (BusinessClassesDataContext context = new BusinessClassesDataContext())
        {
            foreach (B_SALES sale in SalesByDate(context, saleDate))
            {
                Console.WriteLine("{0} : {1}", sale.IdSale, sale.IdProduct);
            }

            Console.WriteLine("{0:N2}$", SalesAverageByCustomer(context, 1));
        }            
    



<METHOD SOFTWARE © 2014>

Sunday, February 2, 2014

LINQ Group Operations

In this post we will make a review of the main grouping operations applied with LINQ

The first step will be adding our diagram of LINQ to SQL Classes



For the sake of simplicity, we will program the function LoadContext, which we will call once and will preload data in typed lists

  
    static void LoadContext()
    {
        using (BusinessDataContext businessCtx = new BusinessDataContext())
        {
            customers = (from cst in businessCtx.B_CUSTOMERs
                            select cst).ToList<B_CUSTOMER>();

            products = (from prd in businessCtx.B_PRODUCTs
                        select prd).ToList<B_PRODUCT>();

            providers = (from prv in businessCtx.B_PROVIDERs
                            select prv).ToList<B_PROVIDER>();

            providers_products = (from prv_prd in businessCtx.B_PROVIDERS_PRODUCTs
                                    select prv_prd).ToList<B_PROVIDERS_PRODUCT>();

            sales = (from sls in businessCtx.B_SALEs
                        select sls).ToList<B_SALE>();
        }
    }
        


The next method will make an average of sales grouped by customers, and grouped by products in the second case

  
    static void getAvgSales()
    {
        var avgSalesByCustomer = 
            (from s in sales
                join c in customers
                on s.IdCustomer equals c.IdCustomer
                group s by new { c.FirstName, c.LastName } into cust
                orderby cust.Key.FirstName
                select new
                {
                    Customer = cust.Key.FirstName + " " + cust.Key.LastName,
                    CountSales = cust.Count(),
                    AvgSales = cust.Average(sl => sl.Price)
                });


        var avgSalesByProduct = 
            (from s in sales
                join p in products
                on s.IdProduct equals p.IdProduct
                group s by new { p.Description } into product
                orderby product.Key.Description
                select new
                {
                    Product = product.Key.Description,
                    CountSales = product.Count(),         
                    CountUnits = product.Sum(sl => sl.Cuantity),
                    AvgSales = product.Average(sl => sl.Price)
                });
            
        Console.WriteLine("\n\nAVERAGE BY CUSTOMER\n\n");
        foreach (var avgSale in avgSalesByCustomer)
            Console.WriteLine("{0} : {1} purchases : {2}$", avgSale.Customer, 
                avgSale.CountSales, string.Format("{0:N2}", avgSale.AvgSales));

        Console.WriteLine("\n\nAVERAGE BY PRODUCT\n\n");
        foreach (var avgSale in avgSalesByProduct)
            Console.WriteLine("{0} : {1} sales : {2} units : {3}$", avgSale.Product, 
                avgSale.CountSales, avgSale.CountUnits, string.Format("{0:N2}", 
                avgSale.AvgSales));
    }
        


The output is as follows



The next method will extract sales data grouped by product and the different periods of sale date
  
    static void getSalesByDate()
    {
        var salesByPeriod = 
            (from s in sales
                group s by new 
                { s.B_PRODUCT.Description, s.SaleDate} into grp
                orderby grp.Key.SaleDate, grp.Key.Description
                select new
                {
                    Date = grp.Key.SaleDate.Value.ToString("MM/yyyy"),
                    Product = grp.Key.Description,
                    CountSales = grp.Count(),
                    CountUnits = grp.Sum(sl => sl.Cuantity),
                    AvgSales = grp.Average(sl => sl.Price)
                });

        Console.WriteLine("\n\nAVERAGE BY DATE PERIOD\n\n");
        foreach (string date in salesByPeriod.Select(s => s.Date).Distinct())
        {
            Console.WriteLine(date);
            foreach (var sale in salesByPeriod.Where(s => s.Date == date))
                Console.WriteLine("-- {0} : {1} sales : {2} units : {3}$",
                    sale.Product, sale.CountSales, sale.CountUnits, 
                    string.Format("{0:N2}", sale.AvgSales));
        }
    }
        


Notice that in this occasion, we don't have performed the join to the product set, instead, we have used the access property to the set of products from the set of sales
The result is the next



We can also use lambda syntax in order to release more group operations, such as max or min

  
    static void getSalesByDate()
    {
        var salesByPeriod = 
            (from s in sales
                group s by new 
                { s.B_PRODUCT.Description, s.SaleDate} into grp
                orderby grp.Key.SaleDate, grp.Key.Description
                select new
                {
                    Date = grp.Key.SaleDate.Value.ToString("MM/yyyy"),
                    Product = grp.Key.Description,
                    CountSales = grp.Count(),
                    CountUnits = grp.Sum(sl => sl.Cuantity),
                    AvgSales = grp.Average(sl => sl.Price)
                });


        var maxSalesDate = (from sl in salesByPeriod select sl)
            .Where(sl => sl.AvgSales == salesByPeriod.Max(sld => sld.AvgSales));

        Console.WriteLine(maxSalesDate.First());
    }
        


The result is this




<METHOD SOFTWARE © 2014>