i have a list of event Ids returned from an xml document as shown below
public IEnumerable<EventFeed> GetEventIdsByEventDate(DateTime eventDate)
{
return (from feed in xmlDoc.Descendants("Show")
from ev in feed.Elements("Event")
where Convert.ToDateTime(ev.Attribute("Date").Value).ToShortDateString() == eventDate.ToShortDateString()
select new EventFeed()
{
EventShowCode = feed.Attribute("Code").Value
}).ToList();
}
i now need to query my database to match events that equal the eventIds returned from the above method. so i would have something like:
select * from eventsdb where eventId in GetEventIdsByEventDate()
how can i do this using LINQ
i cant seem to get any of the answers working.
this is the method that looks up the eventIds from an XML feed
public IList<EventsDetails> GetEventIds(DateTime eventDate)
{
var eventids = (from feed in xmlDoc.Descendants("Show")
from ev in feed.Elements("Event")
where Convert.ToDateTime(ev.Attribute("Date").Value).ToShortDateString() == eventDate.ToShortDateString()
select new EventsDetails()
{
EventId = feed.Attribute("Code").Value
}).ToList();
return eventids;
}
this is the method that looks up the events in my database
public IEnumerable<EventFeed> GetAllEventsFromDatabase()
{
var allEvents = from eventsList in GetEventsList()
select new EventFeed()
{
EventName = eventsList.Title,
EventSummary = eventsList.Introduction,
EventShowCode = eventsList.EventId,
EventImageSmall = eventsList.EventImageThumbUrl,
EventUrl = eventsList.Url,
EventSortBy = eventsList.SortOrder
};
return allEvents.OrderBy(x => x.EventSortBy);
}
and this is the method to look up any matching eventIds in the XML that exist in my database
public IEnumerable<EventFeed> FilteredEvents(DateTime eventDate)
{
return GetAllEventsFromDatabase().Where(p => GetEventIds(eventDate).Contains<EventsDetails>(p.EventShowCode));
}
the project fails to build with the following error:
Error 9 Argument '2': cannot convert from 'string' to 'Events.EventsDetails'
var eventids = GetEventIdsByEventDate(DateTime.Now);
var result = eventsdb.Where(e => eventids.Contains(e));
If you are returnning List<EventFeed> inside the method, you should change the method return type from IEnumerable<EventFeed> to List<EventFeed>.
In likeness of how I found this question using Google, I wanted to take it one step further.
Lets say I have a string[] states and a db Entity of StateCounties and I just want the states from the list returned and not all of the StateCounties.
I would write:
db.StateCounties.Where(x => states.Any(s => x.State.Equals(s))).ToList();
I found this within the sample of CheckBoxList for nu-get.
The "in" in Linq-To-Sql uses a reverse logic compared to a SQL query.
Let's say you have a list of integers, and want to find the items that match those integers.
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var items = from p in context.Items
where numbers.Contains(p.ItemId)
select p;
Anyway, the above works fine in linq-to-sql but not in EF 1.0. Haven't tried it in EF 4.0
Execute the GetEventIdsByEventDate() method and save the results in a variable, and then you can use the .Contains() method
Related
var items = from c in contacts
select new ListItem
{
Value = c.ContactId, //Cannot implicitly convert type 'int' (ContactId) to 'string' (Value).
Text = c.Name
};
var items = from c in contacts
select new ListItem
{
Value = c.ContactId.ToString(), //Throws exception: ToString is not supported in linq to entities.
Text = c.Name
};
Is there anyway I can achieve this?
Note, that in VB.NET there is no problem use the first snippet it works just great, VB is flexible, im unable to get used to C#'s strictness!!!
With EF v4 you can use SqlFunctions.StringConvert. There is no overload for int so you need to cast to a double or a decimal. Your code ends up looking like this:
var items = from c in contacts
select new ListItem
{
Value = SqlFunctions.StringConvert((double)c.ContactId).Trim(),
Text = c.Name
};
I solved a similar problem by placing the conversion of the integer to string out of the query. This can be achieved by putting the query into an object.
var items = from c in contacts
select new
{
Value = c.ContactId,
Text = c.Name
};
var itemList = new SelectList();
foreach (var item in items)
{
itemList.Add(new SelectListItem{ Value = item.ContactId, Text = item.Name });
}
Use LinqToObject : contacts.AsEnumerable()
var items = from c in contacts.AsEnumerable()
select new ListItem
{
Value = c.ContactId.ToString(),
Text = c.Name
};
SqlFunctions.StringConvert will work, but I find it cumbersome, and most of the time, I don't have a real need to perform the string conversion on the SQL side.
What I do if I want to do string manipulations is perform the query in linq-to-entities first, then manipulate the stings in linq-to-objects. In this example, I want to obtain a set of data containing a Contact's fullname, and ContactLocationKey, which is the string concatination of two Integer columns (ContactID and LocationID).
// perform the linq-to-entities query, query execution is triggered by ToArray()
var data =
(from c in Context.Contacts
select new {
c.ContactID,
c.FullName,
c.LocationID
}).ToArray();
// at this point, the database has been called and we are working in
// linq-to-objects where ToString() is supported
// Key2 is an extra example that wouldn't work in linq-to-entities
var data2 =
(from c in data
select new {
c.FullName,
ContactLocationKey = c.ContactID.ToString() + "." + c.LocationID.ToString(),
Key2 = string.Join(".", c.ContactID.ToString(), c.LocationID.ToString())
}).ToArray();
Now, I grant that it does get cumbersome to have to write two anonymous selects, but I would argue that is outweighed by the convenience of which you can perform string (and other) functions not supported in L2E. Also keep in mind that there is probably a performance penalty using this method.
public static IEnumerable<SelectListItem> GetCustomerList()
{
using (SiteDataContext db = new SiteDataContext())
{
var list = from l in db.Customers.AsEnumerable()
orderby l.CompanyName
select new SelectListItem { Value = l.CustomerID.ToString(), Text = l.CompanyName };
return list.ToList();
}
}
Brian Cauthon's answer is excellent! Just a little update, for EF 6, the class got moved to another namespace. So, before EF 6, you should include:
System.Data.Objects.SqlClient
If you update to EF 6, or simply are using this version, include:
System.Data.Entity.SqlServer
By including the incorrect namespace with EF6, the code will compile just fine but will throw a runtime error. I hope this note helps to avoid some confusion.
var selectList = db.NewsClasses.ToList<NewsClass>().Select(a => new SelectListItem({
Text = a.ClassName,
Value = a.ClassId.ToString()
});
Firstly, convert to object, then toString() will be correct.
One more solution:
c.ContactId + ""
Just add empty string and it will be converted to string.
I ran into this same problem when I was converting my MVC 2 app to MVC 3 and just to give another (clean) solution to this problem I want to post what I did...
IEnumerable<SelectListItem> producers = new SelectList(Services.GetProducers(),
"ID", "Name", model.ProducerID);
GetProducers() simply returns an entity collection of Producers.
P.S. The SqlFunctions.StringConvert didn't work for me.
If your "contact" is acting as generic list, I hope the following code works well.
var items = contact.Distinct().OrderBy(c => c.Name)
.Select( c => new ListItem
{
Value = c.ContactId.ToString(),
Text = c.Name
});
Thanks.
Using MySql, the SqlFunctions.StringConvert didn't work for me. Since I use SelectListItem in 20+ places in my project, I wanted a solution that work without contorting the 20+ LINQ statements. My solution was to sub-class SelectedListItem in order to provide an integer setter, which moves type conversion away from LINQ. Obviously, this solution is difficult to generalize, but was quite helpful for my specific project.
To use, create the following type and use in your LINQ query in place of SelectedListItem and use IntValue in place of Value.
public class BtoSelectedListItem : SelectListItem
{
public int IntValue
{
get { return string.IsNullOrEmpty(Value) ? 0 : int.Parse(Value); }
set { Value = value.ToString(); }
}
}
if you use entity framework and you want to make the only int acceptable then you can use this in linq query you can try this
var items = from c in contacts
select new ListItem
{
Value = (int)ContractId
Text = c.Name
};
it will work because using (int) will cast your value to the int so you don't need any conversion for string to int and you get the result you want.
this worked for me in my project i think it would be helpful for you
My understanding is that you have to create a partial class to "extend" your model and add a property that is readonly that can utilize the rest of the class's properties.
public partial class Contact{
public string ContactIdString
{
get{
return this.ContactId.ToString();
}
}
}
Then
var items = from c in contacts
select new ListItem
{
Value = c.ContactIdString,
Text = c.Name
};
var items = from c in contacts
select new ListItem
{
Value = String.Concat(c.ContactId), //This Works in Linq to Entity!
Text = c.Name
};
I found that SqlFunctions.StringConvert((double)c.Age) did not work for me either the field is of type Nullable<Int32>
Took me a lot of searching over the last few days of trial and error to find this.
I hope this helps a few coders out there.
Can you try:
var items = from c in contacts
select new ListItem
{
Value = Convert.ToString(c.ContactId),
Text = c.Name
};
I have a method that returns an object from cache which I use to populate selectlists within the system.
var r = CacheHelper.GetCacheItem(...);
return new SelectList((IEnumerable)r, "Id", "Name");
r is of type System.Collections.Generic.List<<>f__AnonymousType39<string,int,string>>
By using IEnumerable enumerable = (IEnumerable)r; I see that
enumerable looks like this:
[0]: { Name = "Lost", Id = 1, Area = null }
[1]: { Name = "Found", Id = 2, Area = null }
[2]: { Name = "Stock Adjustment", Id = 3, Area = null }
...
I would like to be able to use LINQ toquery the result set to return a subset, while keeping the full list in memory. Something like:
var s = enumerable.Where(x => x.Area == "myarea");
Answers to similar SO questions suggest using ToList(), but I can't call any LINQ methods on enumerable without getting a System.Collections.IEnumerable' does not contain a definition for 'ToList'.. error message. (I'm using ToList() elsewhere in the code so I have a valid reference to System.Linq.
Ideally, you should keep the type information all the way through the system - and potentially create a named type with the relevant properties. You could then cast back to IEnumerable<SomeConcreteType> later.
If you can't do that though, and assuming you're using C# 4 and .NET 4 or later, you could use dynamic typing:
IEnumerable<dynamic> enumerable = (IEnumerable<dynamic>) r;
...
var s = enumerable.Where(x => x.Area == "myarea");
I have the following function (which is hosted in a WCF service, if that matters):
public List<IceVsRepositoryFile> GetRepositoryFilesByRepositoryId(int repId)
{
var entity = new IceVSEntities();
var files = from p in entity.Files where p.RepositoryId == repId select p.FileId;
List<long> iList = files.ToList();
var repFiles = from p in entity.RepositoryFiles where iList.Contains(p.FileId) select p;
if (!repFiles.Any())
return null;
var retFiles = repFiles.ToList().Select(z => new IceVsRepositoryFile
{
FileId = (int)z.FileId,
RollbackFileId = (int)z.RollbackFileId,
UserId = (int)z.UserId,
FileContents = z.FileContents,
ChangeDescription = z.ChangeDescription
}).ToList();
return retFiles;
}
When I run this function I am getting the following an error that says "LINQ to Entities does not recognize the method 'Boolean Contains(Int64)' method and this method cannot be translated into a store expression.
I understand why I am getting the error message. My question is, how can I rewrite my query to make this work as expected? My backend database, if it matters, if SqlLite 3. I am using .NET 3.5.
The contains you used is for List, it's not in IEnumerable so it can't be converted to corresponding sql query. Instead you can use Any, ... like:
iList.Any(x=>x == p.FileId) (or use related property)
Also instead of doing:
List<long> iList = files.ToList();
use files.Any... in your query to prevent from too many fetching from DB. Actually use IEnumerable functions instead of List functions.
I believe a join can do this:
public List<IceVsRepositoryFile> GetRepositoryFilesByRepositoryId(int repId)
{
var entity = new IceVSEntities();
var repFiles = from file in entity.Files where file.RepositoryId == repId join repFile in entity.RepositoryFiles on repFile.FileId equals file.FileId select repFile;
var retFiles = // as before
return retFiles;
}
Do you have a relationship between Files and RepositoryFiles? If so, it would be easier to do something like this:
var repFiles = from p in entity.RepositoryFiles where p.File.RepositoryId == repId select p;
This will avoid the problems with being unable to translate the query to SQL.
I'm trying to construct a Where clause for a Linq statement which needs to determine whether the AccountNumber values retrieved as below exist in a List<string> collection.
I've thus far tried this:
private void FindAccountNumbers(List<string> AccountNumbers)
{
var query = from abc
select new
{
AccountNumber = abc.AccountNumber
};
query = query.Where(AccountNumbers.Contains(x => x.AccountNumber));
}
However I get the following build error:
The type arguments for method
'System.Linq.Queryable.Where(System.Linq.IQueryable,
System.Linq.Expressions.Expression>)' cannot
be inferred from the usage. Try specifying the type arguments
explicitly.
At runtime, query contains AccountNumber values, and I'm trying to pare this down based on matches found in the AccountNumbers collection (similar to an IN statement in TSQL). Should I be using Intersect instead of Contains? What am I doing wrong??
I think you want to have this:
query = query.Where(x => AccountNumbers.Contains(x.AccountNumber));
This doesn't work?
var query = from x in abc
where AccountNumbers.Contains(x.AccountNumber)
select new { x.AccountNumber };
That would give you back any AccountNumber in that list, unless AccountNumber isn't actually a string. That could be your problem.
Its because your syntax for from is wrong, I'm guessing that your collection is abc of items to match against is abc
The correct syntax would be (Version 1)
var query = from x in abc
select new { AccountNumber = x.AccountNumber };
query = query.Where(x=>AccountNumbers.Contains(x.AccountNumber));
you don't need to do an anonymous type either as you are just wanting the same field you could just do (Version 2)
var query = from x in abc select x.AccountNumber;
query = query.Where(x=>AccountNumbers.Contains(x));
However you could just slap the Where straight onto your original collection. (Version 3)
var query = abc.Where(x=>AccountNumbers.Contains(x.AccountNumber);
Or if you are just trying to find whether any exist in the collection (Version 4)
var query = abc.Any(x=>AccountNumbers.Countains(x.AccountNumber);
Version 1 will return IEnumerable<string>
Version 2 will return IEnumerable<string>
Version 3 will return IEnumerable<type of the items in abc>
Version 4 will return bool
Let me verify what you're trying to do.
You have a collection of objects abc. You want to pull out the AccountNumber from each member of that collection, compare it to the list of account numbers passed in, and determine... what? If there IS any overlap, or WHAT the overlap is?
If the AccountNumber field is a string, you could do this:
private IEnumerable<string> OverlappingAccountNumbers(IEnumerable<string> accountNumbers)
{
return abc.Select(x => x.AccountNumber)
.Intersect(accountNumbers);
}
Or for the boolean case:
private bool AnyOverlappingAccountNumbers(IEnumerable<string> accountNumbers)
{
return abc.Select(x => x.AccountNumber)
.Intersect(accountNumbers)
.Count() > 0;
}
I'd go with this:
private void FindAccountNumbers(List<string> AccountNumbers)
{
// Get a strongly-typed list, instead of an anonymous typed one...
var query = (from a in abc select a.AccountNumber).AsEnumerable();
// Grab a quick intersect
var matched = query.Intersect(AccountNumbers)
}
One liner?
var query = (from a in abc select a.AccountNumber).AsEnumerable().Intersect(AccountNumbers);
The last answer are wrong because did mention one important point and obviously didn't be tested, the first issue is, you can't mix between an sql query than not been execute and a string's list, YOU CAN'T MIX!!! the solution for this problem and tested is:
var AccountNumbers = select accountNumber from table where.... // is a entitie
private void FindAccountNumbers(IQueryable<acounts> AccountNumbers) //entitie object not string
{
var query = from abc
select new
{
AccountNumber = abc.AccountNumber
};
query = query.Join(AccountNumbers, abc => abc.AccountNumber, aco=> aco, (ac, coNum) => cpac);
}
It really works! is necessary to mention this solution is when you are working with linq and entities framework!
var items = from c in contacts
select new ListItem
{
Value = c.ContactId, //Cannot implicitly convert type 'int' (ContactId) to 'string' (Value).
Text = c.Name
};
var items = from c in contacts
select new ListItem
{
Value = c.ContactId.ToString(), //Throws exception: ToString is not supported in linq to entities.
Text = c.Name
};
Is there anyway I can achieve this?
Note, that in VB.NET there is no problem use the first snippet it works just great, VB is flexible, im unable to get used to C#'s strictness!!!
With EF v4 you can use SqlFunctions.StringConvert. There is no overload for int so you need to cast to a double or a decimal. Your code ends up looking like this:
var items = from c in contacts
select new ListItem
{
Value = SqlFunctions.StringConvert((double)c.ContactId).Trim(),
Text = c.Name
};
I solved a similar problem by placing the conversion of the integer to string out of the query. This can be achieved by putting the query into an object.
var items = from c in contacts
select new
{
Value = c.ContactId,
Text = c.Name
};
var itemList = new SelectList();
foreach (var item in items)
{
itemList.Add(new SelectListItem{ Value = item.ContactId, Text = item.Name });
}
Use LinqToObject : contacts.AsEnumerable()
var items = from c in contacts.AsEnumerable()
select new ListItem
{
Value = c.ContactId.ToString(),
Text = c.Name
};
SqlFunctions.StringConvert will work, but I find it cumbersome, and most of the time, I don't have a real need to perform the string conversion on the SQL side.
What I do if I want to do string manipulations is perform the query in linq-to-entities first, then manipulate the stings in linq-to-objects. In this example, I want to obtain a set of data containing a Contact's fullname, and ContactLocationKey, which is the string concatination of two Integer columns (ContactID and LocationID).
// perform the linq-to-entities query, query execution is triggered by ToArray()
var data =
(from c in Context.Contacts
select new {
c.ContactID,
c.FullName,
c.LocationID
}).ToArray();
// at this point, the database has been called and we are working in
// linq-to-objects where ToString() is supported
// Key2 is an extra example that wouldn't work in linq-to-entities
var data2 =
(from c in data
select new {
c.FullName,
ContactLocationKey = c.ContactID.ToString() + "." + c.LocationID.ToString(),
Key2 = string.Join(".", c.ContactID.ToString(), c.LocationID.ToString())
}).ToArray();
Now, I grant that it does get cumbersome to have to write two anonymous selects, but I would argue that is outweighed by the convenience of which you can perform string (and other) functions not supported in L2E. Also keep in mind that there is probably a performance penalty using this method.
public static IEnumerable<SelectListItem> GetCustomerList()
{
using (SiteDataContext db = new SiteDataContext())
{
var list = from l in db.Customers.AsEnumerable()
orderby l.CompanyName
select new SelectListItem { Value = l.CustomerID.ToString(), Text = l.CompanyName };
return list.ToList();
}
}
Brian Cauthon's answer is excellent! Just a little update, for EF 6, the class got moved to another namespace. So, before EF 6, you should include:
System.Data.Objects.SqlClient
If you update to EF 6, or simply are using this version, include:
System.Data.Entity.SqlServer
By including the incorrect namespace with EF6, the code will compile just fine but will throw a runtime error. I hope this note helps to avoid some confusion.
var selectList = db.NewsClasses.ToList<NewsClass>().Select(a => new SelectListItem({
Text = a.ClassName,
Value = a.ClassId.ToString()
});
Firstly, convert to object, then toString() will be correct.
One more solution:
c.ContactId + ""
Just add empty string and it will be converted to string.
I ran into this same problem when I was converting my MVC 2 app to MVC 3 and just to give another (clean) solution to this problem I want to post what I did...
IEnumerable<SelectListItem> producers = new SelectList(Services.GetProducers(),
"ID", "Name", model.ProducerID);
GetProducers() simply returns an entity collection of Producers.
P.S. The SqlFunctions.StringConvert didn't work for me.
If your "contact" is acting as generic list, I hope the following code works well.
var items = contact.Distinct().OrderBy(c => c.Name)
.Select( c => new ListItem
{
Value = c.ContactId.ToString(),
Text = c.Name
});
Thanks.
Using MySql, the SqlFunctions.StringConvert didn't work for me. Since I use SelectListItem in 20+ places in my project, I wanted a solution that work without contorting the 20+ LINQ statements. My solution was to sub-class SelectedListItem in order to provide an integer setter, which moves type conversion away from LINQ. Obviously, this solution is difficult to generalize, but was quite helpful for my specific project.
To use, create the following type and use in your LINQ query in place of SelectedListItem and use IntValue in place of Value.
public class BtoSelectedListItem : SelectListItem
{
public int IntValue
{
get { return string.IsNullOrEmpty(Value) ? 0 : int.Parse(Value); }
set { Value = value.ToString(); }
}
}
if you use entity framework and you want to make the only int acceptable then you can use this in linq query you can try this
var items = from c in contacts
select new ListItem
{
Value = (int)ContractId
Text = c.Name
};
it will work because using (int) will cast your value to the int so you don't need any conversion for string to int and you get the result you want.
this worked for me in my project i think it would be helpful for you
My understanding is that you have to create a partial class to "extend" your model and add a property that is readonly that can utilize the rest of the class's properties.
public partial class Contact{
public string ContactIdString
{
get{
return this.ContactId.ToString();
}
}
}
Then
var items = from c in contacts
select new ListItem
{
Value = c.ContactIdString,
Text = c.Name
};
var items = from c in contacts
select new ListItem
{
Value = String.Concat(c.ContactId), //This Works in Linq to Entity!
Text = c.Name
};
I found that SqlFunctions.StringConvert((double)c.Age) did not work for me either the field is of type Nullable<Int32>
Took me a lot of searching over the last few days of trial and error to find this.
I hope this helps a few coders out there.
Can you try:
var items = from c in contacts
select new ListItem
{
Value = Convert.ToString(c.ContactId),
Text = c.Name
};