views:

285

answers:

5

I'm trying to work with the .NET AJAX autocompletion extension. The extension is expecting the following...

public static string[] GetCompletionList(string prefixText, int count, string contextKey)

My database queries are in a LINQ var object. I'm getting compile-time errors about not being able to convert type IQueryable to string[].

InventoryDataContext assets = new InventoryDataContext();
    var assetsInStorage = from a in assets.Assets
                          where a.Name.Contains(prefixText)
                          orderby a.Name ascending
                          select new[] { a.Manufacturer.Name, a.Name };
    return (string[])assetsInStorage;
A: 

Try:

return assetsInStorage.ToArray();
Michael Gattuso
This doesn't address the issue that the Enumerable<T> is not of a string but an anonymous type holding an array of two strings
John Weldon
Oops. I was viewing this on my iPhone and it truncated the line and I didn't see the second parameter being passed in there ... that'll teach me!
Michael Gattuso
@John - Actually, the OP's code is not creating an anonymous type holding an array of two strings - it's just an array of two strings. So the output is `IEnumerable<string[]>`.
Joel Mueller
+1  A: 

Your assetsInStorage doesn't appear to be an IEnumerable<string>... as such, you'd have to project your anonymous type into a string.

assetsInStorage.Select(a=>a[0] + a[1])

(Or however you want to convert that anonymouns type to a string.)

And then you can return .ToArray():

return assetsInStorage.Select(a=>a[0]+a[1]).ToArray();
John Weldon
It is an `IEnumerable<T>` since `IQueryable<T>` inherits from `IEnumerable<T>`.
Andrew Hare
Yes but T is not a string but an anonymous type
John Weldon
T is not an anonymous type but a string array.
Joel Mueller
+6  A: 

In order to get an string[] at first you must select only one string property on your query, not an anonymous object:

var assetsInStorage = from a in assets.Assets
                      where a.Name.Contains(prefixText)
                      orderby a.Name ascending
                      select a.Manufacturer.Name; // or a.Name

assetsInStorage at this moment is an IEnumerable<string>, and then you should convert it to string[] by:

return assetsInStorage.ToArray();
CMS
Better wording... thanks CMS :)
John Weldon
Yes, I confirm this works. Is it possible to concat two fields in the select statement though?
Bay Wolf
yes... the selection just has to return a string.
John Weldon
**@John:** Thank you!, **Bay:** just concatenate them in the select: `select a.Name + " " + a.Manufacturer.Name;`
CMS
Ugh... so simple. Thanks again CMS, et al
Bay Wolf
+1  A: 

This should do the trick:

InventoryDataContext assets = new InventoryDataContext();
var assetsInStorage = from a in assets.Assets                          
   where a.Name.Contains(prefixText)
   orderby a.Name ascending
   select String.Concat(x.ManufacturerName, " ", x.Name);    

return assetsInStorage.ToArray();

EDITED based on comment... EF is able to interpret String.Concat(), so the additional enumeration wasn't necessary.

mkedobbs
The ToList() not necessary, no matter which of those frameworks you're using. The ToArray() call at the end will cause the result set to be enumerated before the underlying connection is closed anyway - there's no point to forcing enumeration twice.
Joel Mueller
+1  A: 

If you want a single array that contains both a.Manufacturer.Name and a.Name for each of the assets, you can do that with a slight modification of CMS's answer:

var assetsInStorage = from a in assets.Assets
                      where a.Name.Contains(prefixText)
                      orderby a.Name ascending
                      select new[] { a.Manufacturer.Name, a.Name };

At this point, assetsInStorage is an IEnumerable<string[]> which also counts as an IEnumerable<IEnumerable<string>>. We can flatten this down to a single IEnumerable<string> using SelectMany and then turn it into an array.

return assetsInStorage.SelectMany(a => a).ToArray();

In this way, you're not required to select only a single string value.

Joel Mueller