How do I select several ids? - c#

There is a list List<string> list
How to build a query using LINQ, which repeat the query "Select * FROM a Where id IN(...)"

Use LINQ and Contains method:
var result = a.Where(c => list.Contains(c.Id)).ToList();

You could use Any as well:
var result = source.Where(item => list.Any(element => element == item.Id)).ToList();
Btw if you're using the list only to check if a given element is present or not, I'd suggest using a HashSet<string> as you may gain better performance:
HashSet<string> container = ....
Then use as follows:
var result = source.Where(item => container.Contains(item.Id));

Related

How to use Linq to check if a list of strings contains any string in a list

I'm constructing a linq query that will check is a string in the DB contains any of the strings in a list of strings.
Something like.
query = query.Where(x => x.tags
.Contains(--any of the items in my list of strings--));
I'd also like to know how many of the items in the list were matched.
Any help would be appreciated.
Update: I should have mentioned that tags is a string not a list. And I am adding on a couple more wheres that are not related to tags before the query actually runs. This is running against entity framework.
EDIT: This answer assumed that tags was a collection of strings...
It sounds like you might want:
var list = new List<string> { ... };
var query = query.Where(x => x.tags.Any(tag => list.Contains(tag));
Or:
var list = new List<string> { ... };
var query = query.Where(x => x.tags.Intersect(list).Any());
(If this is using LINQ to SQL or EF, you may find one works but the other doesn't. In just LINQ to Objects, both should work.)
To get the count, you'd need something like:
var result = query.Select(x => new { x, count = x.tags.Count(tag => list.Contains(tag)) })
.Where(pair => pair.count != 0);
Then each element of result is a pair of x (the item) and count (the number of matching tags).
I've done something like this before:
var myList = new List<string>();
myList.Add("One");
myList.Add("Two");
var matches = query.Where(x => myList.Any(y => x.tags.Contains(y)));
like this:
List<string> list = new List<string>();
list.Add("One");
list.Add("Two");
var result = query.Where(x => list.Contains(x.tags));
I am not quite sure from your question if x.tags is a string or list, if it is a list Jon Skeet's answer is correct. If I understand you correctly though x.tags is a string of strings. If so then the solution is:
list.Any(x => x.tags.IndexOf(x) > -1)
to count them do
list.Count(x => x.tags.IndexOf(x) > -1)
var t = new List<string> { "a", "b", "c" };
var y = "a b d";
var res = y.Count(x => t.Contains(x.ToString()));
I faced a similar problem recently and here's how I managed to work it out:
var list = [list of strings];
if (list != null && list.Any())
{
queryable = queryable.Where(x => x.tags != null);
var tagQueries = new List<IQueryable<WhateverTheDbModelIs>>();
foreach (var element in list)
{
tagQueries.Add(queryable.Where(x => x.tags.Contains(element)));
}
IQueryable<WhateverTheDbModelIs> query = tagQueries.FirstOrDefault();
foreach (var tagQuery in tagQueries)
{
query = query.Union(tagQuery);
}
queryable = queryable.Intersect(query);
}
probably not the best option but something a less experienced developer can understand and use

Grab a List item based on newest datetime

Im grabing articles with this code.
List<view_M04FrontpagesEntity> fList = new view_M04FrontpagesService().GetByCategoryId(0);
var article = new M02ArticlesService().GetById(fList.First<view_M04FrontpagesEntity>().M02ArticleId);
I want to grab the article with the newest article.UpdatedDate how can a best do this with linq or other method?
Use MaxBy method provided my MoreLinq
List<view_M04FrontpagesEntity> fList = new view_M04FrontpagesService().GetByCategoryId(0);
var newest = fList.MaxBy(article => article.UpdatedDate);
you can Use OrderByDescending in LInQ.
var query = myList.Where(x =>x=="somePredicate")
.OrderByDescending(x => x.UpdatedDate ).FirstOrDefault();
Returns the first element of a sequence, or a default value if the sequence contains no elements.
var first = articles.OrderByDescending( a => a.UpdateDate ).First();
Generally speaking, this is it. You need to transfer this to your code yourself, because none of the code you posted helped.
var result = (from article in fList
orderby article.UpdatedDate descending
select article).First();
This is working as intended.
var m04FrontpagesEntities = new view_M04FrontpagesService().GetByCategoryId(0).ToList().Select(x => new M02ArticlesService().GetById(x.M02ArticleId)).ToList().OrderByDescending(x => x.UpdatedDate); ;
var article = m04FrontpagesEntities.First();

Using SelectMany() or matching elements of two sequences with LINQ (dot syntax)

I need select all elements from a set whose Id property is contained within a second set. Can "SelectMany()" be used to accomplish this? What is the most efficient / best solution for this type of matching problem.
Example:
Select all DateRangeIds for a given ReportId by way of a joining entity set.
Sets:
Reports {ReportId, ReportName}
ReportDateRanges {DateRangeId, ReportId, ReportDateRangeId}
DateRanges {DateRangeId, DateRangeName}
Here is my solution's code. I am unsure if this is the proper approach, but this does solve the problem I've described:
var report = Reports.Take(1).FirstOrDefault();
int reportId = Convert.ToInt32(report.Id);
var dateRangeIds = ReportDateRanges.Where(rdr => rdr.ReportId == reportId).OrderBy(it => it.DateRangeId).Select(it => it.DateRangeId);
var dateRanges = DateRanges.Where(dateRange => dateRangeIds.Contains(dateRange.Id));
LINQ experts, please feel free to critique this code and offer any suggestions. Thanks for the help!
Well, you can use an Enumerable.Intersect(Of TSource) Method (IEnumerable(Of TSource), IEnumerable(Of TSource), IEqualityComparer(Of TSource))
for example:
var list1 = new List<int> {1,2,3,4,5,6,7,8};
var list2 = new List<int> {9,10,11,12,13,4,5};
list1.Intersect(list2);
result
4,5
Using overload specified in link, you can specify EqualityComparer for your custom object in order to find intersection of both enumerations.
Hope this helps.
I think your code is simple and readable but there are something which is not good:
var report = Reports.Take(1).FirstOrDefault();
you can write:
var report = Reports.FirstOrDefault();
And in this line:
var dateRangeIds = ReportDateRanges.Where(rdr => rdr.ReportId == reportId)
.OrderBy(it => it.DateRangeId)
.Select(it => it.DateRangeId);
you used orderby but you don't need this.
You can join the collections.
Given that you have the reportId you can issue this query.
Reports
.Where(report => report.ReportId == reportId)
.Join(ReportDateRanges,
report => report.ReportId,
rdr => rdr.ReportId,
(report, reportDateRange) => reportDateRange)
.Join(DateRanges,
rdr => rdr.DateRangeId,
dateRange => dateRange.DateRangeId,
(reportDateRange, dateRange) => dateRange);
Here's one way to do it:
IEnumerable<SomeTypeWithAnIDProperty> sourceSequence = //whatever
IEnumerable<TypeOfTheIDProperty> ids = //whatever
var selectedItems =
from sourceObject in sourceSequence
join id in ids
on sourceObject.ID equals id
select sourceObject;
Or, to use your example
var dateRangeIds = ReportDateRanges
.Where(rdr => rdr.ReportId == reportId)
.OrderBy(it => it.DateRangeId)
.Select(it => it.DateRangeId);
var dateRanges = DateRanges.Join(dateRangeIds, dateRange => dateRange.Id, id => id, (dateRange, id) => dateRange);

LINQ: How to remove element from IQueryable<T>

How do you loop through IQueryable and remove some elements I don't need.
I am looking for something like this
var items = MyDataContext.Items.Where(x => x.Container.ID == myContainerId);
foreach(Item item in items)
{
if(IsNotWhatINeed(item))
items.Remove(item);
}
Is it possible? Thanks in advance
You should be able to query that further as in this
var filtered = items.Where(itm => IsWhatINeed(itm));
Also notice the subtle change in the boolean function to an affirmative rather than a negative. That (the negative) is what the not operator is for.
items = items.Where( x => !IsNotWhatINeed(x) );
var items = MyDataContext.Items.Where(x => x.Container.ID == myContainerId
&& !IsNotWhatINeed(x));
or
var items = MyDataContext.Items.Where(x => x.Container.ID == myContainerId)
.Where(x=> !IsNotWhatINeed(x));
The other answers are correct in that you can further refine the query with a 'where' statement. However, I'm assuming your query is a Linq2Sql query. So you need to make sure you have the data in memory before further filtering with a custom function:
var items = MyDataContext.Items.Where(x => x.Container.ID == myContainerId)
.ToList(); // fetch the data in memory
var itemsToRemove = items.Where(IsNotWhatINeed);
If you really want to extend the IQueryable, then the 'IsNotWhatINeed' function must be translated to something that Linq2Sql understands.
Try This:
var items = YourDataContext.Items.Where(x => x.Container.ID == myContainerId
&& !IsNotWhatYouNeed(x));

How to specify an Order or Sort using the C# driver for MongoDB?

I'm trying to figure out how to sort a collection of documents server side by telling the C# driver what the sort order is, but it appears not to support that construct yet.
Is it possible to do this any other way?
You can also do it using the SetSortOrder method on the MongoCursor class:
db["collection"].Find().SetSortOrder(SortBy.Ascending("SortByMe"));
Just to add to Chris's answer, in C# Driver 2.x it is now done with SortBy, SortByDescending, ThenBy & ThenByDescending
collection.Find(bson => true).SortBy(bson => bson["SortByMeAscending"]).ThenByDescending(bson => bson["ThenByMeDescending"]).ToListAsync()
Now it resembles Linq even more.
http://mongodb.github.io/mongo-csharp-driver/2.0/reference/driver/crud/reading/#sort
For async methods:
var filter = Builders<BsonDocument>.Filter.Empty;
var sort = Builders<BsonDocument>.Sort.Ascending("time");
collection.FindAsync(filter, new FindOptions<BsonDocument, BsonDocument>()
{
Sort = sort
});
Simple usage of api in MongoDB.Driver 2.5.0
var client = new MongoClient("mongodb://localhost:27017");
var database = client.GetDatabase("Blog");
var list = database.GetCollection<BlogPost>("BlogPost")
.Find(e => e.Deleted == false)
.SortByDescending(e => e.CreatedOn)
.Limit(20)
.ToList();
Note that to sort on multiple fields use this:
db["collection"].Find().SetSortOrder(SortBy.Ascending("SortByMe").Descending("An‌​dByMe");
If you want to use linq:
From the documentation: (http://docs.mongodb.org/ecosystem/tutorial/use-linq-queries-with-csharp-driver/)
var query=
(from c in collection.AsQueryable<C>()
orderby c.X
select c)
foreach (var d in query)
{
// process your documents
}
If you want you can also limit the results:
var query=
(from c in collection.AsQueryable<C>()
orderby c.X descending
select c).Take(1);
Just remember to have an index on the field you are sorting by : ]
It seems the way to do this using the existing C# driver is as follows:
db["collection"].Find(new Document().Append("query",
new Document()).Append("orderby",
new Document().Append(name:1).Append(age,-1)));
Which I was turned on to by Sam Corder here
You can apply sort with SortDefinition like this:
FilterDefinition<User> filter = Builders<User>.Filter.Eq(a => a.Deleted , false);
SortDefinition<User> sort = Builders<User>.Sort.Descending(a => a.Id);
List<User> result = _dbContext.Users.Find(filter).Sort(sort).Limit(10).ToList();
#DmitryZyr's answer for FindAsync was not working. This one did however.
var sortDefinition = new SortDefinitionBuilder<ImmutableLog>().Descending("date");
var findOptions = new FindOptions<ImmutableLog>() {Sort = sortDefinition};
await this.Collection.FindAsync(new BsonDocument(), findOptions);
I'm currently using the API version MongoDB.Driver 2.8.1.
Here is my method that I call to return a list of objects with Descending sorting, if it is required:
public static IEnumerable<TEntity> GetDocumentsForCollection(
IMongoDatabase database,
string collectionName,
FilterDefinition<TEntity> query,
string databaseCollectionKeyToSortOnDescending)
{
var _mongoSettings = new MongoCollectionSettings();
_mongoSettings.GuidRepresentation = GuidRepresentation.Standard;
var _collection = database.GetCollection<TEntity>(collectionName, _mongoSettings);
if (string.IsNullOrEmpty(databaseCollectionKeyToSortOnDescending))
{
return _collection.Find(query).ToList();
}
return _collection.Find<TEntity>(query).Sort(Builders<TEntity>.Sort.Descending(databaseCollectionKeyToSortOnDescending)).ToList();
}
I'm doing this in JavaScript since I don't know C#, but it should have equivalent syntax with the C# driver.
If your query looked like:
db.c.find({"foo" : "bar"})
and you want to sort by "baz" ascending, wrap your query in a "query" field and add an "orderby" field:
db.c.find({"query" : {"foo" : "bar"}, "orderby" : {"baz" : 1}})
For descending sort, use -1.

Categories

Resources