I want order all users, then grouped by GroupCode.
I cant query all data, Because the number of users is large.
And I have to use pagination (take,skip)
What's my bug?
public class User
{
public int Id { get; set; }
public int GroupCode { get; set; }
public DateTime CreatedDateTime { get; set; }
}
var query = _context.Users
.OrderByDescending(s => s.CreatedDateTime)
.GroupBy(s => s.GroupCode)
.Select(s => s.Key)
.Skip(skip)
.Take(take)
.ToListAsync()
The only solution that comes to my mind is to query all Users.OrderBy and then group them by GroupCode
Related
I want to return the Tags from the Tag table that are only found in the TagRecipe table. How can I do this?
var dataTags = await _context.Tags
.Include(tc => tc.TagCategory)
.ToListAsync();
public class Tag
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<TagRecipe> TagRecipes { get; set; }
public int TagCategoryID { get; set; }
public TagCategory TagCategory { get; set; }
}
public class TagRecipe
{
public int TagId { get; set; }
public int RecipeId { get; set; }
public Tag Tag { get; set; }
public Recipe Recipe { get; set; }
}
Thank you
Try this
var dataTags = await _context.TagRecipe
.Include(tc => tc.Tag.TagCategory)
.Select(i=> i.Tag)
.ToListAsync();
or you can use this syntax if you like it more
var dataTags = await _context.TagRecipe
.Include(t => t.Tag)
.ThenInclude(tc => tc.TagCategory)
.Select(i=> i.Tag)
.ToListAsync();
An alternative starting at table Tags using Join that will return a result without duplicates.
var dataTags = db.Tags
.Join(db.TagRecipes, tag => tag.Id, tagRecipe => tagRecipe.TagId, (tag, tagRecipe) => tag)
.Include(tag => tag.TagCategory)
.ToLookup(tag => tag.Id) // client-side from here
.Select(grouping => grouping.First()) // to make distinct
.ToList();
Will generate a straight-forward SQL
SELECT "t"."Id", "t"."Name", "t"."TagCategoryId", "t1"."Id", "t1"."Name"
FROM "Tags" AS "t"
INNER JOIN "TagRecipes" AS "t0" ON "t"."Id" = "t0"."TagId"
INNER JOIN "TagCategories" AS "t1" ON "t"."TagCategoryId" = "t1"."Id"
It is possible to use .Distinct in the above expression for removing duplicates instead of using grouping, but that will create a more complex SQL.
Table TagRecipes seems to be a join table in a many-to-many between table Tags and table Recipes. The latter is not included in the question, but I added it during my tests.
Please note that in EF Core 5, many-to-many relations may be created without an entity class for the join table.
I have two tables
CREATE TABLE RetailGroup(
Id int IDENTITY(1,1),
GroupName nvarchar(50),
)
CREATE TABLE RetailStore(
Id int IDENTITY(1,1),
StoreName nvarchar(100),
RetailGroupId int
)
Where RetailGroupId in RetailStore is referencing RetailGroup ID. I am trying to create a search function where I can search for both RetailGroup and RetailsStores. If I get a matching RetailStore I want to return the Group it is tied to and the matching Store record. If I get a matching Group, I want the group record but no retail stores.
I tried to do it the following way:
public List<RetailGroup> SearchGroupsAndStores(string value)
{
return _context.RetailGroups.Where(group => group.GroupName.Contains(value)).Include(group => group.RetailStores.Where(store => store.StoreName.Contains(value))).ToList();
}
But this is wrong because include should not be used for selection.
Here is my entity framework model for groups
public class RetailGroup
{
[Key]
public int Id { set; get; }
[MaxLength(50)]
public String GroupName { set; get; }
//Relations
public ICollection<RetailStore> RetailStores { set; get; }
}
And here is the one for the store
public class RetailStore
{
[Key]
public int Id { get; set; }
[MaxLength(100)]
public string StoreName { get; set; }
[ForeignKey("RetailGroup")]
public int RetailGroupId { get; set; }
//Relations
public RetailGroup RetailGroup { get; set; }
public ICollection<EGPLicense> Licenses { get; set; }
}
How do I create my LINQ to get the results I am looking for ?
The query returning the desired result with projection is not hard:
var dbQuery = _context.RetailGroups
.Select(rg => new
{
Group = rg,
Stores = rg.RetailStores.Where(rs => rs.StoreName.Contains(value))
})
.Where(r => r.Group.GroupName.Contains(value) || r.Stores.Any());
The problem is that you want the result to be contained in the entity class, and EF6 neither supports projecting to entity types nor filtered includes.
To overcome these limitations, you can switch to LINQ to Objects context by using AsEnumerable() method, which at that point will effectively execute the database query, and then use delegate block to extract the entity instance from the anonymous type projection, bind the filtered collection to it and return it:
var result = dbQuery
.AsEnumerable()
.Select(r =>
{
r.Group.RetailStores = r.Stores.ToList();
return r.Group;
})
.ToList();
Try using an OR condition to filter both the group name and the store name.
return _context.RetailGroups
.Where(group => group.GroupName.Contains(value) || group.RetailStores.Any(store => store.StoreName.Contains(value)))
.Include(group => group.RetailStores.Where(store => store.StoreName.Contains(value)))
.ToList();
Another option would be doing 2 searches, one for the groups and other for the stores. The problem here would be geting a unique set of groups from both results.
List<RetailGroup> retailGroups = new List<RetailGroup>();
var groupSearchResults = _context.RetailGroups
.Where(group => group.GroupName.Contains(value))
.Include(group => group.RetailStores.Where(store => store.StoreName.Contains(value)))
.ToList();
var storeSearchResults = _context.RetailStores
.Where(store => store.StoreName.Contains(value))
.Select(store => store.RetailGroup)
.ToList();
retailGroups.AddRange(groupSearchResults);
retailGroups.AddRange(storeSearchResults);
// Remove duplicates by ID
retailGroups = retailGroups
.GroupBy(group => group.Id)
.Select(group => group.First());
Either use OR condition and have the search in one statement :
public List<RetailGroup> SearchGroupsAndStores(string value)
{
return _context.RetailGroups
.Where(rg => rg.GroupName.Contains(value) || rg.RetailStores.Any(rs => rs.StoreName.Contains(value)))
.Include(rg => rg.RetailStores.Where(rs => rs.StoreName.Contains(value)).ToList())
.ToList();
}
Or you can split the search, first look for RetailGroups then search RetailStores and return their RetailGroup :
public List<RetailGroup> SearchGroupsAndStores(string value)
{
List<RetailGroup> searchResults = new List<RetailGroup>();
searchResults.AddRange(_context.RetailGroups.Where(rg => rg.GroupName.Contains(value)).ToList());
searchResults.AddRange(_context.RetailStores.Where(rs => rs.StoreName.Contains(value)).Select(rs => rs.RetailGroup).ToList());
}
i want to get latest 10 unique records whose last 12 characters should be unique.
sample data
json data
[{"timestamp":"2017-03-20T05:27:01.688Z","dataFrame":"ACnrAAAAAAAAAAA=","fcnt":165,"port":3,"rssi":-85,"snr":7,"sf_used":12,"id":1489987621688,"decrypted":true},{"timestamp":"2017-03-20T05:27:41.675Z","dataFrame":"ACntAAAAAAAAAAA=","fcnt":169,"port":3,"rssi":-85,"snr":9,"sf_used":12,"id":1489987661675,"decrypted":true},..
AGMDAQo1/wSsCPU=
AGMEAQo1/wSsCPU=
AGMFAQo1/wSsCPU=
AGMGAQo1/wSsCPU=
AGMHAQo1/wSsCPU=
ASHAAQo2FgSsBxc=
getting output like this , but it should only be one because last 12 characters are same.
AGMDAQo1/wSsCPU=,
AGMEAQo1/wSsCPU=,
AGMFAQo1/wSsCPU=
desired output
AGMDAQo1/wSsCPU=
ASHAAQo2FgSsBxc=
code
var Pirs = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AssetDetail>>(responseString);
var items = Pirs.Where(a => !a.dataFrame.EndsWith("AAAAAAAAAAA="))
.GroupBy(a => a.dataFrame)
.Select(g => g.First())
.OrderByDescending(a => a.timestamp)
.Take(10);
model
public class AssetDetail
{
public long id { get; set; }
public DateTime timestamp { get; set; }
public string dataFrame { get; set; }
public long fcnt { get; set; }
public int port { get; set; }
public int rssi { get; set; }
public string snr { get; set; }
public string sf_used { get; set; }
public bool decrypted { get; set; }
}
You could use a.dataFrame.Substring(a.dataFrame.Length - 12) inside the GroupBy function to group by the AssetDetails that have the same 12 characters at the end on their dataFrame property.
var Pirs = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AssetDetail>>(responseString);
var items = Pirs.Where(a => !a.dataFrame.EndsWith("AAAAAAAAAAA="))
.GroupBy(a => a.dataFrame.Substring(a.dataFrame.Length - 12))
.Select(g => g.First())
.OrderByDescending(a => a.timestamp)
.Take(10);
There is no need to use the Distinct() function if you are using GroupBy()
Use Distinct():
Newtonsoft.Json.JsonConvert.DeserializeObject<List<AssetDetail>>(responseString);
var items = Pirs.Where(a => !a.dataFrame.EndsWith("AAAAAAAAAAA="))
.GroupBy(a => a.dataFrame)
.Select(g => g.First())
.Distinct()
.OrderByDescending(a => a.timestamp)
.Take(10);
Hope it helps!
I have a catalog of products that I want to calculate aggregates on. This is simple enough for top level properties such as brand name, manufacturer, etc. The trouble comes with trying to calculate range counts on prices because we sell in multiple currencies, and when determining these counts I only want to query on one currency at a time. Here is a sample of my product object mapping:
public class Product
{
public int ID { get; set;}
public string Name { get; set; }
public IList<Price> Prices { get; set; }
}
public class Price
{
public int CurrencyID { get; set; }
public decimal Cost { get; set; }
}
Here is an example of a query for all products with a price below 100:
var cheapProducts = client.Search<Product>(s => s
.From(0)
.Size(1000)
.Query(q => q
.Range(r => r
.LowerOrEquals(100)
.OnField(f => f.Prices.FirstOrDefault().Cost))));
The ElasticSearch request that this generates is:
{
"from": 0,
"size": 1000,
"query": {
"range" : {
"prices.cost": {
"lte": "100"
}
}
}
}
This returns all products with at least one price below 100 in any currency, as you would expect. What I've been unable to do is to run this query against just prices in a given currency. For example, adding this filter to the query only removes products that don't have a price in currency 1:
var cheapProducts = client.Search<Product>(s => s
.From(0)
.Size(1000)
.Filter(f => f
.Term(t => t
.Prices.FirstOrDefault().CurrencyID, 1))
.Query(q => q
.Range(r => r
.LowerOrEquals(100)
.OnField(f => f.Prices.FirstOrDefault().Cost))));
I've tried treating the Prices list as both a nested object and a child object, but ElasticSearch doesn't appear to be indexing the prices in that way because I get an error of "AggregationExecutionException[[nested] nested path [prices] is not nested]" and similar for HasChild queries. Is it possible to generate queries and aggregates in this way?
First you need to map the nested type:
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
[ElasticProperty(Type = FieldType.Nested)]
public IList<Price> Prices { get; set; }
}
After that, try execute this query:
var cheapProducts = client.Search<Product>(s => s
.From(0)
.Size(1000)
.Query(x => x.Term(p => p
.Prices.First().CurrencyID, 1) && x.Range(r => r
.LowerOrEquals(100)
.OnField(f => f.Prices.FirstOrDefault().Cost))));
I have two entities like:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Lastname { get; set; }
public virtual ICollection<EmployeeEducation> EducationList { get; set; }
}
and
public class EmployeeEducation
{
public int Id { get; set; }
public int EmployeeId { get; set; }
public int Type { get; set; }
[ForeignKey("EmployeeId")]
public virtual Employee Employee { get; set; }
}
My question is, how can I get a specific employee and this employee's education list ordered by Type property?
I have tried:
Employee employee = _work.EmployeeRepository.GetSet()
.SelectMany(e => e.EducationList, (e,d) => new { e, d })
.OrderBy(x => x.d.Type)
.Select(x => x.e)
.FirstOrDefault(e => e.Id == id);
But it does't seem to be sorting. What is the correct way to do this?
Thanks for everyone...
You do SelectMany(), but never use the produced EducationList part, becuase you do .Select(x => x.e). But couldn't life be simpler? After all, you only get 1 employee, why not sort its EducationList as soon as you need it, after having Included it, if necessary:
Employee employee = _work.EmployeeRepository.GetSet().Include("EducationList")
.FirstOrDefault(e => e.Id == id);
Depending if u are using POCO or not u should either use CreateSourceQuery() or Query()
In the case of POCO something like:
Employee employee = _work.EmployeeRepository.GetSet()
.SelectMany(e => e.EducationList, (e,d) => new { e, d })
.Query()
.OrderBy(x => x.d.Type)
.Select(x => x.e)
.FirstOrDefault(e => e.Id == id);