Get Max value from an Nhibernate IQueryOver - c#

I am working with an NHibernate project that has a method that returns an IQuery object.
I want to find the oldest car with a particular colour.
At the moment it returns the oldest car only if you if you specify the colour correctly (or don't specify it at all).
I can see roughly what I am doing wrong (I am getting the maxAge for the whole table and then adding it as a restriction on the existing IQueryOver).
How do I change the code to get the max age just for existing IQueryOver?
private IQueryOver GetFilteredQuery()
{
var query = Session.QueryOver<Car>();
if (this.Colour != nulI)
{
query.Where(x => x.Colour == this.Colour));
}
if (this.GetOldestCar == true)
{
QueryOver<Car> maxAge= QueryOver.Of<Car>()
.SelectList(c => c.SelectMax(x => x.Age));
query.Where(Subqueries.WhereProperty<Car>(i => i.Age).Eq(maxAge));
}
return query;
}

To get the oldest Car, you may try :
var query = Session.QueryOver<Car>().OrderBy(x=>x.Age).Desc().Take(1);
This would lead to :
private IQueryOver GetFilteredQuery()
{
var query = Session.QueryOver<Car>();
if (this.Colour != null)
{
query.Where(x => x.Colour == this.Colour));
}
if (this.GetOldestCar)
{
query.OrderBy(x=>x.Age).Desc().Take(1)
}
return query;
}

Related

Linq code doesn't return correct record

I have a table named dbo.EmployeeType with three records:
PK_EmployeetypeID EmployeeTypeName
1 Project Manager
2 Business Analyst
3 Developer
I have this piece of Linq code:
public static string GetTypeByID(int id)
{
using (ProjectTrackingEntities1 db = new ProjectTrackingEntities1())
{
var type = db.EmployeeTypes.Select(o => new LOOKUPEmployeeType
{
PK_EmployeeTypeID = id,
EmployeeTypeName = o.EmployeeTypeName
});
return type.FirstOrDefault().EmployeeTypeName;
}
}
No matter what id I send to it, it returns Project Manager, and I'm confused as to why.
You need to apply a filter, otherwise you're just returning the first record and hard coding the ID. Try this:
public static string GetTypeByID(int id)
{
using (ProjectTrackingEntities1 db = new ProjectTrackingEntities1())
{
//Here we apply a filter, the lambda here is what creates the WHERE clause
var type = db.EmployeeTypes
.FirstOrDefault(et => et.PK_EmployeeTypeID == id);
if(type != null)
{
return type.EmployeeTypeName;
}
else
{
return "";
}
}
}
Note that using FirstOrDefault means if there are no matches, or multiple matches, type will be null and you will get an empty string returned.
Set a breakpoint on type = ... and inspect it. You have no Where in there so you get all - and Select just makes LOOKUPEmployeeTypes out of all of them.
FirstOrDefault then returns the first of those 3 which is always the ProjManager
Fix:
var type = db
.EmployeeTypes
.Where( o => o.Id == id)
.Select(o => new LOOKUPEmployeeType
{
PK_EmployeeTypeID = id,
EmployeeTypeName = o.EmployeeTypeName
});
In your code you only return the first value. You need to tell EF which value you need to return.
Let us assume you need the value with Id=2. Instead of Select(), use Single(x => x.Id == 2) or First(x => x.Id == 2).

Distinct() linq query

I am trying to filter my linq query, using distinct() method but I keep getting all the data records (including duplication). I have tried the following variations, which all seem to be failing.
int total = Data.Count();
// Data = Data.GroupBy(member => member.Tag).Select(x => x.OrderBy(y => y.Name).First());
// Data = Data.OrderByDescending(c => c.UploadDate);
Data = Data.Distinct().OrderBy(value => value.Tag);
var data = Data.ToList();
How can I filter my query by showing all the data fieldnames which are filtered by unique tags field name? My tag fieldname does contain NULL data as well.
Here is my entire method, for further reference:
[Authorize]
[HttpPost]
private HttpResponseMessage method(HttpContext request, Query query)
{
if (User.IsInRole("admin") || User.IsInRole("art"))
{
IQueryable<database_B> Data = null;
if (!string.IsNullOrEmpty(query.name))
{
var ids = query.name.Split(',');
// var dataMatchingTags = db.database_B.Where(c => ids.Any(id => c.Name.Contains(id)));
if (Data == null)
Data = dataMatchingTags;
else
Data = Data.Union(dataMatchingTags);
}
if (Data == null) // If no tags or name is being queried, apply filters to the whole set of products
Data = db.database_B;
if (query.endDate != null)
{
Data = Data.Where(c => c.UploadDate <= query.endDate);
}
if (query.startDate != null)
{
Data = Data.Where(c => c.UploadDate >= query.startDate);
}
int total = Data.Count();
// Data = Data.GroupBy(member => member.Tag).Select(x => x.OrderBy(y => y.Name).First());
// Data = Data.OrderByDescending(c => c.UploadDate);
Data = Data.Distinct().OrderBy(value => value.Tag);
var data = Data.ToList();
if (!data.Any())
{
var message = string.Format("No data found");
return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
}
// return Request.CreateResponse(HttpStatusCode.OK, data);
return Request.CreateResponse(HttpStatusCode.OK, new { total, data });
}
Thank you for any further help.
You need something like that ?
http://www.codeproject.com/Articles/535374/DistinctBy-in-Linq-Find-Distinct-object-by-Propert
If database_B is a class (as opposed to a struct) which does not implement IEquatable<database_B> in a suitable way, Distinct will treat different objects as different, regardless of member values. A possible solution would be to implementet IEquatable<database_B> to reflect the comparision which is desired for equality.
Alternatively, a different overload of Distinct can be used, where it is possible to give a custom comparision as an argument.
Your class database_B has to implement Equals- and GetHashCode-Method in order to tell the Distinct under which circumstances two instances are considered equal and may therefor be filtered out.

Linq Method Error IOrderedQueryable

I have a database with a specific id with recorded Time's, I need help on trying to figure out time gap's between an ID's time's e.g 13:05:15 and 13:05:45 though if the time gap is over 10/15 seconds it needs to be recorded so it can be used in say a text file/other data etc. I previously asked a similar question on here, here is what my code looks like so far:
This class is used to manipulate data through the linq var being queried/looped
public class Result
{
public bool LongerThan10Seconds { get; set; }
public int Id { get; set; }
public DateTime CompletionTime { get; set; }
}
This is the foor loop within a separate class which was my original idea
using (var data = new ProjectEntities())
{
Result lastResult = null;
List<Result> dataResults = new List<Result>();
foreach(var subResult in data.Status.Select(x => x.ID).Distinct().Select(Id => data.Status.Where(x => x.ID == Id).OrderBy(x => x.Time)))
{
if (lastResult != null)
{
if (subResult.CompletionTime.Subtract(lastResult.CompletionTime).Seconds > 10)
dataResults.Add(subResult);
}
lastResult = subResult;
}
Which I got the error:
Linq.IOrderedQueryAble does not contain a definition for 'CompletionTime' and no Extension method 'CompletionTime' accepting a first argument of type 'System.Linq.IOrderedQueryable.
I changed the for loop to use an object of the manipulation class
foreach(Result subResult in data.AssetStatusHistories.Select(x => x.ID).Distinct().SelectMany(Id => data.AssetStatusHistories.Where(x => x.ID == Id).OrderBy(x => x.TimeStamp)))
{
if (lastResult != null)
{
if (subResult.CompletionTime.Subtract(lastResult.CompletionTime).Seconds > 10)
{
vehicleResults.Add(subResult);
}
}
lastResult = subResult;
}
Though now I get the error: Cannot convert type 'Project.Status' to 'Project.Result'
Does anyone possibly have a solution to get around this I have looked through a few resources but haven't been able to find anything of helps also even on Microsoft's Linq Forum. Any help is much appreciated ! :)
Try adding .ToList() to the end of your LINQ statement, after OrderBy:
var results = data.Status.Select(x => x.ID).Distinct()
.Select(Id => data.Status.Where(x => x.ID == Id)
.OrderBy(x => x.Time)
.ToList();
foreach(var subResult in results))
{
...
}
Also, I think you could modify your LINQ to do a GroupBy of the ID column, but that's something you could do research on if you wish. (Tutorial)
Your linq query (in the second try) will return an IEnumerable of whatever is the element type of data.AssetStatusHistories. I assume this is some kind of IEnumerable<Project.Status>, so you're in fact trying to assign Project.Status objects to an iterator variable (subResult) of type Result, which is why you're getting the error Cannot convert type 'Project.Status' to 'Project.Result'.
So your problem is not really in the linq query, you just need a way to convert your Project.Status objects to Project.Result objects.

Matching on search attributes selected by customer on front end

I have a method in a class that allows me to return results based on a certain set of Customer specified criteria. The method matches what the Customer specifies on the front end with each item in a collection that comes from the database. In cases where the customer does not specify any of the attributes, the ID of the attibute is passed into the method being equal to 0 (The database has an identity on all tables that is seeded at 1 and is incremental). In this case that attribute should be ignored, for example if the Customer does not specify the Location then customerSearchCriteria.LocationID = 0 coming into the method. The matching would then match on the other attributes and return all Locations matching the other attibutes, example below:
public IEnumerable<Pet> FindPetsMatchingCustomerCriteria(CustomerPetSearchCriteria customerSearchCriteria)
{
if(customerSearchCriteria.LocationID == 0)
{
return repository.GetAllPetsLinkedCriteria()
.Where(x => x.TypeID == customerSearchCriteria.TypeID &&
x.FeedingMethodID == customerSearchCriteria.FeedingMethodID &&
x.FlyAblityID == customerSearchCriteria.FlyAblityID )
.Select(y => y.Pet);
}
}
The code for when all criteria is specified is shown below:
private PetsRepository repository = new PetsRepository();
public IEnumerable<Pet> FindPetsMatchingCustomerCriteria(CustomerPetSearchCriteria customerSearchCriteria)
{
return repository.GetAllPetsLinkedCriteria()
.Where(x => x.TypeID == customerSearchCriteria.TypeID &&
x.FeedingMethodID == customerSearchCriteria.FeedingMethodID &&
x.FlyAblityID == customerSearchCriteria.FlyAblityID &&
x.LocationID == customerSearchCriteria.LocationID )
.Select(y => y.Pet);
}
I want to avoid having a whole set of if and else statements to cater for each time the Customer does not explicitly select an attribute of the results they are looking for. What is the most succint and efficient way in which I could achieve this?
Criteria that are not selected are always zero, right? So how about taking rows where the field equals the criteria OR the criteria equals zero.
This should work
private PetsRepository repository = new PetsRepository();
public IEnumerable<Pet> FindPetsMatchingCustomerCriteria(CustomerPetSearchCriteria customerSearchCriteria)
{
return repository.GetAllPetsLinkedCriteria()
.Where(x => (customerSearchCriteria.TypeID == 0 || x.TypeID == customerSearchCriteria.TypeID)&&
(customerSearchCriteria.FeedingMethodID == 0 || x.FeedingMethodID == customerSearchCriteria.FeedingMethodID) &&
(customerSearchCriteria.FlyAblityID == 0 || x.FlyAblityID == customerSearchCriteria.FlyAblityID) &&
(customerSearchCriteria.LocationID == 0 || x.LocationID == customerSearchCriteria.LocationID))
.Select(y => y.Pet);
}
Alternatively, if this is something you find yourself doing alot of, you could write an alternate Where extension method that either applies the criteria or passes through if zero, and chain the calls instead of having one condition with the criteria anded. Then you'd do the comparision for the criteria == 0 just once per query, not for every unmatched row. I'm not sure that it's worth the - possible - marginal performance increase, you'd be better off applying the filters in the database if you want a performance gain.
Here it is anyway, for the purposes of edification . . .
static class Extns
{
public static IEnumerable<T> WhereZeroOr<T>(this IEnumerable<T> items, Func<T, int> idAccessor, int id)
{
if (id == 0)
return items;
else
return items.Where(x => idAccessor(x) == id);
}
}
private PetsRepository repository = new PetsRepository();
public IEnumerable<Pet> FindPetsMatchingCustomerCriteria(CustomerPetSearchCriteria customerSearchCriteria)
{
return repository.GetAllPetsLinkedCriteria()
.WhereZeroOr(x => x.TypeID, customerSearchCriteria.TypeID)
.WhereZeroOr(x => x.FeedingMethodID, customerSearchCriteria.FeedingMethodID)
.WhereZeroOr(x => x.FlyAblityID, customerSearchCriteria.FlyAblityID)
.WhereZeroOr(x => x.LocationID, customerSearchCriteria.LocationID);
}
Looks like you're using a stored procedure and you're getting all records first and then doing your filtration. I suggest you filter at the stored procedure level, letting the database do the heavy lifting and any micro filtration that you need to do afterwords will be easier. In your sproc, have your params default to NULL and make your properties nullable for the criteria object so you can just pass in values and the sproc will(should) be corrected to work with these null values, i.e.
private PetsRepository repository = new PetsRepository();
public IEnumerable<Pet> FindPetsMatchingCustomerCriteria(CustomerPetSearchCriteria customerSearchCriteria)
{
return repository.GetAllPetsLinkedCriteria(customerSearchCriteria.TypeID,customerSearchCriteria.FeedingMethodID,customerSearchCriteria.FlyAblityID,customerSearchCriteria.LocationID).ToList();
}
I'm not seeing an elegant solution. May be this:
IEnumerable<Pet> FindPetsMatchingCustomerCriteria(CustomerPetSearchCriteria customerSearchCriteria)
{
return repository.GetAllPetsLinkedCriteria()
.Where(x =>
Check(x.TypeID, customerSearchCriteria.TypeID) &&
Check(x.FeedingMethodID, customerSearchCriteria.FeedingMethodID) &&
Check(x.FlyAblityID, customerSearchCriteria.FlyAblityID) &&
Check(x.LocationID, customerSearchCriteria.LocationID))
.Select(x => x.Pet);
}
static bool Check(int petProperty, int searchCriteriaProperty)
{
return searchCriteriaProperty == 0 || petProperty == searchCriteriaProperty;
}

How can I make this LINQ query?

I have a Dropdownlist that I fill with all consultants.
This is my entities I am using for this LINQ query:
What I want to do is to get all consultants ids that have a goalcard with Complete_date set. I have no idea how to do this.
Right now I have this following LINQ query to get all consultants ids.
public List<Consultant> GetAllConsultantsByID()
{
var allConsultants = from id in db.Consultant
select id;
return allConsultants.ToList();
}
Any kind of help is appreciated
Thanks in advance
Update:
This is how I have to use my Linq method in my Get Action Method:
var consultants = repository.GetAllConsultantsByID();
model.Consultants = new SelectList(consultants, "Id", "Name");
You can use the Consultant.GoalCard navigation property and the Any extension method:
var query = from con in db.Consultant
where con.GoalCard.Any(card => card.Completed_Date != null)
select con;
return query.ToList();
Consultant.Goalcard exposes all GoalCards of the Consultant as a queryable property. So you can perform queries on that, too. (This example assumes Completed_Date is nullable)
Note: Seeing that a Consultant can have several GoalCards, you might want to rename the Consultant's GoalCard navigation property to GoalCards (to make it clear there can be several).
Now assuming the Complete_Date is of type DateTime?, you could do it like that:
public IEnumerable<Consultant> GetConsultantIds()
{
return db.Consultant.Where(c => c.GoalCard != null && c.GoalCard.Completed_Date.HasValue).Select(c => c.Id).AsEnumerable();
}
[EDIT]
Since GoalCard is a collection (misleading name :) ), you can do something like that to get the IDs of Consultants who have at least one completed date set on any of the cards:
public IEnumerable<int> GetConsultantIds()
{
return db.Consultant.Where(c => c.GoalCard != null && c.GoalCard.Any(card => card.Completed_Date.HasValue)).Select(c => c.Id).AsEnumerable();
}
That's for the list of IDs only, for the list of Consultant objects meeting the criteria:
public IEnumerable<Consultant> GetConsultantIds()
{
return db.Consultant.Where(c => c.GoalCard != null && c.GoalCard.Any(card => card.Completed_Date.HasValue)).AsEnumerable();
}

Categories

Resources