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;
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();
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();
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.
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.
Try:
return assetsInStorage.ToArray();
Related
list1 contains userid and username
list2 contains userids
Need to display the list1 where its userid is included in list2.
string userids = "user1,user2,user3";
var list2 = userids.Split(',').Select(userid => userid.Trim()).ToList();
list1 = list1.Any(x => x.UserID)... //Got stuck here
Better use HashSet<T> for search:
string userids = "user1,user2,user3";
var userIdSet = new HashSet<string>(userids.Split(',').Select(userid => userid.Trim()));
list1 = list1.Where(x => userIdSet.Contains(x.UserID)).ToList();
Another way is Enumerable.Join which is more efficient if the lists are pretty large:
var containedUsers = from x1 in list1
join x2 in list2 on x1.UserId equals x2
select x1;
list1 = containedUsers.ToList();
I assume that the UserID's in list2 are unique(otherwise use Distinct). If not, joining them might cause duplcicate items in list1.
Its easy to get stuck on So you need to check list2 contains the item you picked.
found = list1.Where( x => list2.contains(x.UserID));
Method Any returns bool, it
Determines whether any element of a sequence satisfies a condition
Return Value
Type: System.Boolean
true if any elements in the source sequence pass the test in the specified predicate; otherwise, false.
Method Where
Filters a sequence of values based on a predicate.
So you can use Any inside Where to filter only results that contains inside list2.
list1 = list1.Where(l1 => list2.Any(l2 => l2 == l1.UserID)).ToList();
References: Enumerable.Any(Of TSource) Method, Enumerable.Where(Of TSource) Method
I know that I can cast my linq query to an array or list but this doesn't seem to help.
Here is my query:
var bracct = from DataRow x in _checkMasterFileNew.Rows
select new {BranchAccount = string.Format("{0}{1}", x["Branch"], x["AccountNumber"])};
When I attempt to convert it to a list or array:
List<string> tstx = bracct.ToList();
or this:
string[] stx = bracct.ToArray();
If give me this:
I am assuming I need to change my query but I'm not sure the best way to hanlde it. How do I get it to a generic collection of strings?
It won't work because you've created an anonymous type with 1 property which is a string. Instead, If all you want is to convert it into a List<string> do:
var bracct = (from DataRow x in _checkMasterFileNew.Rows
select string.Format("{0}{1}", x["Branch"], x["AccountNumber"])).ToList();
And if using c# 6.0 you can use string interpolation:
var bracct = (from DataRow x in _checkMasterFileNew.Rows
select $"{x["Branch"]}{x["AccountNumber"]}").ToList();
Your query is creating an anonymous type with a single member BranchAccount. If you actually just want a string, then just select that instead:
var bracct =
from DataRow x in _checkMasterFileNew.Rows
select string.Format("{0}{1}", x["Branch"], x["AccountNumber"]);
And now your ToList() call will return List<string>:
List<string> tstx = bracct.ToList();
You must select the property you are assigning the string to before performing ToList(), or remove the anonymous type and select string.Format() directly
Try this:
List<string> tstx = bracct.Select( x => x.BranchAccount ).ToList();
Suppose I have a collection of strings.
How do I select all the elements that don't contain a certain parameter value?
List<string> TheList = .....
var TheCleanList = (from s in TheList
where s != parameter
select s).ToList();
I was thinking about where s!= parameter but I'm wondering if there's a cleaner way to do it.
Thanks.
If you don't need a new list you don't need Linq for this - use Remove()- this avoids having to create a new list:
If you want to remove all strings that are equal to Parameter:
TheList.RemoveAll(s => s == Parameter);
If you want to remove all strings that contain Parameter (not clear from your question):
TheList.RemoveAll(s => s.Contains(Parameter));
You mean:
List<string> TheList = .....
var TheCleanList = (from s in TheList
where !s.Contains(parameter)
select s).ToList();
You can use String.Contains
var TheCleanList = (from s in TheList
where !s.Contains(parameter)
select s).ToList();
Or
var TheCleanList = TheList.Where(s => !s.Contains(parameter)).ToList();
String.Contains is case-sensitive. If you want a case-insensitve:
string lower = parameter.ToLower();
...
where s.ToLower().Contains(lower)
I'm wondering if its possible to join together IEnumerable's.
Basically I have a bunch of users and need to get their content from the database so I can search and page through it.
I'm using LINQ to SQL, my code at the moment it:
public IEnumerable<content> allcontent;
//Get users friends
IEnumerable<relationship> friends = from f in db.relationships
where f.userId == int.Parse(userId)
select f;
IEnumerable<relationship> freindData = friends.ToList();
foreach (relationship r in freindData)
{
IEnumerable<content> content = from c in db.contents
where c.userId == r.userId
orderby c.contentDate descending
select c;
// This is where I need to merge everything together
}
I hope that make some sense!
Matt
If I understand correctly what you are trying to do, why don't you try doing:
var result = from r in db.relationships
from c in db.contents
where r.userId == int.Parse(userId)
where c.userId == r.UserId
orderby c.contentDate descending
select new {
Relationship = r,
Content = c
}
This will give you an IEnumerable<T> where T is an anonymous type that has fields Relationship and Content.
If you know your users will have less than 2100 friends, you could send the keys from the data you already loaded back into the database easily:
List<int> friendIds = friendData
.Select(r => r.UserId)
.Distinct()
.ToList();
List<content> result = db.contents
.Where(c => friendIds.Contains(c.userId))
.ToList();
What happens here is that Linq translates each Id into a parameter and then builds an IN clause to do the filtering. 2100 is the maximum number of parameters that SQL server will accept... if you have more than 2100 friends, you'll have to break the ID list up and combine (Concat) the result lists.
Or, if you want a more literal answer to your question - Concat is a method that combines 2 IEnumerables together by creating a new IEnumerable which returns the items from the first and then the items from the second.
IEnumerable<content> results = Enumerable.Empty<content>();
foreach (relationship r in friendData)
{
IEnumerable<content> content = GetData(r);
results = results.Concat(content);
}
If you're doing an INNER join, look at the .Intersect() extension method.
Which things are you merging?
There are two main options you could use: .SelectMany(...) or .Concat(...)
I've got a LINQ query going against an Entity Framework object. Here's a summary of the query:
//a list of my allies
List<int> allianceMembers = new List<int>() { 1,5,10 };
//query for fleets in my area, including any allies (and mark them as such)
var fleets = from af in FleetSource
select new Fleet
{
fleetID = af.fleetID,
fleetName = af.fleetName,
isAllied = (allianceMembers.Contains(af.userID) ? true : false)
};
Basically, what I'm doing is getting a set of fleets. The allianceMembers list contains INTs of all users who are allied with me. I want to set isAllied = true if the fleet's owner is part of that list, and false otherwise.
When I do this, I am seeing an exception: "LINQ to Entities does not recognize the method 'Boolean Contains(Int32)' method"
I can understand getting this error if I had used the contains in the where portion of the query, but why would I get it in the select? By this point I would assume the query would have executed and returned the results. This little ditty of code does nothing to constrain my data at all.
Any tips on how else I can accomplish what I need to with setting the isAllied flag?
Thanks
This poached from a previous answer...
Contains not supported.
IN and JOIN are not the same operator (Filtering by IN never changes the cardinality of the query).
Instead of doing it that way use the join method. It's somewhat difficult to understand without using the query operators, but once you get it, you've got it.
var foo =
model.entitySet.Join( //Start the join
values, //Join to the list of strings
e => e.Name, // on entity.Name
value => value, //equal to the string
(ModelItem ent, String str) => ent);//select the entity
Here it is using the query operators
var foo = from e in model.entitySet
join val in values on
e.Name equals val
select e;
Basically the entity framework attempts to translate your LINQ query into a SQL statement but doesn't know how to handle the Contains.
What you can do instead is retrieve your fleets from the database and set the isAllied property later:
var fleets = (from af in FleetSource
select new Fleet
{
fleetID = af.fleetID,
fleetName = af.fleetName,
userId = af.userId
}).AsEnumerable();
foreach (var fleet in fleets)
{
fleet.isAllied = (allianceMembers.Contains(fleet.userID) ? true : false);
}
Everyone above me is wrong!!! (No offense ...) It doesn't work because you are using the IList overload of "Contains" and not the IEnumerable overload of "Contains". Simply change to:
allianceMembers.Contains<int>(af.userID)
By adding the <int>, you are telling the compiler to use the IEnumerable overload instead of the IList overload.
var fleets = from af in FleetSource;
var x = from u in fleets.ToList()
select new Fleet
{
fleetID = u.fleetID,
fleetName = u.fleetName,
isAllied = (allianceMembers.Contains(u.userID) ? true : false)
}
calling ToList() on fleets the query is executed, later you can use Contains().