Showing posts with label LINQ 2 SQL. Show all posts
Showing posts with label LINQ 2 SQL. Show all posts

Friday, 23 July 2010

LINQ to Objects - Performing a wildcard (LIKE in SQL) match between 2 different lists (aka Converting For Loops to LINQ queries or a Cool Feature of Resharper)

We'll start with an example. How would I get a list of any items in the "letterList" List below that matches (ie Contains) any of the numbers in the "numbersList" List below?

var letterList = new List<string>() { "A1", "A2", "A3", "A4", "B1", "B2", "B3", "B4", "C1", "C2", "C3", "C4"};

var numberList = new List<string>() { "1", "2", "3" }; 

We could do this in a looping fashion, or we could use LINQ to perform the query in a more declarative fashion.

For loop solution:
[TestMethod]
public void TestForEach()
{
    //We want all items in the letterList that wildcard 
    //match numbers in the numberList. The output for this example should
    //not include any items in the letterlist with "4" as it is not in the 
    var letterList = new List<string>() { "A1", "A2", "A3", "A4", 
        "B1", "B2", "B3", "B4", "C1", "C2", "C3", "C4"};
    var numberList = new List<string>() { "1", "2", "3" };
    var outputList = new List<string>();

    foreach (var letter in letterList)
    {
        foreach (var number in numberList)

            if (letter.Contains(number))
            {
                outputList.Add(letter);
            }
    }
}

How would we do this in LINQ?
One of the problems is that the LINQ Contains method only matches one value at a time (not Numbers 1,2,3 at the same time). We also can't use a normal LINQ equijoin as the LINQ join syntax doesn't support wildcard matches.

The answer is to do the below:
[TestMethod]
public void TestForEachLINQ()
{
    //We want all items in the letterList that wildcard 
    //match numbers in the numberList. The output for this example should
    //not include any items in the letterlist with "4" as it is not in the 
    var letterList = new List<string>() { "A1", "A2", "A3", "A4", 
        "B1", "B2", "B3", "B4", "C1", "C2", "C3", "C4"};
    var numberList = new List<string>() { "1", "2", "3" };
    var outputList = (
        from letter in letterList 
        from number in numberList 
        where letter.Contains(number) select letter).ToList();
}

This effectively does a wildcard match between 2 different lists. When you look at it, it really is very similar to a SQL Server wildcard join - but just using a WHERE statement.

The simplest wayway to make a conversion like this is to use one of the new features of Resharper 5 - the "Convert Part of body into LINQ-expression" refactoring functionality. This will automatically convert the for each syntax to the declarative LINQ syntax. EASY!


DDK

Tuesday, 20 April 2010

Finding Duplicates in a list using LINQ Lambda Expressions

Here is a one-liner that allows you to get a list of the duplicates in a list. I originally tried to approach the problem using the LINQ Group By syntax (like what I did here in 2008), but I found this to be a much simpler solution.

This works by utilizing the .Except extension method that compares with a blank list. Because ALL items don't match what is in the blank list, then all elements are passed to the subsequent .Any statement which picks up any item in which all fields specified in the lambda expression match.

Here's the code for listing duplicates in LINQ, comparing against multiple columns:

var duplicates =
timesheetDto.TimesheetItems.Where(timesheetItem =>
timesheetDto.TimesheetItems
.Except(new List { timesheetItem })
.Any(matchingTimesheetItem => 
timesheetItem.ActivityType  == matchingTimesheetItem.ActivityType &&
timesheetItem.ReceivingWBSElement == matchingTimesheetItem.ReceivingWBSElement &&
timesheetItem.ReceivingCostCentre == matchingTimesheetItem.ReceivingCostCentre &&
timesheetItem.SendingCostCentre == matchingTimesheetItem.SendingCostCentre
)
).ToList(); 

return duplicates.Count > 0;

Friday, 3 April 2009

LinqDatasource not updating when Update Button is clicked in ASP.NET ListView

If you are using a LINQDatasource (or any ASP.NET datasource controls with 2 way databinding) and some of your fields are not updating, then one of the first things you should check is that you are not using Eval, rather than Bind() on your templated fields.

Today, one of my colleagues had issues with both inserting and updating records using a ListView and a LINQ datasource. After a little bit of DK (Divide and Konquer), I eventually found something he had (painfully) overlooked - the Item Template values used Eval (which is fine). However, he had updated the Item template and copied it over to the Edit Item templates and Insert Item templates to save time.

Obviously, Evals are readonly - so the values were never passed into the update of the LINQ datasource.

Tuesday, 31 March 2009

Rendering Different Colors for each row in an ASP.NET Gridview

This is simple as handling the MyGridViewName_RowDataBound event. The following code sample is used in the following scenario:
  1. The grid is bound to a LINQDataSource (the e.Row.DataItem has a type of "DynamicClass" and so cannot be cast directly)
  2. Consequently uses reflection to get a nested property inside the e.Row.DataItem, then casts that to a known LINQ2SQL class.
  3. From this reflected information, grabs the display colour HEX value (e.g. #CCFFCC and converts it to a System.Drawing.Color colour (by using System.Drawing.ColorTranslator).

protected void proposalListGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DoPBusiness.PlanningProposalTracking.PP_LIST_Status status =
(DoPBusiness.PlanningProposalTracking.PP_LIST_Status)
e.Row.DataItem.GetType()
.GetProperty("PP_LIST_Status")
.GetValue(e.Row.DataItem, null);

e.Row.BackColor = System.Drawing.ColorTranslator.FromHtml(status.DisplayColour);
}
}




NB. An alternative (and preferred) to using relection to get the nested property is using LINQ projection - which is how I did it when I checked the code into source. control. However, the code sample above still illustrates the topic of this post.