There is a table, where i store information about bookings.
It's a simple one. Has just few attr like: bookingId, personId, date and shouldBeConsidered
I want to retrieve for each person booked from som period of time for last 10 days and then to include property shouldBeConsidered.
For instance there were 100 bookings and 2 of those amount should be taken from db. And also, there can be person who booked 100 booking where is 0 shouldBeConsidered
I've code something like this:
var res = await this.context.Bookings
.Where(x => x.DateTime >= bookingsStartDateTime || x.ShouldBeConsidered)
.GroupBy(x => br.PId)
.Select(x => Dal
{
Id = br.Key,
TotalBookings = x.Count(),
BookingsIssues = x.Count(x => x.ShouldBeConsidered)
})
.ToListAsync();
But, unfortuanlly, it does not work properly. Sometimes, it could take a bit more issues and also count a bit more total.
You will need a bit more clear example with a few record scenarios followed by what you expect to have been returned and what you actually got returned. Your logic is going to give you all bookings where either the booking date >= that start date OR the ShouldBeConsidered flag is true. (regardless of date)
On a hunch I think you probably want to remove that || x.ShouldBeConsidered in that ultimately you'd be interested in the total # of bookings after the start date, and a separate count of the bookings after the start date with that flag set. the statement "and then to include property shouldBeConsidered" seems confusing. All properties of the booking are included/available for querying against:
var res = await this.context.Bookings
.Where(x => x.DateTime >= bookingsStartDateTime)
.GroupBy(x => br.PId)
.Select(x => Dal
{
Id = br.Key,
TotalBookings = x.Count(),
BookingsIssues = x.Count(x => x.ShouldBeConsidered)
}).ToListAsync();
Related
I am using a LinqToSql-DataSource for a GridView in this way:
wsv.wsv2DataContext db = new wsv.wsv2DataContext();
e.KeyExpression = "id";
e.QueryableSource = (from mitgliedschaft in db.mitgliedschaft
join person in db.person on mitgliedschaft.person_id equals person.id
join institution in db.institution on mitgliedschaft.verein_id equals institution.id
select new
{
vorname = person.vorname,
nachname = person.nachname,
nameVerein = institution.name,
vereinid = mitgliedschaft.verein_id,
id = mitgliedschaft.id,
verbandsMitgliedsNummer = person.verbandsMitgliedsNummer,
strasse = person.strasse,
plz = person.plz,
ort = person.ort,
geburtsdatum = person.geburtsdatum,
geschlechtid = person.geschlechtid,
statusid = mitgliedschaft.statusid,
bezirk_id = mitgliedschaft.bezirk_id,
kreis_id = mitgliedschaft.kreis_id,
person_id = mitgliedschaft.person_id.Value,
deletedFlag = mitgliedschaft.deletedFlag,
stammverein = mitgliedschaft.stammVerein,
eintrittsdatum = mitgliedschaft.eintritt
}).GroupBy(p => p.person_id).Select(p => p.First());
}
Now i want to order the Selection. At first the "stammVerein"-Column of Table "mitgliedschaft" descending AND the Column "eintritt" of Table "mitgliedschaft". I have tried several ways:
wsv.wsv2DataContext db = new wsv.wsv2DataContext();
e.KeyExpression = "id";
e.QueryableSource = (from mitgliedschaft in db.mitgliedschaft
join person in db.person on mitgliedschaft.person_id equals person.id
join institution in db.institution on mitgliedschaft.verein_id equals institution.id
orderby mitgliedschaft.stammVerein descending, mitgliedschaft.eintritt
select new
{
...
}).GroupBy(p => p.person_id).Select(p => p.First());
}
AND:
wsv.wsv2DataContext db = new wsv.wsv2DataContext();
e.KeyExpression = "id";
e.QueryableSource = (from mitgliedschaft in db.mitgliedschaft
join person in db.person on mitgliedschaft.person_id equals person.id
join institution in db.institution on mitgliedschaft.verein_id equals institution.id
select new
{
...
}).GroupBy(p => p.person_id).Select(p => p.First()).OrderByDescending(stamm => stamm.stammverein).ThenBy(eintritt => eintritt.eintrittsdatum);
}
AND:
wsv.wsv2DataContext db = new wsv.wsv2DataContext();
e.KeyExpression = "id";
e.QueryableSource = (from mitgliedschaft in db.mitgliedschaft
join person in db.person on mitgliedschaft.person_id equals person.id
join institution in db.institution on mitgliedschaft.verein_id equals institution.id
select new
{
....
}).OrderByDescending(stamm => stamm.stammverein).ThenBy(eintritt => eintritt.eintrittsdatum).GroupBy(p => p.person_id).Select(p => p.First());
But nothing of this has any Effects ! I am very new in this kind of DataSource and Linq.
Can anyone help me achieving this order ?
Items within a grouped result will not retain their order. Depending on how you want to factor in the ordering, you will need to do it after the group by, and before, and/or after your First...
To accomplish this, it will be easiest if you map the relationships in EF with navigation properties rather than substituting SQL with Linq QL (joins and such)
Using the following base query:
var query = db.mitgliedschaft
.GroupBy(m => m.Person); // Group by related entity, not ID
For instance, after the group by, you will have sets of records grouped by Person. If you want the first Person with an earliest related record:
var result = query.OrderByDescending(g => g.Key.mitgliedschafts.Max(stamm => stamm.stammverein)
.ThenBy(stamm => stamm.eintritt.eintrittsdatum)
.First();
This is taking a wild guess at your schema & entity relationships, but hopefully it will help you work out something that fits. I can only guess at what eintritt is and how it relates to your entity model.
The initial query takes just your base entities that you want to group, and groups them by the related entity. The result of that grouping will be a set of Grouped mitgliedschafts with a key being the Person. To Order those groups by the person with the most recent mitgliedschafts we use an orderby on the Key's associated mitgliedschafts using the Max value for the collection given a descending order request.
The First then gives us the first grouped collection of mitgliedschafts.
Then if you want to sort the resulting list of mitgliedschafts after getting the person with the most recent one:
var result = query.OrderByDescending(g => g.Key.mitgliedschafts.Max(stamm => stamm.stammverein)
.ThenBy(stamm => stamm.eintritt.eintrittsdatum)
.First().OrderByDescending(stamm => stamm.stammverein)
.ThenBy(stamm => stamm.eintritt.eintrittsdatum)
.ToList();
The 2nd set of OrderBy clauses apply to the selected group, or the mitgliedschafts.
To compose the desired view model, Insert a Select() to build the view model from the mitgliedschafts before the ToList().
With the navigation properties this can probably be done without resorting to a group by. On a hunch, something like this should return something similar:
var query = db.Person
.OrderByDescending(p => p.mitgliedschafts.Max(stamm => stamm.stammverien))
.ThenBy(stamm => stamm.eintritt.eintrittsdatum)
.SelectMany(p => p.mitgliedschafts)
.OrderByDescending(stamm => stamm.stammverien)
.ThenBy(stamm => stamm.eintritt.eintrittsdatum)
.Select(stamm => new { ... })
.ToList();
Anyhow, hopefully that gives you some ideas on things to try if you have the navigation properties mapped or can set those up.
I have a field, that's indexed as
Index(x => x.Status, FieldIndexing.Default);
in a collection with a total of 2566 records.
Now when I query like this:
var query = _ravenSession
.Query<MyIndex.ReduceResult, MyIndex>()
.Statistics(out stats);
query = query.Where(x => x.Status != "inactive" && x.Status != "invalid" && x.Status != "sold");
I get a total result count of 2512.
But if I query like this:
query = query.Where(x => !x.Status.In("inactive", "invalid", "sold"));
I get a total result count of 2520. How can this count be different?
I can see, that the first query translates to
{((((-Status:inactive AND Status:*) AND -Status:invalid))
AND -Status:sold)}
and the second one:
{(: AND -#in`<Status>:(inactive , invalid , sold) )}
There is a difference with how this query is processed.
In the first case, you are allowing only results that have a Status, in the second, you are saying everything but those particular values. So if you have values that don't have the status property, that might explain it.
I have a main VendorProfile table and a 1-many VendorHistory table that contains status codes and date stamps. The query below works at retrieving only the latest status (status code and date) for each vendor. However, the view allows the user to select checkboxes of any of the status codes to filter the view. So I need to add a where clause that matches ANY of the checkbox StatusSelections.
Model Diagram
public IEnumerable<BrowseStatusModel> BrowseByStatus(int[] StatusSelections)
{
IQueryable<BrowseStatusModel> query = _db.VendorProfiles
.Include("VendorStatusHistory")
.Include("StatusCodes")
.Select(s => new BrowseStatusModel
{
ProfileID = s.ProfileID,
Name = s.Name,
CompanyName = s.CompanyName,
CompanyDBA = s.CompanyDBA,
DateCreated = s.DateCreated,
Status = s.VendorStatusHistories.OrderByDescending(o => o.DateCreated).FirstOrDefault().Id,
StatusDate = s.VendorStatusHistories.OrderByDescending(o => o.DateCreated).FirstOrDefault().DateCreated
})
.OrderBy(x => x.ProfileID);
foreach (int status in StatusSelections)
{
query = query.Where(x => x.Status == status);
}
return query;
}
The above foreach loop works but, unfortunately creates AND condition where ALL selections must be true instead of ANY. I figured I would have to use a where clause with the following in some way but have been unsuccessful at the correct syntax.
.AsQueryable().Any();
Use contains in the place of that foreach loop
query = query.Where(x => StatusSelections.Contains(x.Status))
If I want to apply a predicate to a document before I aggregate in a Reduce function, do I want to place that predicate in the Map function, or in the Reduce function?
So for example putting the predicate in the Map function would look like this:
Map = orders => orders
.Where(order => order.Status != OrderStatus.Cancelled)
.Select(order => new
{
Name = order.Firstname + ' ' + order.Lastname,
TotalSpent = order.Total,
NumberOfOrders = 1
});
Reduce = results => results
.GroupBy(result => result.Email)
.Select(customer => new
{
Name = customer.Select(c => c.Name).FirstOrDefault(),
TotalSpent = customer.Sum(c => c.TotalSpent),
NumberOfOrders = customer.Sum(c => c.NumberOfOrders)
});
And putting it in the Reduce function would look like this:
Map = orders => orders
.Select(order => new
{
Name = order.Firstname + ' ' + order.Lastname,
TotalSpent = order.Total,
NumberOfOrders = 1,
Status = order.Status
});
Reduce = results => results
.Where(order => order.Status != OrderStatus.Cancelled)
.GroupBy(result => result.Email)
.Select(customer => new
{
Name = customer.Select(c => c.Name).FirstOrDefault(),
TotalSpent = customer.Sum(c => c.TotalSpent),
NumberOfOrders = customer.Sum(c => c.NumberOfOrders),
Status = (OrderStatus)0
});
The latter obviously makes more sense, however it means that I have to add the Status property to the class of the Reduce result and then just set it to some unknown value in the Reduce as it doesn't actually mean anything there.
Only the first approach works for map/reduce. And no, the order will be ignored and you can't do something like FirstOrDefault in the result.
You need to think of map/reduce as two independent functions whereas the reduce function can be run multiple times on the same input, that's why the format of the input must match the format of the output. This can also happen on different server in parallel and asynchronously, thus new documents can be saved while the indexing is running.
I have a parent-child relationship between Teacher and StudentReport. Each StudentReport has a timestamp field recording when the teacher finished the report. I have a query to find all teachers who have completed one or more of their reports as of a certain number of minutes ago:
public IList<Teacher> FindRecentlyActiveTeachers(int intervalMinutes)
{
if (intervalMinutes <= 0)
throw new ArgumentException("Interval must be a positive number of minutes");
DateTime activityCutoff = DateTime.Now.AddMinutes(-1 * intervalMinutes);
return Session.QueryOver<Teacher>()
.Left.JoinQueryOver<StudentReport>(t => t.StudentReports)
.Where(r => r.FirstSaveTimestamp >= activityCutoff)
.TransformUsing(Transformers.DistinctRootEntity)
.List<Teacher>();
}
This returns the correct list of teachers, but the child collection for each teacher only contains the reports that match the selection criterion. I would like the report collection of each matching teacher to contain all of the reports, not just the few reports that meet the criteria.
Is there some way I can either load the full child collection eagerly, or omit loading it in this query and rely on lazy loading it?
Update
This is the solution:
return Session.QueryOver<Teacher>()
.Fetch(t => t.StudentReports).Eager
.JoinQueryOver<StudentReport>(t => t.StudentReports)
.Where(r => r.FirstSaveTimestamp >= activityCutoff)
.TransformUsing(Transformers.DistinctRootEntity)
.List<Teacher>();
Use Fetch
return Session.QueryOver<Teacher>()
.Fetch(t => t.StudentReports)
.Where(r => r.FirstSaveTimestamp >= activityCutoff)
.TransformUsing(Transformers.DistinctRootEntity)
.List<Teacher>();