Restrict records returned from nested LINQ statement - linq

how would I restrict the "Charges" returned in this linq query, to a specified date range:
var dte = DateTime.Parse("2012-01-01");
var dte2 = DateTime.Parse("2012-02-01");
var meetingrooms = tblMeetingRoom
.Where(r => r.building_id==1)
.GroupBy(p => p.tblType)
.Select(g => new
{
TypeName = g.Key.room_type,
TypeID = g.Key.type_id,
TypeCount = g.Count(),
charges =
from rt in charges
where (rt.type_id == g.Key.type_id)
select new {
rt.chargedate,
rt.people,
rt.charge
}
});
meetingrooms.Dump();
I think it needs to go inbetween here somehwhere:
from rt in charges
where (rt.type_id == g.Key.type_id) (EG) && rt.chargedate>=dte and rt.chargedate <dte2
select new {
Thanks for any help,
Mark

from rt in charges
where rt.type_id == g.Key.type_id && (rt.chargedate >= dte && rt.chargedate <= dte2)
select new {
.....

#Maarten - I've been trying this for ages - LinqPad kept giving errors, so I was trying all different ways I could think of - for whatever reason, I must have made some typos, that I didn't make above!
Sorry for wasting everyone's time - the above works "as-is"!
Mark

Related

How to get all the birthdays of today?

Does anyone know how to make a Linq query that gets all the birthdays of today? The code below doesn't work :
var getBirthdays =
orgContext.CreateQuery<Contact>()
.Where(c => c.BirthDate != null
&& c.BirthDate.Value.Month == DateTime.Now.Month).ToList();
I get an error like this:
"Invalid 'where' condition. An entity member is invoking an invalid
property or method."
Thanks in advance!
Anytime a vendor writes a four part blog series on how to do something as simple as finding a birthday (as Microsoft did in 2007), you have to know this won't be simple. So far as I can tell, this hasn't updated since then.
Find contacts with upcoming birthdays
Find contacts with upcoming birthdays - Part 2
Find contacts with upcoming birthdays - Parts 3 and 4
So you have limited options:
Make new fields called something like new_birthmonth and new_birthday that's updated every time a contact is created or updated via a plugin, and then query on those int fields.
Using Dynamic Linq, construct an OR clause in your WHERE clause that checks to see if the birthday falls in a reasonable range of years (say, 140 for the long-livers) (code below).
List<string> birthdays = new List<string>(); //will contain list of OR clauses
//makes sure no CRM unsupported dates are passed (less than 1/1/1900)
for (int i = Math.Min(140, DateTime.Today.Year - 1900); i > -1; i--)
{
//adds a different date per year
birthdays.Add
(
string.Format
(
//DateTimes are stored in UTC
"BirthDate = DateTime.Parse(\"{0}\")",
DateTime.Today.ToUniversalTime().AddYears(-i)
)
);
}
//completes the correct dynamic linq OR clause
string birthdayList = string.Join(" OR ", birthdays);
var getBirthdays = orgContext.CreateQuery<Xrm.Contact>()
.Where(c => c.BirthDate != null)
.Where(birthdayList)
.ToList();
I solved my problem based on the example of "Peter Majeed" and using "LinqKit"!
var predicate = PredicateBuilder.False<Contact>();
for (int i = Math.Min(140, DateTime.Today.Year - 1900); i > -1; i--)
{
DateTime cleanDateTime = new DateTime(DateTime.Today.AddYears(-i).Year, DateTime.Today.AddYears(-1).Month, DateTime.Today.AddYears(-i).Day);
predicate = predicate.Or(p => p.BirthDate == cleanDateTime.ToUniversalTime());
}
var getBirthdays = (from c in orgContext.CreateQuery<Contact>().AsExpandable().Where(predicate)
select c).ToList();
The above query gave me the correct result! Thx to all who helped me!
If c.BirthDate is nullable, you have to convert it to a datetime first:
var getBirthdays = orgContext.CreateQuery<Contact>()
.Where(c => c.BirthDate != null &&
(Convert.ToDateTime(c.BirthDate).Month ==
DateTime.Now.Month) &&
Convert.ToDateTime(c.BirthDate).Day ==
DateTime.Now.Day))
.ToList();
You could fetch this info with a Query, if that is possible in your situation?
//set up the condition + filter
var ce = new Microsoft.Xrm.Sdk.Query.ConditionExpression();
ce.Operator = Microsoft.Xrm.Sdk.Query.ConditionOperator.LastXDays;
ce.AttributeName = "birthdate";
ce.Values.Add(30);
var fe = new Microsoft.Xrm.Sdk.Query.FilterExpression();
fe.AddCondition(ce);
//build query
var query = new Microsoft.Xrm.Sdk.Query.QueryExpression();
query.EntityName = "contact";
query.Criteria.AddFilter(fe);
//get results
var results = CrmHelperV5.OrgProxy.RetrieveMultiple(query);
//if you want early bound entities, convert here.
var contacts = new List<Contact>();
foreach(var result in results.Entities)
{
contacts.Add(result.ToEntity<Contact>());
}
You may want to investigate the other operators for the filters + conditions
You can use QueryExpression (it works for Microsoft CRM Plugin)
public EntityCollection getBirthdateList(IOrganizationService orgsService)
{
List<string> birthdays = new List<string>();
//makes sure no CRM unsupported dates are passed (less than 1/1/1900)
for (int i = Math.Min(140, DateTime.Today.Year - 1930); i > -1; i--)
{
//adds a different date per year
birthdays.Add
(
DateTime.Now.AddYears(-i).ToString("yyyy-MM-dd")
);
}
// Instantiate QueryExpression
var query = new QueryExpression("contact");
// Define filter QEquote.Criteria
var queryfilter = new FilterExpression();
query.Criteria.AddFilter(queryfilter);
// Define filter
queryfilter.FilterOperator = LogicalOperator.Or;
queryfilter.AddCondition("birthdate",ConditionOperator.In,birthdays.ToArray());
return orgsService.RetrieveMultiple(query); ;
}

Can I get values from my database using this method but without generating the additional text?

I am very new to programming and I can't seem to find a way around this. Maybe there is also a better way.
I am trying to get 2 values out of a single row in my database. I have connected to it using EF.
My code is:
using (var myEntities = new dataEntities())
{
var myValues = (from values in myEntities.PointValues
where values.PointID == dataValue && values.DataTime >= fromDate && values.DataTime <= toDate
select new
{ values.DataTime,
values.DataValue
}).ToList();
I then write them to a file with this code:
using (StreamWriter sw = new StreamWriter(#"c:\Test.csv"))
{
for (var i = 0; i < myValues.Count; i++)
{
sw.WriteLine(myValues[i]);
}
}
The problem is the resulting CSV file is like this:
{ DataTime = 1/20/2010 2:15:00 AM, DataValue = 11.72 }
How do I get rid of the { DataTime =, DataValue and the closing }? (DataTime and DataValue are the field labels in the database).
Many thanks for any assistance.
Kind regards,
Julian
You just need to change how you write out the information:
using (var sw = new StreamWriter(#"c:\Test.csv"))
{
foreach(var value in myValues)
{
sw.WriteLine(string.Format("{0}, {1}", value.DataTime, value.DataValue));
}
}
Right now, you're writing out the anonymous class directly, instead of creating the output formatted as needed.
Alternatively, you could build the string directly in your query and write the results easily using:
var myValues = (from values in myEntities.PointValues
where values.PointID == dataValue && values.DataTime >= fromDate && values.DataTime <= toDate
select new
{ values.DataTime,
values.DataValue
})
.AsEnumerable()
.Select(v => string.Format("{0}, {1}", v.DataTime, v.DataValue));
File.WriteAllLines(#"c:\Test.csv", myValues);
This would just build a IEnumerable<string> instead of building the anonymous class.
I would use this approach if you're not using the query results for anything other than writing to the file. If you're using the anonymous class in other code in between, the first is going to keep you from needing to change that code.
Add another select at the end.
var myValues = (from values in myEntities.PointValues
where values.PointID == dataValue
&& values.DataTime >= fromDate
&& values.DataTime <= toDate
select new
{ values.DataTime,
values.DataValue
})
.ToList()
.Select(x => string.Format("{0}, {1}", x.DateTime, x.DataValue);
Additionally, if you don't need bells & whistles of the StreamWriter you could also use File.WriteAllLines():
File.WriteAllLines(#"c:\Test.csv", myValues);
(updated per Reed's post)

Linq to Entities performance problem with many columns

I am having an issue with getting linq to entities to perform well. The query I have (not mine, maintaining someone's code :-)), has several includes that I've determined are all necessary for the WPF screen that consumes the results of this query.
Now, the SQL generated executes very fast and only returns one row of data. But it is returning 570 columns, and i think the performance hit is in the overhead of creating all the objects and all of those fields.
I've tried using lazy loading, but that doesn't seem to have any effect on performance.
I've tried removing any of the "include" statements that aren't necessary, but it appears that they all are needed.
here's the linq query:
var myQuery =
from appt in ctx.Appointments
.Include("ScheduleColumnProfile")
.Include("EncounterReason")
.Include("Visit")
.Include("Visit.Patient")
.Include("Visit.Patient.PatientInsurances")
.Include("Visit.Patient.PatientInsurances.InsuranceType")
.Include("Visit.Patient.PatientInsurances.InsuranceCarrier")
.Include("MasterLookup")
.Include("User1")
.Include("User2")
.Include("Site")
.Include("Visit.Patient_CoPay")
.Include("Visit.Patient_CoPay.User")
.Include("Visit.VisitInstructions.InstructionSheet")
where appt.VisitId == visitId
&& appt.MasterLookup.LookupDescription.ToUpper() != Rescheduled
&& appt.Site.PracticeID == practiceId
&& appt.MasterLookup.LookupDescription.ToUpper() != Cancelled
orderby appt.AppointmentId descending
select appt;
The SQL generate is 4000 lines long with 570 columns in the select statment and 3 or 4 Union ALLs, so I'm not going to paste it here unless someone REALLY wants to see it. Basically, i'm looking for a way to get rid of the unions if possible, and trim down the columns to only what's needed.
Help!
:-)
if anyone is keeping track, this is the solution that ended up working for me. Thanks to everyone who commented and made suggestions... it eventually lead me to what i have below.
ctx.ContextOptions.LazyLoadingEnabled = true;
var myQuery =
from appt in ctx.Appointments
where appt.VisitId == visitId
&& appt.MasterLookup.LookupDescription.ToUpper() != Rescheduled
&& appt.Site.PracticeID == practiceId
&& appt.MasterLookup.LookupDescription.ToUpper() != Cancelled
orderby appt.AppointmentId descending
select appt;
var myAppt = myQuery.FirstOrDefault();
ctx.LoadProperty(myAppt, a => a.EncounterReason);
ctx.LoadProperty(myAppt, a => a.ScheduleColumnProfile);
ctx.LoadProperty(myAppt, a => a.Visit);
ctx.LoadProperty(myAppt, a => a.MasterLookup);
ctx.LoadProperty(myAppt, a => a.User1);
ctx.LoadProperty(myAppt, a => a.User2);
ctx.LoadProperty(myAppt, a => a.PatientReferredProvider);
var myVisit = myAppt.Visit;
ctx.LoadProperty(myVisit, v => v.Patient);
ctx.LoadProperty(myVisit, v => v.Patient_CoPay);
ctx.LoadProperty(myVisit, v => v.VisitInstructions);
ctx.LoadProperty(myVisit, v => v.EligibilityChecks);
var pat = myVisit.Patient;
ctx.LoadProperty(pat, p => p.PatientInsurances);
//load child insurances
foreach (PatientInsurance patIns in myAppt.Visit.Patient.PatientInsurances)
{
ctx.LoadProperty(patIns, p => p.InsuranceType);
ctx.LoadProperty(patIns, p => p.InsuranceCarrier);
}
//load child instruction sheets
foreach (VisitInstruction vi in myAppt.Visit.VisitInstructions)
{
ctx.LoadProperty(vi, i => i.InstructionSheet);
}
//load child copays
foreach (Patient_CoPay coPay in myAppt.Visit.Patient_CoPay)
{
ctx.LoadProperty(coPay, c => c.User);
}
//load child eligibility checks
foreach (EligibilityCheck ec in myAppt.Visit.EligibilityChecks)
{
ctx.LoadProperty(ec, e => ec.MasterLookup);
ctx.LoadProperty(ec, e => ec.EligibilityResponse);
}
I would recommend creating a new Class that contains only the properties that you need to display. When you project to a new type you don't need to have Include statements, but you can still access the navigation properties of the entity.
var myQuery = from appt in ctx.Appointments
where appt.VisitId == visitId
&& appt.MasterLookup.LookupDescription.ToUpper() != Rescheduled
&& appt.Site.PracticeID == practiceId
&& appt.MasterLookup.LookupDescription.ToUpper() != Cancelled
orderby appt.AppointmentId descending
select new DisplayClass
{
Property1 = appt.Prop1,
Proeprty2 = appt.Visit.Prop1,
.
.
.
};

Groupby and where clause in Linq

I am a newbie to Linq. I am trying to write a linq query to get a min value from a set of records. I need to use groupby, where , select and min function in the same query but i am having issues when using group by clause. here is the query I wrote
var data =newTrips.groupby (x => x.TripPath.TripPathLink.Link.Road.Name)
.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link.Speed).Min();
I am not able to use group by and where together it keeps giving error .
My query should
Select all the values.
filter it through the where clause (pathnum).
Groupby the road Name
finally get the min value.
can some one tell me what i am doing wrong and how to achieve the desired result.
Thanks,
Pawan
It's a little tricky not knowing the relationships between the data, but I think (without trying it) that this should give you want you want -- the minimum speed per road by name. Note that it will result in a collection of anonymous objects with Name and Speed properties.
var data = newTrips.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link)
.GroupBy(x => x.Road.Name)
.Select(g => new { Name = g.Key, Speed = g.Min(l => l.Speed) } );
Since I think you want the Trip which has the minimum speed, rather than the speed, and I'm assuming a different data structure, I'll add to tvanfosson's answer:
var pathnum = 1;
var trips = from trip in newTrips
where trip.TripPath.PathNumber == pathnum
group trip by trip.TripPath.TripPathLink.Link.Road.Name into g
let minSpeed = g.Min(t => t.TripPath.TripPathLink.Link.Speed)
select new {
Name = g.Key,
Trip = g.Single(t => t.TripPath.TripPathLink.Link.Speed == minSpeed) };
foreach (var t in trips)
{
Console.WriteLine("Name = {0}, TripId = {1}", t.Name, t.Trip.TripId);
}

Linq To Nhibernate - Separated queries

I've got the following situation:
var totalRecords = (from entry in invalidAccEntryRepository
select entry).Where(entry =>
entry.CustomerAccountInfo.CustomerAccountName == CustomerAccountName &&
entry.CustomerAccountInfo.CustomerAccountId == CustomerAccountId).Count();
vs.
var totalRecords = (from entry in invalidAccEntryRepository
select entry);
if (CustomerAccountInfoFilterActive)
{
totalRecords.Where(entry =>
entry.CustomerAccountInfo.CustomerAccountName == CustomerAccountName &&
entry.CustomerAccountInfo.CustomerAccountId == CustomerAccountId);
}
totalRecordsCount = totalRecords.Count();
The first query works completely but the second query only executes the only
var totalRecords = (from entry in invalidAccEntryRepository
select entry);
and ignores the conditionally added where expression.
Anyone know what the problem could be? Do you need more info?
Thx in advance!
You aren't actually applying the where. In your if, use this instead:
totalRecords = totalRecords.Where(entry =>
entry.CustomerAccountInfo.CustomerAccountName == CustomerAccountName &&
entry.CustomerAccountInfo.CustomerAccountId == CustomerAccountId);

Resources