About the author

Brian Keating is a developer addicted to Microsoft Technologies.

Month List

RecentComments

Comment RSS

Linq DistinctBy

clock April 5, 2012 11:54 by author Brian Keating |

 

Here is an extension method that I just had to share, TBH I’ve forgotten what I robbed the initial idea from, it wasn’t mine, but it’s something I found that I use over and over.

The problem is I want to use the Distinct() extension method. However the objects I’m creating don’t override the default equality comparer, nor did I want to create a functor and supply to the overload just for this scenario.

Lets have a look of what I’m dealing with.

public class Source
{
        
    public string Code { get; set; }    
    public string Name { get; set; }        
}

Here’s what one would initially try

// Remove any duplicates
 c.DependingOnSources = c.DependingOnSources.Distinct();

The problem here is that I don’t use the overload that allows me to specify an equality comparer, and the class itself doesn’t have the default equality comparer.

So what’s the solution?

var set = new HashSet<string>();
c.DependingOnSources = c.DependingOnSources.Where(element => set.Add(element.Name));

 

It’s a beauty it’s it, and quite simplistic, what I do is create a HashSet of the keys I want o compare, then I use use the Linq Where statement to select all the elements that I can add to the list. If you’re familiar with HashSet you’ll know that for first time we try add an element it will be not exist in the set and it gets added to the set and returns true, because the set.Add returns true.. we satisfy the Func in the Where clause and it gets added to the items that get returned.

 

Simple ey.. yes true, but it gets better, we can make this a little more generic and leverage an extension method to do the lifting for us.

 

internal static class LinqExtensions
{
    public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
                        this IEnumerable<TSource> source, Func<TSource, TKey> selector)
    {
        var set = new HashSet<TKey>();
        return source.Where(element => set.Add(selector(element)));
    }
}

 

So now we can call our method like so

// Remove any duplicates
c.DependingOnSources = c.DependingOnSources.DistinctBy(k => k.Name);
 
Neat ey! (another common method is to use GroupBy and Select.)



Linq to Xlsx

clock April 27, 2010 08:02 by author Brian Keating |

A sample how to read a Excel 2007/2010 using Open XML SDK V2

(forgive the bad syntax highlighting)

 

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Packaging;

namespace ConsoleApplicationLinqToXlsx
{
    class Program
    {
        static void Main(string[] args)
        {
            //Declare variables to hold refernces to Excel objects.
            Workbook workBook;
            SharedStringTable sharedStrings;
            IEnumerable<Sheet> workSheets;
            WorksheetPart custSheet;
            WorksheetPart orderSheet;

            //Declare helper variables.
            string custID;
            string orderID;
            List<Customer> customers;
            List<Order> orders;

            //Open the Excel workbook.
            using (SpreadsheetDocument document =
              SpreadsheetDocument.Open(@"d:\Temp\ConsoleApplicationLinqToXlsx\TestOpenXMl.xlsx ", true))
            {
                //References to the workbook and Shared String Table.
                workBook = document.WorkbookPart.Workbook;
                workSheets = workBook.Descendants<Sheet>();
                sharedStrings =
                  document.WorkbookPart.SharedStringTablePart.SharedStringTable;

                //Reference to Excel Worksheet with Customer data.
                custID =
                  workSheets.First(s => s.Name == @"Customer").Id;
                custSheet =
                  (WorksheetPart)document.WorkbookPart.GetPartById(custID);

                //Load customer data to business object.
                customers =
                  Customer.LoadCustomers(custSheet.Worksheet, sharedStrings);

                //Reference to Excel worksheet with order data.
                orderID =
                  workSheets.First(sheet => sheet.Name == @"Order").Id;
                orderSheet =
                  (WorksheetPart)document.WorkbookPart.GetPartById(orderID);

                //Load order data to business object.
                orders =
                  Order.LoadOrders(orderSheet.Worksheet, sharedStrings);

                //List all customers to the console.
                //Write header information to the console.
                Console.WriteLine("All Customers");
                Console.WriteLine("{0, -15} {1, -15} {2, -5}",
                  "Customer", "City", "State");

                //LINQ Query for all customers.
                IEnumerable<Customer> allCustomers =
                    from customer in customers
                    select customer;

                //Execute query and write customer information to the console.
                foreach (Customer c in allCustomers)
                {
                    Console.WriteLine("{0, -15} {1, -15} {2, -5}",
                      c.Name, c.City, c.State);
                }
                Console.WriteLine();
                Console.WriteLine();


                //Write all orders over $100 to the console.
                //Write header information to the console.
                Console.WriteLine("All Orders over $100");
                Console.WriteLine("{0, -15} {1, -10} {2, 10} {3, -5}",
                  "Customer", "Date", "Amount", "Status");

                //LINQ Query for all orders over $100.
                //Join used to display customer information for the order.
                var highOrders =
                  from customer in customers
                  join order in orders on customer.Name equals order.Customer
                  where order.Amount > 100.00
                  select new
                  {
                      customer.Name,
                      order.Date,
                      order.Amount,
                      order.Status
                  };

                //Execute query and write information to the console.
                foreach (var result in highOrders)
                {
                    Console.WriteLine("{0, -15} {1, -10} {2, 10} {3, -5}",
                      result.Name, result.Date.ToShortDateString(),
                      result.Amount, result.Status);
                }
                Console.WriteLine();
                Console.WriteLine();


                //Report on customer orders by status.
                //Write header information to  the console.
                Console.WriteLine("Customer Orders by Status");

                //LINQ Query for summarizing customer order information by status.
                //There are two LINQ queries. 
                //Internal query is used to group orders together by status and
                //calculates the total order amount and number of orders.
                //External query is used to join Customer information.
                var sumoforders =
                  from customer in customers
                  select new
                  {
                      customer.Name,
                      statusTotals =
                          from order in orders
                          where order.Customer == customer.Name
                          group order.Amount by order.Status into statusGroup
                          select new
                          {
                              status = statusGroup.Key,
                              orderAmount = statusGroup.Sum(),
                              orderCount = statusGroup.Count()
                          }
                  };

                //Execute query and write information to the console.
                foreach (var customer in sumoforders)
                {
                    //Write Customer name to the console.
                    Console.WriteLine("-{0}-", customer.Name);
                    foreach (var x in customer.statusTotals)
                    {
                        Console.WriteLine("  {0, -10}: {2,2} orders totaling {1, 7}",
                          x.status, x.orderAmount, x.orderCount);
                    }
                    Console.WriteLine();
                }

                //Keep the console window open.
                Console.Read();
            }
        }

        /// <summary>
        /// Used to store customer information for analysis.
        /// </summary>
        public class Customer
        {
            //Properties.
            public string Name { get; set; }
            public string City { get; set; }
            public string State { get; set; }

            /// <summary>
            /// Helper method for creating a list of customers
            /// from an Excel worksheet.
            /// </summary>
            public static List<Customer> LoadCustomers(Worksheet worksheet,
              SharedStringTable sharedString)
            {
                //Initialize the customer list.
                List<Customer> result = new List<Customer>();

                //LINQ query to skip first row with column names.
                IEnumerable<Row> dataRows =
                  from row in worksheet.Descendants<Row>()
                  where row.RowIndex > 1
                  select row;

                foreach (Row row in dataRows)
                {
                    //LINQ query to return the row's cell values.
                    //Where clause filters out any cells that do not contain a value.
                    //Select returns the value of a cell unless the cell contains
                    //  a Shared String.
                    //If the cell contains a Shared String, its value will be a
                    //  reference id which will be used to look up the value in the
                    //  Shared String table.
                    IEnumerable<String> textValues =
                      from cell in row.Descendants<Cell>()
                      where cell.CellValue != null
                      select
                        (cell.DataType != null
                          && cell.DataType.HasValue
                          && cell.DataType == CellValues.SharedString
                        ? sharedString.ChildElements[
                          int.Parse(cell.CellValue.InnerText)].InnerText
                        : cell.CellValue.InnerText)
                      ;

                    //Check to verify the row contained data.
                    if (textValues.Count() > 0)
                    {
                        //Create a customer and add it to the list.
                        var textArray = textValues.ToArray();
                        Customer customer = new Customer();
                        customer.Name = textArray[0];
                        customer.City = textArray[1];
                        customer.State = textArray[2];
                        result.Add(customer);
                    }
                    else
                    {
                        //If no cells, then you have reached the end of the table.
                        break;
                    }
                }

                //Return populated list of customers.
                return result;
            }
        }

        /// <summary>
        /// Used to store order information for analysis.
        /// </summary>
        public class Order
        {
            //Properties.
            public string Number { get; set; }
            public DateTime Date { get; set; }
            public string Customer { get; set; }
            public Double Amount { get; set; }
            public string Status { get; set; }

            /// <summary>
            /// Helper method for creating a list of orders
            /// from an Excel worksheet.
            /// </summary>
            public static List<Order> LoadOrders(Worksheet worksheet,
              SharedStringTable sharedString)
            {
                //Initialize order list.
                List<Order> result = new List<Order>();

                //LINQ query to skip first row with column names.
                IEnumerable<Row> dataRows =
                  from row in worksheet.Descendants<Row>()
                  where row.RowIndex > 1
                  select row;

                foreach (Row row in dataRows)
                {
                    //LINQ query to return the row's cell values.
                    //Where clause filters out any cells that do not contain a value.
                    //Select returns cell's value unless the cell contains
                    //  a shared string.
                    //If the cell contains a shared string its value will be a
                    //  reference id which will be used to look up the value in the
                    //  shared string table.
                    IEnumerable<String> textValues =
                      from cell in row.Descendants<Cell>()
                      where cell.CellValue != null
                      select
                        (cell.DataType != null
                          && cell.DataType.HasValue
                          && cell.DataType == CellValues.SharedString
                        ? sharedString.ChildElements[
                          int.Parse(cell.CellValue.InnerText)].InnerText
                        : cell.CellValue.InnerText)
                      ;

                    //Check to verify the row contains data.
                    if (textValues.Count() > 0)
                    {
                        //Create an Order and add it to the list.
                        var textArray = textValues.ToArray();
                        Order order = new Order();
                        order.Number = textArray[0];
                        order.Date = new DateTime(1900, 1, 1).AddDays(
                          Double.Parse(textArray[1]) - 2);
                        order.Customer = textArray[2];
                        order.Amount = Double.Parse(textArray[3]);
                        order.Status = textArray[4];
                        result.Add(order);
                    }
                    else
                    {
                        //If no cells, then you have reached the end of the table.
                        break;
                    }
                }

                //Return populated list of orders.
                return result;
            }
        }

    }
}




LINQPad

clock April 16, 2010 20:14 by author Brian Keating |

If you've not used nor know what LINQPad is...... tut tut tut

Download it form here

http://www.linqpad.net/  it will make your life easier, infact you'll wonder whatever you did without it...

So how does it help...? try it and see :-)




Linq to SQL

clock February 3, 2010 07:20 by author Brian Keating |

Requirment:

Nothwind Sql Database

Advantages of Linq to SQL

While everything with Linq to Sql ca be done with Ado.Net, there are a few advantages

  • Less code: you don't need to write ADO.NET code for querying the database. You can use a tool to generate the data classes you need.
  • Flexible querying capabilities: Rather than struggle with SQL, you can use the LINQ querying model. Ultimately, you'llbe able to use one consistent model (LINQ expressions) to access many different types of data, from databases to XML.
  • Change tracking and batch updates: This is the most important one for me, (because I already have ado.net tools and i don't mindwriting sql) You can change multiple details about the data yo've queried and commit a batch update. 

Add a new linq to sql item to your project 

 

 

 Sample usage

 

class Program
{
    static void Main(string[] args)
    {
        Program prog = new Program();
        prog.ListAllOrderProducts();
        prog.ListAllOrderProductsForCustomer();
        Console.ReadLine();
    }


    private void ListAllOrderProducts()
    {
        CustomerOrdersDataContext dc = new CustomerOrdersDataContext();
        Table<Order> table = dc.GetTable<Order>();
        foreach (var order in table)
        {
            Console.WriteLine(order.Order_Details[0].Product.ProductName);
        }           
    }

    private void ListAllOrderProductsForCustomer(string custId = "ALFKI")
    {
        CustomerOrdersDataContext dc = new CustomerOrdersDataContext();
        var result =
            from order in dc.GetTable<Order>()
            where order.CustomerID == custId
            select order;
                   
        foreach (var x in result)
        {
            Console.WriteLine(x.Order_Details[0].Product.ProductName);
        }
    }
}




Inline XML Linq manipulation sample

clock November 4, 2009 20:37 by author Brian Keating |

A quick example of inline xml and Linq

 

Code

void LinqToXmlSample()
{
  Console.WriteLine("{0} : Start", new StackTrace(0, true).GetFrame(0).GetMethod().Name);

  XDocument xDocument = new XDocument(
    new XElement("people",
      new XElement("person",
        new XAttribute("sex", "male"),
        new XElement("FirstName", "Brian"),
        new XElement("LastName", "Keating")),
      new XElement("person",
        new XAttribute("type", "female"),
        new XElement("FirstName", "Dustin"),
        new XElement("LastName", "Turkey"))));

  IEnumerable<XElement> elements =
    xDocument.Element("people").Descendants("FirstName");

  /*  First, I will display the source elements.*/
  foreach (XElement element in elements)
  {
    Console.WriteLine("Source element: {0} : value = {1}",
      element.Name, element.Value);
  }

  /*  Now, I will display the ancestor elements for each source element.*/
  foreach (XElement element in elements.Ancestors())
  {
    Console.WriteLine("Ancestor element: {0}", element.Name);
  }

  Console.WriteLine("{0} : Finish", new StackTrace(0, true).GetFrame(0).GetMethod().Name);
}

 

Output

LinqToXmlSample : Start
Source element: FirstName : value = Brian
Source element: FirstName : value = Dustin
Ancestor element: person
Ancestor element: people
Ancestor element: person
Ancestor element: people
LinqToXmlSample : Finish