Best linq questions in October 2011

Combining arrays of strings together

12 votes

I'm looking to combine the contents of two string arrays, into a new list that has the contents of both joined together.

string[] days = { "Mon", "Tue", "Wed" };
string[] months = { "Jan", "Feb", "Mar" };

// I want the output to be a list with the contents
// "Mon Jan", "Mon Feb", "Mon Mar", "Tue Jan", "Tue Feb" etc...

How can I do it ? For when it's only two arrays, the following works and is easy enough:

List<string> CombineWords(string[] wordsOne, string[] wordsTwo)
{
    var combinedWords = new List<string>();
    foreach (var wordOne in wordsOne)
    {
        foreach (string wordTwo in wordsTwo)
        {
            combinedWords.Add(wordOne + " " + wordTwo);
        }
    }
    return combinedWords;
}

But I'd like to be able to pass varying numbers of arrays in (i.e. to have a method with the signature below) and have it still work.

List<string> CombineWords(params string[][] arraysOfWords)
{
    // what needs to go here ?
}

Or some other solution would be great. If it's possible to do this simply with Linq, even better!

Code below works for any number of arrays (and uses linq to some degree):

List<string> CombineWords(params string[][] wordsToCombine)
{
     if (wordsToCombine.Length == 0)
         return new List<string>();

     IEnumerable<string> combinedWords = wordsToCombine[0].ToList();
     for (int i = 1; i < wordsToCombine.Length; ++i)
     {
         var temp = i;
         combinedWords = (from x in combinedWords from y in wordsToCombine[temp]
                       select x + " " + y);
     }
     return combinedWords.ToList();
 }

How to convert an expression tree to a partial SQL query?

9 votes

When EF or LINQ to SQL runs a query, it:

  1. Builds an expression tree from the code,
  2. Converts the expression tree into an SQL query,
  3. Executes the query, gets the raw results from the database and converts them to the result to be used by the application.

Looking at the stack trace, I can't figure out where the second part happens.

In general, is it possible to use an existent part of EF or (preferably) LINQ to SQL to convert an Expression object to a partial SQL query (using Transact-SQL syntax), or I have to reinvent the wheel?


Update: a comment asks to provide an example of what I'm trying to do.

Actually, the answer by Ryan Wright below illustrates perfectly what I want to achieve as a result, except the fact that my question is specifically about how can I do it by using existent mechanisms of .NET Framework actually used by EF and LINQ to SQL, instead of having to reinvent the wheel and write thousands of lines of not-so-tested code myself to do the similar thing.

Here is also an example. Again, note that there is no ORM-generated code.

private class Product
{
    [DatabaseMapping("ProductId")]
    public int Id { get; set; }

    [DatabaseMapping("Price")]
    public int PriceInCents { get; set; }
}

private string Convert(Expression expression)
{
    // Some magic calls to .NET Framework code happen here.
    // [...]
}

private void TestConvert()
{
    Expression<Func<Product, int, int, bool>> inPriceRange =
        (Product product, int from, int to) =>
            product.PriceInCents >= from && product.PriceInCents <= to;

    string actualQueryPart = this.Convert(inPriceRange);

    Assert.AreEqual("[Price] between @from and @to", actualQueryPart);
}

Where does the name Price come from in the expected query?

The name can be obtained through reflection by querying the custom DatabaseMapping attribute of Price property of Product class.

Where do names @from and @to come from in the expected query?

Those names are the actual names of the parameters of the expression.

Where does between … and come from in the expected query?

This is a possible result of a binary expression. Maybe EF or LINQ to SQL would, instead of between … and statement, stick with [Price] >= @from and [Price] <= @to instead. It's ok too, it doesn't really matter since the result is logically the same (I'm not mentioning performance).

Why there is no where in the expected query?

Because nothing indicates in the Expression that there must be a where keyword. Maybe the actual expression is just one of the expressions which would be combined later with binary operators to build a larger query to prepend with a where.

The short answer seems to be that you cannot use a part of EF or LINQ to SQL as a shortcut to translation. You need at least a subclass of ObjectContext to get at the internal protected QueryProvider property, and that means all the overhead of creating the context, including all the metadata and so on.

Assuming you are ok with that, to get a partial SQL query, for example, just the WHERE clause you're basically going to need the query provider and call IQueryProvider.CreateQuery() just as LINQ does in its implementation of Queryable.Where. To get a more complete query you can use ObjectQuery.ToTraceString().

As to where this happens, LINQ provider basics states generally that

IQueryProvider returns a reference to IQueryable with the constructed expression-tree passed by the LINQ framework, which is used for further calls. In general terms, each query block is converted to a bunch of method calls. For each method call, there are some expressions involved. While creating our provider - in the method IQueryProvider.CreateQuery - we run through the expressions and fill up a filter object, which is used in the IQueryProvider.Execute method to run a query against the data store

and that

the query can be executed in two ways, either by implementing the GetEnumerator method (defined in the IEnumerable interface) in the Query class, (which inherits from IQueryable); or it can be executed by the LINQ runtime directly

Checking EF under the debugger it's the former.

If you don't want to completely re-invent the wheel and neither EF nor LINQ to SQL are options, perhaps this series of articles would help:

Here are some sources for creating a query provider that probably involve much more heavy lifting on your part to implement what you want:

Can't use Descendants() or Elements() with xmlns

6 votes

I'm new to working with XML, and I've encountered a weird problem while trying to get a specific tag from a spring.net configuration file. After trying to narrow down the problem with a test xml file, I found out that applying the following code:

List<XElement> nodes = xmlFile.Descendants("B").ToList();

provides a non-empty list with the following file:

<?xml version="1.0" encoding="utf-8" ?>
<A fakeAttribute="aaa">
  <B id="DbProvider"/>
</A>

but provides an empty string with the following file:

<?xml version="1.0" encoding="utf-8" ?>
<A xmlns="aaa">
  <B id="DbProvider"/>
</A>

The only difference between the files being the attribute.

I can't imagine an explanation for this. Thanks for your help.

You need to search for tags in that namespace:

XNamespace ns = "aaa";

xmlFile.Descendants(ns + "B").ToList()

How to detect if element exist using a lambda expression in c#?

5 votes

I've been using a try/catch statement to run through whether or not an element exists when I parse through it. Obviously this isn't the best way of doing it. I've been using LINQ (lambda expressions) for the majority of my parsing, but I just don't know how to detect if an element is there or not.

One big problem with some solutions I found is that they take 3-4 times more code than using the try/catch block, which kind of defeats the purpose.

I would assume the code would look something like this:

if(document.Element("myElement").Exists())
{
   var myValue = document.Element("myElement").Value;
}

I did find this link, but the looping is unecessary in my case as I can guarantee that it will only show up once if it exists. Plus the fact of having to create a dummy element which seems unecessary as well. Doesn't seem like it's the best way (or a good way) of checking. Any ideas?

XElement e = document.Element("myElement");
if (e != null)
{
    var myValue = e.Value; 
}

http://msdn.microsoft.com/en-us/library/system.xml.linq.xcontainer.element.aspx

"Gets the first (in document order) child element with the specified XName."

"Returns Nothing if there is no element with the specified name."

How to do datatemplate for items in listbox?

5 votes

I have an XML file (see below) and can display all the Product Names in a listbox. I want each entry in the listbox to display Product Name followed by Price, not just Product Name.

How do I do the datatemplate in the XAML file? Thanks.

Simplified XML file:

<Product> 
<Name>Red Chair</Name> 
<Price>29.5</Price>  
</Product>

Simplified XAML file:

<DockPanel>      
<ListBox Name="listBox1" ItemsSource="{Binding}" Margin="10" >      
</ListBox> 
</DockPanel> 

In my C# file, I use LINQ to collect the products from the XML file and assign var products to listBox1.DataContext and it works fine. Now I just want to add in the Price. Thanks.

You do this the same as any other ItemTemplate.

Make sure that you're binding to the Product, not the Name. You can then select the values from the XML using XPath, something like this.

<DockPanel>
  <ListBox Name="listBox1" 
           ItemsSource="{Binding}" 
           Margin="10" >       
    <ListBox.ItemTemplate>
      <DataTemplate>
        <StackPanel>
          <TextBlock Text={Binding XPath=./Name} />
          <TextBlock Text={Binding XPath=./Price} />
        </StackPanel>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>
</DockPanel>