segunda-feira, 26 de maio de 2008

Linq to Objects - Querying in-memory collections

Clique aqui para ver a versão em português deste post

Hello everyone. This post's issue continues about the Linq technology, but this we'll see a specific segment: Linq to Objects.

Before we begin, I want to recommend the book about Linq that I'm reading now: Linq in Action, from the authors Fabrice Marguerie, Steve Eichert, Jim Wooley, published by Manning. It's indeed a great book and will cover not only Linq, but C# features and best practices as well.

Let's get back to Linq to Objects. This technology allows us to query in-memory data collections. Instances of type array, List and others that implement the IEnumerable interface can be used with Linq to Objects. You only need to add a using entry to the namespace System.Linq.

Linq to Objects is particularly useful when we need to query, filter and/or order an in-memory data collection. These tasks when done without Linq (traditional ways) require quite a lot of code that uses loops and temporary variables. Another advantage on using Linq is that the code is easier to read, maintain and debug, as the code clearly shows what we'll get as result. Look at the example:

string[] Months = {"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"};

var MonthsWithJ =
from mon in Months
where mon.StartsWith("J")
orderby mon descending
select mon;

foreach (var m in MonthsWithJ) {
Console.WriteLine(m);
}


The result will be:

June
July
January


How would we produce the same result without Linq? If you want to have some fun and practice some algorithms, suit yourself :)

Now, let's say if, instead of an array of strings we could query an Object list? Yeah, it's possible:

class Program {

class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
}

static void Main(string[] args) {

var Felipe = new Person { FirstName = "Felipe", LastName = "Guerço" };
var Gerson = new Person { FirstName = "Gerson", LastName = "Motta" };

var People = new List<Person> {Gerson, Felipe};

var qry =
from person in People
orderby person.FirstName
select person;

foreach (var p in qry) {
Console.WriteLine("{0} {1}", p.FirstName, p.LastName);
}
}
}


Now we'll take a little break on Linq to show some of the new C# features for those that doesn't know them yet. First, auto properties:

public string FirstName { get; set; }


This implementation creates the property and, behind the scenes create the encapsulated field to store the property value. Very usefil for those properties that are read and written directly in the fields and don't need any specific validation logic behind them. But, at same time, provide structure to future changes, as the get and set are already there.

Next, type inference

var Felipe = new Person { FirstName = "Felipe", LastName = "Guerço" };


In early versions we had to define the variable type before initialize it. With this new feature the compiler infers the type in the first value assignment. Make no mistake: the type definition is still strong (not variant); we just don't need to explicitly inform the type because the compiler knows it from the assignment. To define a variable without initialize we do need to inform the type.

At last, a special constructor:

var Felipe = new Person { FirstName = "Felipe", LastName = "Guerço" };


This constructor allows us to create an instance of a class setting the properties rigth away.

Now Let's get back to Linq. Here we'll query all people on the list sorting by FirstName. If we wanted, we could add a search criteria by Name adding a where clause:

where person.FirstName.Contains("xxx")


Cool, isn't it? But there's more! We can query related data in more complex collections:


class Program {

class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
}

class Pet {
public string Name { get; set; }
public Person Owner { get; set; }
}

static void Main(string[] args) {

var Felipe = new Person { FirstName = "Felipe", LastName = "Guerço" };
var Gerson = new Person { FirstName = "Gerson", LastName = "Motta" };

var Meg = new Pet { Name = "Meg", Owner = Felipe };
var Rex = new Pet { Name = "Rex", Owner = Gerson };
var Max = new Pet { Name = "Max", Owner = Gerson };
var Nina = new Pet { Name = "Nina", Owner = Felipe };

var Pets = new List<Pet> { Meg, Rex, Max, Nina };

var qry =
from pet in Pets
orderby pet.Owner.FirstName
select new {
OwnerName = pet.Owner.FirstName + ' ' + pet.Owner.LastName,
PetName = pet.Name
};

foreach (var p in qry) {
Console.WriteLine("{0} {1}", p.OwnerName, p.PetName);
}

}
}


Now let's see another new interesting feature: Anonymous types.

select new {
OwnerName = pet.Owner.FirstName + ' ' + pet.Owner.LastName,
PetName = pet.Name
};


Here we define a new type (anonymous because it's defined at same time that we set the properties). Now we have an object with properties named OwnerName and PetName. The compiler automatically infers the properties' types according with their initialization.

Now we're goind to do an aggregation. We'll show the owner and how many pets they have:

var qry2 =
from pet in Pets
group pet by pet.Owner.FirstName + ' ' + pet.Owner.LastName into ownerPets
select new {
Name = ownerPets.Key,
Pets = ownerPets.Count()
};

foreach (var p in qry2) {
Console.WriteLine("{0}'s Pets: {1}", p.Name, p.Pets);
}


Now we created a group in the query counting pets with a key being the Owner's name. In this group we have a property named Key, which represents the information we're grouping. Then we project the group key and the group count in the resultset.

Before we finish, let me point out something: We can use these query results as data sources for data-aware controls, such as GridViews on WinForms or WebForms.

Well, it ended up more lengthy than I expected, but i think that it could show some of the power and usefulness of Linq to Objects technique. Thank you all for the support and see you at the next post. Take care!

Nenhum comentário:

Postar um comentário

 
BlogBlogs.Com.Br