In HqlNamedParams if where condition does not yield result fetch all rows - hql

StringBuilder query = new StringBuilder("from country ");
query.append("and stateId in (:stateId)");
hqlNamedParam.addParamAndValue("stateId", values);
Here if "values" doesn't exist in table, fetch all rows.
How do I do it?

I've misunderstood the question, now I edit my answer:
You must run two queries.
// The first:
StringBuilder query = new StringBuilder("from country ");
query.append("and stateId in (:stateId)");
hqlNamedParam.addParamAndValue("stateId", values);
// The second (only if the first doesn't return rows)
if (outList == null || outList.size == 0) {
StringBuilder query2 = new StringBuilder("from country ");
}
Alternatively (but you use more subqueries with count)
StringBuilder query = new StringBuilder("from country ");
query.append(" where
(select count(c2.id) from country c2 where c2.stateid in (:stateId)) > 0
and cs.stateid in (:stateId)
or (select count(c3.id) from country c3 where c3.stateid in (:stateId)) = 0");
hqlNamedParam.addParamAndValue("stateId", values);

Related

Linq Sql Query Error for Get value

Here is my linq query for get Qty and Number from first collection Qty - Second Collection Qty and first collection Number - Second Collection Number, Some times First collection RM not contain second colection
var summary = (from r in firstCollection
join s in secondCollection
on new { r.RM, r.Size } equals new { s.RM, s.Size }
group new { r, s } by new { RM = r.RM, Size = s.Size, Qty = (r.Qty - s.Qty), Number = (r.Number - s.Number) }
into grp
select new
{
RM = grp.Key.RM,
RMsize = grp.Key.Size,
Qty = grp.Key.Qty,
Number = grp.Key.Number
}).ToList();
there is an error like
Additional information: A group by expression can only contain
non-constant scalars that are comparable by the server. The expression
with type 'Manufacturing.DataAccess.tbl_RawMaterial' is not
comparable.
How can i solve this ?
You can project to anonymous type first and then do a grouping. Try this:
var summary = (from r in firstCollection
join s in secondCollection
on new { r.RM, r.Size } equals new { s.RM, s.Size }
select new
{
RM = r.RM,
Size = s.Size,
Qty = (r.Qty - s.Qty),
Number = (r.Number - s.Number)
} into tmp
group tmp by new
{
RM,
Size,
Qty,
Number
} into grp
select new
{
RM = grp.Key.RM,
RMsize = grp.Key.Size,
Qty = grp.Key.Qty,
Number = grp.Key.Number
}).ToList();
Looks like the problem is RM member which I assume is some navigation property of type Manufacturing.DataAccess.tbl_RawMaterial. As the exception message states, you can only group by simple properties.
Let say your entity Manufacturing.DataAccess.tbl_RawMaterial primary key is called Id (you can replace it with the actual name). Then the query could be something like this
var summary =
(from r in firstCollection
join s in secondCollection
on new { r.RM.Id, r.Size } equals new { s.RM.Id, s.Size }
group new { r, s }
by new { Id = r.RM.Id, Size = s.Size, Qty = (r.Qty - s.Qty), Number = (r.Number - s.Number) }
into grp
select new
{
RM = grp.FirstOrDefault(e => e.r),
RMsize = grp.Key.Size,
Qty = grp.Key.Qty,
Number = grp.Key.Number
}).ToList();

Link OrderBy method not taking effect after Union method

I'm using LINQ's Union method to combine two or more collections. After that I'm trying to apply sorting to the combined collection by calling OrderBy on a field that is common to the collections. Here is how I am applying sorting:
combinedCollection.OrderBy(row => row["common_field"]);
combinedCollection is defined as:
Enumerable<DataRow> combinedCollection;
I need the sorting to be applied to the entire combined collection. For some reason, that is not happening. Instead I see there is sorting applied on some other field separately within each 'collection' block within the combined collection
And idea why??
First Edit
foreach (....)
{
if (combinedCollection != null)
{
combinedCollection = combinedCollection.Union(aCollection);
}
else
{
combinedCollection = aCollection;
}
}
Second Edit
_Cmd.CommandText = "SELECT Person.Contact.FirstName, Person.Contact.LastName, Person.Address.City, DATEDIFF(YY, HumanResources.Employee.BirthDate, GETDATE()) AS Age"
+ " FROM HumanResources.EmployeeAddress INNER JOIN"
+ " HumanResources.Employee ON HumanResources.EmployeeAddress.EmployeeID = HumanResources.Employee.EmployeeID INNER JOIN"
+ " Person.Address ON HumanResources.EmployeeAddress.AddressID = Person.Address.AddressID INNER JOIN"
+ " Person.Contact ON HumanResources.Employee.ContactID = Person.Contact.ContactID AND HumanResources.Employee.ContactID = Person.Contact.ContactID AND "
+ " HumanResources.Employee.ContactID = Person.Contact.ContactID AND HumanResources.Employee.ContactID = Person.Contact.ContactID";
DataTable employeeTable = new DataTable();
_Adpt.Fill(employeeTable);
DataRow[] allRows = null;
allRows = employeeTable.Select("");
IEnumerable<DataRow> filteredEmployeeRows;
filteredEmployeeRows = from row in allRows select row;
// Declare a variable to hold the city-filtered rows and set it to null for now
IEnumerable<DataRow> cityFilteredEmployeeRows = null;
//Copy filtered rows into a data table
DataTable filteredEmployeeTable = filteredEmployeeRows.CopyToDataTable<DataRow>();
foreach (DataRowView city in CityListBox.SelectedItems)
{
// create an exact copy of the data table
DataTable filteredEmployeeCopyTable = filteredEmployeeTable.Copy();
// Enumerate it
IEnumerable<DataRow> filteredEmployeeRowsInSingleCity = filteredEmployeeCopyTable.AsEnumerable();
// Apply the city filter
filteredEmployeeRowsInSingleCity = _ApplyCityFilter(filteredEmployeeRowsInSingleCity, city["City"].ToString());
if (cityFilteredEmployeeRows != null)
{
// Combine the filtered rows for this city with the overall collection of rows
cityFilteredEmployeeRows = cityFilteredEmployeeRows.Union(filteredEmployeeRowsInSingleCity);
}
else
{
cityFilteredEmployeeRows = filteredEmployeeRowsInSingleCity;
}
}
//apply ordering
cityFilteredEmployeeRows.OrderBy(row => row["Age"]);
//cityFilteredEmployeeRows.OrderByDescending(row => row["Age"]);
EmployeeGridView.DataSource = cityFilteredEmployeeRows.CopyToDataTable<DataRow>();
.......
private IEnumerable<DataRow> _ApplyCityFilter(IEnumerable<DataRow> filteredEmployeeRows, string city)
{
IEnumerable<DataRow> temp = filteredEmployeeRows;
filteredEmployeeRows = from row in temp
where row["City"].ToString() == city
select row;
return filteredEmployeeRows;
}
I think you have a problem with the LINQ lazy evaluation, I would have to investigate to find out wich part causes the problem.
Using the foreach(var item...) in lazy functions has already bitten me (because when executed later they all reference the last iterated item), but in your case it doesn't look like this is the problem.
To check it is the really the issue you can just use a DataRow[] in place of the IEnumerable<DataRow> and call .ToArray() after every LINQ function.
Edit: I'm not sure I got your code right but can't you just use:
var cities = CityListBox.SelectedItems.Cast<DataRowView>()
.Select(city => city["City"].ToString())
.ToArray();
var rows = allRows
.Where(r => cities.Contains((string)r["City"]))
.OrderBy(r => (int?)r["Age"])
.ToArray(); // if you want to evaluate directly, not mandatory

need to return the first record linq

I need to return only the first record. Although I had to put the z.FirstOrDefault(); still more than one were displayed
public DataTable GetDependents(string EmployeeID)
{
HealthCareSystem.DataClassesDataContext db = new HealthCareSystem.DataClassesDataContext();
var z = (from s in db.SelectingDependentsGroupBies
where s.EmployeeID.Equals(EmployeeID)
join d in db.Dependents on s.DependentID equals d.DependentID
orderby s.DependentID descending
//Selecting wanted tables dependents fields by datatable
select new DependentsX { DependentID = Convert.ToInt32(s.DependentID), EmployeeID = s.EmployeeID, Name = s.Name, Surname = s.Surname, IDCardNo = s.IDCardNo, ContactNo = s.ContactNo, BirthDate = s.BirthDate, StartSchemeDate = s.StartDate, EndSchemeDate = s.EndDate, RelationType = s.Type, Payment = Convert.ToDouble(d.Payment), });
var firstRecord = z.FirstOrDefault();
Add this line after your existing code:
var firstRecord = x.First();
If there might be zero results and you don't want an exception then you can use FirstOrDefault instead.
var firstRecord = x.FirstOrDefault();
Another common way is to enclose your query in parenthesis and then include the extension methods outside the parenthesis:
var x = (from d in db.DependentsRelationsViews
where d.IDCardNo.Equals(DepID)
orderby d.DependentID descending
select new DependentsX
{
DependentID = Convert.ToInt32(d.DependentID),
EmployeeID = d.EmployeeID,
Name = d.Name,
Surname = d.Surname,
IDCardNo = d.IDCardNo,
ContactNo = d.ContactNo,
BirthDate = d.BirthDate,
StartSchemeDate = Convert.ToDateTime(d.StartSchemeDate),
EndSchemeDate = d.EndSchemeDate,
Payment = d.Payment,
RelationType = Convert.ToString(d.Type)
}).FirstOrDefault();
If you don't enclose it in parenthesis and try to call FirstOrDefault() then you're applying that extension to the anonymous type in just the very last Select clause. By enclosing the whole query in parenthesis and then calling the FirstOrDefault() extension, you're indicating to the compiler that you wish to apply it to the return value of your entire query, which will be the IEnumerable<> or IQueryable<> collection.

How can I define a List to add results of a query in a loop?

I have an array filled with long type values and for each value in the array I need to implement a query. I used foreach loop as you can see from the code below:
var result;
foreach(long id in PrdIdArr)
{
var mainQuery = (from o in db.OPERATIONs
join u in db.UNITs on o.OP_UNIT_ID equals u.UNIT_ID into smt
from s in smt
join x in db.XIDs on s.UNIT_ID equals x.UNIT_ID
where o.OP_OT_CODE == OtCode
where x.IDTYP_CD == "BSN"
where s.START_PRD_ID == id
where o.OP_UPD_DATE >= _StartDate
where o.OP_UPD_DATE <= _EndDate
select new
{
o.OP_ID,
o.OP_UPD_DATE,
x.EXTERNAL_ID,
o.OP_OS_CODE,
o.OP_START,
o.OP_ST_STATION,
s.START_PRD_ID
}).Take(_RowNumber);
//var result = mainQuery.ToList();
result.add(mainQuery.ToList());
}
data = this.Json(result);
data.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return data;
However, I have a problem in my code; I have to define a main list just before the foreach loop so that I could add results of each query to the that main list. my question is: How can I define this list as you can see at the beginning of my code? Thanks for the help...
How can I define this list as you can see at the beginning of my code?
Make
new {
o.OP_ID,
o.OP_UPD_DATE,
x.EXTERNAL_ID,
o.OP_OS_CODE,
o.OP_START,
o.OP_ST_STATION,
s.START_PRD_ID
}
into a concrete type (say QueryResult, although something a little more specific than that), and then just declare
var result = new List<QueryResult>();
Also, you should consider turning
foreach(long id in PrdIdArr)
and
where s.START_PRD_ID == id
into
where PrdIdArr.Contains(s.Start_PRD_ID)
var result = new List<object>();
foreach(long id in PrdIdArr)
{
....
result.Add(mainQuery.ToList());
}
You could do this:
var result = PrdIdArr.Select(id =>
from o in db.OPERATIONs
join u in db.UNITs on o.OP_UNIT_ID equals u.UNIT_ID into smt
from s in smt
join x in db.XIDs on s.UNIT_ID equals x.UNIT_ID
where o.OP_OT_CODE == OtCode
where x.IDTYP_CD == "BSN"
where s.START_PRD_ID == id
where o.OP_UPD_DATE >= _StartDate
where o.OP_UPD_DATE <= _EndDate
select new
{
o.OP_ID,
o.OP_UPD_DATE,
x.EXTERNAL_ID,
o.OP_OS_CODE,
o.OP_START,
o.OP_ST_STATION,
s.START_PRD_ID
}
.Take(_RowNumber)
.ToList()
).ToList();
I highly recommend performing some Extract Method refactorings, as the code is pretty complex and hard to understand/mange this way.
Just create the anonymous type outside with the same property names and the correct type
var result = Enumerable.Range(0, 0).Select(x => new
{
OP_ID = 1,
OP_UPD_DATE = DateTime.Now,
EXTERNAL_ID = 1,
OP_OS_CODE = 1,
OP_START = DateTIme.Now,
OP_ST_STATION = "",
START_PRD_ID = 1,
}).ToList();
And in your loop call AddRange
result.AddRange(mainQuery.ToList());

Conditional Multiple Fields Searching and Filtering in LINQ

Assuming that we have the following table:
Person:
PersonID,
Name,
Age,
Gender
And we are providing a search function that allows users to search the table according to the name and/or the age.
The tricky part in writing the SQL ( or LINQ) query is that the users can choose to search for both field, or any one field, or no field. If he wants to search for all then he would just have to leave the textbox blank.
The logic to do this can be written as follows:
var p;
if(Name_TextBox=='')
{
p=from row in person
select row ;
}
else
{
p= from row in person
where row.Name=Name_TextBox
select row ;
}
// repeat the same for age
Now after a while the code gets very long and messy... How can I compress the above into a single query with no if-else?
Try code like this
string personName = txtPersonName.Text;
int personAge = Convert.ToInt32(txtAge.Text);
var opportunites = from p in this.DataContext.Persons
select new
{
p.PersonID,
p.Name,
p.Age,
p.Gender
};
if (personsID != 0)
opportunites = opportunites.Where(p => p.PersonID == personID);
if (personName != string.Empty)
opportunites = opportunites.Where(p => p.Name.StartsWith(personName));
if (personAge != 0)
opportunites = opportunites.Where(p => p.Age == personAge);
This will work fine. If personName is not given it will be not add to where, and if given then it will added.
One alternative which I have used in SQL which could be implemented in Linq too is
var p = from p in Person
where p.Name == Name_TextBox || Name_TextBox == String.Empty
select p;
(Note that your 'linq' is using SQL syntax, which won't compile. Also you can't declare a var as you are doing without directly assigning a value)
why not use the null coalescing operator? eg.
var products = from a in context.products
where a.ID == (productID ?? a.ID)
select a;
This works really well on my system

Resources