I'm trying to get some content by taxonomies, that are a part of that content/ Here's what I have:
var taxonomyTerms = _taxonomyService.GetTerms(taxonomy.Id).Where(t => termsToSearch.Contains(t.Name)).ToList();
var listOfTermsIds= taxonomyTerms.Select(x => x.Id).ToList();
//works well until here, I have my list of terms ids
var originalContentItems = _cm
.Query<GenericContentPart, GenericContentRecord>()
.Join<TermsPartRecord>().Where(l => !l.Terms.Select(t => t.TermRecord.Id).Except(listOfTermsIds).Any()).List();
//this returns no records
I've managed to do this with a foreach, but I want to do the same with an expression. The problem is that last bit of code doesn't return me any records.
Any help?
I found the problem:
contentItems = _cm
.Query<GenericContentPart, GenericContentRecord>()
.Join<TermsPartRecord>().ForPart<TermsPart>().List()
.Where(l => !listOfTermsIds.Except(l.Terms.Select(t => t.TermRecord.Id).ToList()).Any());
Thanks.
Related
Consider the following LINQ statements:
var model = getModel();
// apptId is passed in, not the order, so get the related order id
var order = (model.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => y.OrderId));
var orderId = 0;
var orderId = order.LastOrDefault();
// see if more than one appt is associated to the order
var apptOrders = (model.getMyData
.Where(x => x.OrderId == orderId)
.Select(y => new { y.OrderId, y.AppointmentsId }));
This code works as expected, but I could not help but think that there is a more efficient way to accomplish the goal ( one call to the db ).
Is there a way to combine the two LINQ statements above into one? For this question please assume I need to use LINQ.
You can use GroupBy method to group all orders by OrderId. After applying LastOrDefault and ToList will give you the same result which you get from above code.
Here is a sample code:
var apptOrders = model.getMyData
.Where(x => x.ApptId == apptId)
.GroupBy(s => s.OrderId)
.LastOrDefault().ToList();
Entity Framework can't translate LastOrDefault, but it can handle Contains with sub-queries, so lookup the OrderId as a query and filter the orders by that:
// apptId is passed in, not the order, so get the related order id
var orderId = model.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => y.OrderId);
// see if more than one appt is associated to the order
var apptOrders = model.getMyData
.Where(a => orderId.Contains(a.OrderId))
.Select(a => a.ApptId);
It seems like this is all you need:
var apptOrders =
model
.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => new { y.OrderId, y.AppointmentsId });
I have a requirement to get the count of documents based on status of customer. So I need to use aggregate function and then group by based on status. I have used following code for that but the problem is that in Result I am getting the list of documents but what I just want to have is the status and count of documents under that. Can any body please help in adjusting the query to achieve the results.
var result = collection.Aggregate()
.Group(
x => x.status,
g => new
{
Result = g.Select(x => new CustomerDetailsList
{
ActiveType = x.status,
Count = g.Count()
}
)
}
);
Thanks in advance
The reason you're getting a list of documents for every key is that you're running this nested Select, all you need is:
collection.Aggregate()
.Group(
x => x.status,
g => new CustomerDetailsList
{
ActiveType = g.Key,
Count = g.Count()
}).ToList();
I am satisfied with the answer of #mickl and it works well as I tested according to my requirement but here is the way I opted in my app as this is what I am comfortable with. The method is to use the collection as queryable
var result = collection.AsQueryable()
.GroupBy(x => x.status)
.Select(x => new CustomerDetailsList
{
ActiveType = x.Key, Count = x.Count()
}).ToList();
I have used more LINQ in this way so I choose this as it's better to understand for me.
You can choose any of the methods either this or as demonstrated by #mickl
My goal is to order some data coming back. I love lambda expressions, but they are failing me. The code below gets a wonderful error about not putting a lambda in an include.
public async Task<Header> GetHeader(int HeaderId)
{
var header = await _context.Headers
.Include(location => location.HeaderLocation)
.Include(details => details.Details.OrderBy(x => x.FieldName).OrderBy(y => y.LineVersion).ToList())
.Where(p => p.HeaderId == HeaderId).FirstOrDefaultAsync();
return header;
}
The header has details, and the details need to be ordered by the property "FieldName", then by the property "LineVersion". Error I get:
Lambda expression used inside Include is not valid.
After some digging, I found a couple of ways to get around the lambda, but I am not having any luck with getting an example that has OrderBy, and my brain is failing me at the moment, and would love to get a little kick to get this working.
BTW: the code works fine when it is without the OrderBy, except that the details may not always come back in the order I need them.
Thanks in advance for the help
Brad
On top of the other suggestion I have seen, I used the link in the comments of the original post, and got a great answer there, too. I tested it, and it works like a charm. Here is what I ended up with:
public async Task<PermitHeader> GetPermit(int HeaderId)
{
var header = await _context.Headers
.Include(location => location.Location)
.Where(p => p.HeaderId == HeaderId).FirstOrDefaultAsync();
var details = await _context.Details
.OrderBy(ob => ob.FieldName)
.OrderBy(ob => ob.LineVersion)
.Where(d => d.HeaderHeaderId == HeaderId).ToListAsync();
header.Details = Details;
return header;
}
Thanks for a quick response!
I'd use a Select to get the entities with OrderBy after the Where but before FirstOrDefaultAsync(). Like this:
var header = await _context.Headers
.Include(location => location.HeaderLocation)
.Include(details => details.Details)
.Where(p => p.HeaderId == HeaderId)
.Select(header => new Header
{
// Assign Header values
Location = header.Location,
Details = header.Details.OrderBy(h => h.FieldName).OrderBy(h => h.LineVersion)
}).FirstOrDefaultAsync();
this code written by #Rahul Singh in this post Convert TSQL to Linq to Entities :
var result = _dbContext.ExtensionsCategories.ToList().GroupBy(x => x.Category)
.Select(x =>
{
var files = _dbContext.FileLists.Count(f => x.Select(z => z.Extension).Contains(f.Extension));
return new
{
Category = x.Key,
TotalFileCount = files
};
});
but this code have problem when used inside database context and we should use ToList() like this to fix "Only primitive types or enumeration types are supported in this context" error :
var files = _dbContext.FileLists.Count(f => x.Select(z => z.Extension).ToList().Contains(f.Extension));
the problem of this is ToList() fetch all records and reduce performance, now i wrote my own code :
var categoriesByExtensionFileCount =
_dbContext.ExtensionsCategories.Select(
ec =>
new
{
Category = ec.Category,
TotalSize = _dbContext.FileLists.Count(w => w.Extension == ec.Extension)
});
var categoriesTOtalFileCount =
categoriesByExtensionFileCount.Select(
se =>
new
{
se.Category,
TotalCount =
categoriesByExtensionFileCount.Where(w => w.Category == se.Category).Sum(su => su.TotalSize)
}).GroupBy(x => x.Category).Select(y => y.FirstOrDefault());
the performance of this code is better but it have much line of code, any idea about improve performance of first code or reduce line of second code :D
Regards, Mojtaba
You should have a navigation property from ExtensionCategories to FileLists. If you are using DB First, and have your foreign key constraints set up in the database, it should do this automatically for you.
If you supply your table designs (or model classes), it would help a lot too.
Lastly, you can rewrite using .ToList().Contains(...) with .Any() which should solve your immediate issue. Something like:
_dbContext.FileLists.Count(f => x.Any(z => z.Extension==f.Extension)));
How can I turn the following statement back to List<DocumentData>
IEnumerable<IGrouping<string, DocumentData>> documents =
documentCollection.Select(d => d).GroupBy(g => g.FileName);
the goal is to get List that should be smaller than documentCollection.
FileName contains duplicates so I want to make sure I don't have duplicate names.
I have also tried the following but it's still providing me with duplicate file names
documentCollection =
documentCollection.GroupBy(g => g.FileName).SelectMany(d => d).ToList();
Each IGrouping<string, DocumentData> is an IEnumerable<DocumentData>, so you could simply call SelectMany to flatten the sequences:
var list = documents.SelectMany(d => d).ToList();
Edit: Per the updated question, it seems like the OP wants to select just the first document for any given filename. This can be achieved by calling First() on each IGrouping<string, DocumentData> instance:
IEnumerable<DocumentData> documents =
documentCollection.GroupBy(g => g.FileName, StringComparer.OrdinalIgnoreCase)
.Select(g => g.First())
.ToList();
You haven't said what T should stand for in List<T> you're looking for, so here are couple the most likely to be desired:
List<DocumentData> - rather pointless as you already have that on documentCollection
var results = documents.SelectMany(g => g).ToList();
List<KeyValuePair<string, List<DocumentData>>
var results =
documents.Select(g => new KeyValuePair(g.Key, g.ToList())).ToList();
List<string> - just the names
var results = documents.Select(g => g.Key).ToList();
List<IGrouping<string, DocumentData>>
var results = documents.ToList();