Hooked on LINQ

Hooked on LINQ - Developers' Wiki
for .NET Language Integrated Query

Companion book for this site
LINQ to Objects Using C# 4.0:
Using and Extending LINQ to Objects and Parallel LINQ (PLINQ)
Quick Search

Advanced Search »

Update Operator

Modified: 2007/01/21 02:06 by t_magennis - Categorized as: LINQ to Objects, Samples
Update is an extension method that allows you to update properties on objects that are the result of a query. Whilst the standard query operators support retrieving data objects from a collection, the standard update SQL type clause is missing. A consistent pattern of querying data, then foreach'ing over that data is replicated many, many times when using LINQ to Objects. The Update extension method aims to remove the need for as many foreach loops by allowing you to achieve property assignments on the resulting objects of a query within the one query statement block.

My original vision was to create an extension method that allows this type of query syntax:

int count = (from d in drawingObjects
             where d.IsSelected && d.Color == Colors.Blue
             select d)
             .Update(do => { do.Color = Color.Red; do.Selected = false; } );

or using Extension Method syntax:

int count = drawingObjects
            .Where(d => d.IsSelected && d.Color == Colors.Blue)
            .Update(do => { do.Color = Color.Red; do.Selected = false; } );

The Update extension method simply iterates an IEnumerable<T> source and calls a void return type delegate statement block. The Lambda Expression syntax allows you to pass in multiple statements enclosed in curly-braces (you can drop them if there is only one assignment being made), although the May 2006 LINQ CTP editor support will show syntax errors, you can still compile. The January Orcas CTP does not suffer this editor syntax issue, and it works perfectly.

Email me comments, suggestions and feedback. See my contact details here.

January CTP Code and Unit Tests

// Copyright (C) 2007 Troy Magennis. All Rights Reserved. // You are free to use this material, however you do so AT YOUR OWN risk. // You are prohibited from removing this disclaimer or copyright notice from any derivitive works. // Remember to visit http://www.hookedonlinq.com - The LINQ wiki community project.

using System; using System.Collections.Generic;

namespace Aspiring.Linq {

public static class UpdateExtensions {

public delegate void Func(TArg0 element);

/// /// Executes an Update statement block on all elements in an IEnumerable sequence. /// /// The source element type. /// The source sequence. /// The update statement to execute for each element. /// The numer of records affected. public static int Update(this IEnumerable source, Func update) { if (source == null) throw new ArgumentNullException("source"); if (update == null) throw new ArgumentNullException("update"); if (typeof(TSource).IsValueType) throw new NotSupportedException("value type elements are not supported by update.");

int count = 0; foreach (TSource element in source) { update(element); count++; } return count; } } }

// Copyright (C) 2007 Troy Magennis. All Rights Reserved. // You are free to use this material, however you do so AT YOUR OWN risk. // You are prohibited from removing this disclaimer or copyright notice from any derivitive works. // Remember to visit http://www.hookedonlinq.com - The LINQ wiki community project.

using System; using System.Collections.Generic; using System.Text; using System.Linq; using NUnit.Framework; using Aspiring.Linq;

namespace Aspiring.Linq.UnitTests { TestFixture public class UpdateTests {

public class TestClass { public int I; public string S; public bool B = false; }

Test ExpectedException("System.ArgumentNullException") public void UpdateNullSourceTest() { List values = null; values.Update(u => u.I = 1); }

Test ExpectedException("System.ArgumentNullException") public void UpdateNullUpdateTest() { List values = new List(); values.Update(null); }

Test ExpectedException("System.NotSupportedException") public void UpdateValueTypeElementTest() { List values = new List(); values.Update(u => u = 1); }

Test public void UpdateClassBasicTest() { List values = new List { new TestClass { I = 1, S = "one" }, new TestClass { I = 2, S = "two" }, new TestClass { I = 3, S = "three" }, new TestClass { I = 4, S = "four" }, new TestClass { I = 5, S = "five" } }; // no matching elements to change int count0 = (from t in values where t.I > 100 select t).Update(tc => { tc.S = tc.I.ToString(); tc.B = true; } ); Assert.AreEqual(0, count0, "Incorrect count returned"); // 3 matching elements to change int count = (from t in values where t.I < 4 select t).Update(tc => { tc.S = tc.I.ToString(); tc.B = true; } );

// or, using extension method syntax //int count = values.Where(t => t.I < 4) // .Update(tc => { tc.S = tc.I.ToString(); tc.B = true; } ); Assert.AreEqual(3, count, "Incorrect count returned"); Assert.AreEqual("1", values0.S); Assert.AreEqual("2", values1.S); Assert.AreEqual("3", values2.S); Assert.AreEqual("four", values3.S); Assert.AreEqual("five", values4.S);

Assert.AreEqual(true, values0.B); Assert.AreEqual(true, values1.B); Assert.AreEqual(true, values2.B); Assert.AreEqual(false, values3.B); Assert.AreEqual(false, values4.B); } } }

May 2006 CTP Code and Unit Tests

// Copyright (C) 2007 Troy Magennis. All Rights Reserved. // You are free to use this material, however you do so AT YOUR OWN risk. // You are prohibited from removing this disclaimer or copyright notice from any derivitive works. // Remember to visit http://www.hookedonlinq.com - The LINQ wiki community project.

using System; using System.Collections.Generic;

namespace Aspiring.Query {

public static class UpdateExtensions {

public delegate void Func(TArg0 element); /// /// Executes an Update statement block on all elements in an IEnumerable sequence. /// /// The source element type. /// The source sequence. /// The update statement to execute for each element. /// The numer of records affected. public static int Update(this IEnumerable source, Func update) { if (source == null) throw new ArgumentNullException("source"); if (update == null) throw new ArgumentNullException("update"); if (typeof(TSource).IsValueType) throw new NotSupportedException("value type elements are not supported by update.");

int count = 0; foreach(TSource element in source) { update(element); count++; } return count; } } }

using System; using System.Collections.Generic; using System.Text; using System.Query; using NUnit.Framework; using Aspiring.Query;

namespace Aspiring.Query.UnitTests { TestFixture public class UpdateTests {

public class TestClass { public int I; public string S; public bool B = false; }

Test ExpectedException("System.ArgumentNullException") public void UpdateNullSourceTest() { List values = null; values.Update(u => u.I = 1); }

Test ExpectedException("System.ArgumentNullException") public void UpdateNullUpdateTest() { List values = new List(); values.Update(null); }

Test ExpectedException("System.NotSupportedException") public void UpdateValueTypeElementTest() { List values = new List(); values.Update(u => u = 1); }

Test public void UpdateClassBasicTest() { List values = new List { new TestClass { I = 1, S = "one" }, new TestClass { I = 2, S = "two" }, new TestClass { I = 3, S = "three" }, new TestClass { I = 4, S = "four" }, new TestClass { I = 5, S = "five" } }; // no matching elements to change int count0 = (from t in values where t.I > 100 select t).Update(tc => { tc.S = tc.I.ToString(); tc.B = true; } ); Assert.AreEqual(0, count0, "Incorrect count returned"); // 3 matching elements to change int count = (from t in values where t.I < 4 select t).Update(tc => { tc.S = tc.I.ToString(); tc.B = true; } );

// or, using extension method syntax //int count = values.Where(t => t.I < 4) // .Update(tc => { tc.S = tc.I.ToString(); tc.B = true; } ); Assert.AreEqual(3, count, "Incorrect count returned"); Assert.AreEqual("1", values0.S); Assert.AreEqual("2", values1.S); Assert.AreEqual("3", values2.S); Assert.AreEqual("four", values3.S); Assert.AreEqual("five", values4.S);

Assert.AreEqual(true, values0.B); Assert.AreEqual(true, values1.B); Assert.AreEqual(true, values2.B); Assert.AreEqual(false, values3.B); Assert.AreEqual(false, values4.B);a } } }

If you would like to comment on this page, click on the Discuss button located on the top-right of each page. Feel free to edit any mistakes or omissions you find. If you have an objection or find in-appropriate content then contact the administrator. This website is not affiliated with Microsoft®, all content and opinions are those of the specific author and some advice, solutions and article may contain unintentional errors - please use care. Other websites by this author: Focused Objective, Geek Speak Decoded.