linq conditional query - c#

What would be the best practice for setting a status depending on several other "columns" retrieved in a linq query.
var result = (from q in query
select new Item
{
ApprovedDate = q.ApprovedDate,
CreatedDate = q.CreatedDate,
DeclinedDate = q.DeclinedDate,
Status = 0
});
I'd like to set the status to either 0, 1, 2.
(ApprovedDate == null and DeclinedDate == null) --> 0
(ApprovedDate != null and DeclinedDate == null) --> 1
(DeclinedDate != null) --> 3
So perhaps something like:
var result = (from q in query
select new Item
{
ApprovedDate = q.ApprovedDate,
CreatedDate = q.CreatedDate,
DeclinedDate = q.DeclinedDate,
Status = (q.CreatedDate == null && q.DeclinedDate == null) ? 0 : (q.ApprovedDate != null && q.DeclinedDate == null) ? 1 : 2
});
I might add even more status combinations, so should I try and do this in the linq select query, in my repository object.. Or later on in the controller where I would do a .ToList() and then foreach the list to set the correct status code?
Having even more than 3 statuscodes, the linq query gets "hard" to read.

What about moving status calculation to Item class? If status property depends on other properties value, then it's definitely calculated property:
var result = from q in query
select new Item
{
ApprovedDate = q.ApprovedDate,
CreatedDate = q.CreatedDate,
DeclinedDate = q.DeclinedDate
});
And
public class Item
{
// other properties
public int Status
{
get
{
if (ApprovedDate == null and DeclinedDate == null)
return 0;
if (ApprovedDate != null and DeclinedDate == null)
return 1;
if (DeclinedDate != null)
return 3;
// etc
}
}
}
Actually I think it's best option, because in this case status calculation logic will be close to required data. If (for some reason) you can't use this approach, then move setting statuses to local items collection:
var items = result.ToList().ForEach(i => i.Status = CalculateStatus(i));

Maybe wrapped all in a function An do a linq like this
var result = (from q in query sele q).AsEnumerable()
.Select( x => new Item()
{
ApprovedDate = x.ApprovedDate,
CreatedDate = x.CreatedDate,
DeclinedDate = x.DeclinedDate,
Status = MyStatusFunction(x.CreatedDate,q.DeclinedDate)
});
public int MyStatusFunction(DateTime ApprovedDate , Datetime DeclinedDate)
{
if (ApprovedDate == null and DeclinedDate == null) return 0;
else if(ApprovedDate != null and DeclinedDate == null) return 1;
else if (DeclinedDate != null) return 3;
}

Related

How can I make the system empty value from the guid null?

In the Build Query I have a query like this:
var characteristicPrices = await scope.BuildQuery<CharacteristicPrice, CharacteristicVersion, CharacteristicPrice>((op, ccp, cv) => op.Select(op.AllColumnsOf(ccp))
.InnerJoin<CharacteristicVersion>(cv.Id == ccp.CharacteristicVersionId)
.Where(ccp.CountryId == request.CountryId && cv.VersionId == request.VersionId)).Get();
Here the request.CountryId field comes to me as "000000...". but my query is not working correctly because its equivalent is null in the database. How can I set this value to null?
You can either directly pass null to the query instead of Guid.Empty or you could modify your condition:
Either...
Guid? id = request.CountryId;
if (id==Guid.Empty)
{
id = null;
}
var characteristicPrices = await scope.BuildQuery<CharacteristicPrice, CharacteristicVersion, CharacteristicPrice>((op, ccp, cv) => op.Select(op.AllColumnsOf(ccp))
.InnerJoin<CharacteristicVersion>(cv.Id == ccp.CharacteristicVersionId)
.Where(ccp.CountryId == id && cv.VersionId == request.VersionId)).Get();
...or...
var characteristicPrices = await scope.BuildQuery<CharacteristicPrice, CharacteristicVersion, CharacteristicPrice>((op, ccp, cv) => op.Select(op.AllColumnsOf(ccp))
.InnerJoin<CharacteristicVersion>(cv.Id == ccp.CharacteristicVersionId)
.Where((ccp.CountryId == request.CountryId || (request.CountryId==Guid.Empty && ccp.CountryId=null)) && cv.VersionId == request.VersionId)).Get();

How to overcome foreach loop for list object dynamically

I'm swapping my values in List Object on some conditions and update List Object value.
Currently, what I'm doing is
- Looping on each object through List
- Check If condition is net
- Swap values
public static void SwapMinMaxIfNull<T>(this IEnumerable<T> rows, string reportfor)
{
if (reportfor.Equals("Comparison"))
{
var row = rows as IEnumerable<RiskBoardDataToExport>;
try
{
if (rows.Any())
{
var Tests = row.Where(min => min.MinGaitSpeed == null && min.MaxGaitSpeed != null).ToList();
if (Tests != null)
{
foreach (RiskBoardDataToExport test in Tests)
{
test.MinGaitSpeed = test.MaxGaitSpeed;
test.MaxGaitSpeed = null;
}
}
// again check for next object
Tests = row.Where(min => min.MinTUGTime == null && min.MaxTUGTime != null).ToList();
if (Tests != null)
{
foreach (RiskBoardDataToExport test in Tests)
{
test.MinTUGTime = test.MaxTUGTime;
test.MaxTUGTime = null;
}
}
// again check for next object
Tests = row.Where(min => min.MinBergScoreSpeed == null && min.MaxBergScoreSpeed != null).ToList();
if (Tests != null)
{
foreach (RiskBoardDataToExport test in Tests)
{
test.MinBergScoreSpeed = test.MaxBergScoreSpeed;
test.MaxBergScoreSpeed = null;
}
}
//.. for brevity
}
}
}
Can I do it in better way? I know about PropertyInfo i.e. Can check property name and get value etc, but, not having any hint to get this done.
Thanks
It's not exactly what you're asking for, but you can combine the clauses in your Where statements and then have a few if statements in the body:
public static void SwapMinMaxIfNull(this IEnumerable<RiskBoardDataToExport> rows,
string reportfor)
{
if (rows = null) return;
if (reportfor.Equals("Comparison", StringComparison.OrdinalIgnoreCase))
{
foreach (var row in rows.Where(r =>
(r.MinGaitSpeed == null && r.MaxGaitSpeed != null) ||
(r.MinBergScoreSpeed == null && r.MaxBergScoreSpeed != null) ||
(r.MinBergScoreSpeed == null && r.MaxBergScoreSpeed != null)))
{
if (row.MinGaitSpeed == null)
{
row.MinGaitSpeed = row.MaxGaitSpeed;
row.MaxGaitSpeed = null;
}
if (row.MinTUGTime == null)
{
row.MinTUGTime = row.MaxTUGTime;
row.MaxTUGTime = null;
}
if (row.MinBergScoreSpeed == null)
{
row.MinBergScoreSpeed = row.MaxBergScoreSpeed;
row.MaxBergScoreSpeed = null;
}
}
}
}
As this is an operation where order of the items in the list does not matter, you can easily speed this up by parallelization (you can read up on that here).
So, what you should do, is handle this foreach loop in a parallel way and combine it with Rufus L's optimized code for the fastest result.
var rows = rows.Where(r =>
(r.MinGaitSpeed == null && r.MaxGaitSpeed != null) ||
(r.MinBergScoreSpeed == null && r.MaxBergScoreSpeed != null) ||
(r.MinBergScoreSpeed == null && r.MaxBergScoreSpeed != null))
Parallel.ForEach(rows, (row) => {
{
if (row.MinGaitSpeed == null)
{
row.MinGaitSpeed = row.MaxGaitSpeed;
row.MaxGaitSpeed = null;
}
if (row.MinTUGTime == null)
{
row.MinTUGTime = row.MaxTUGTime;
row.MaxTUGTime = null;
}
if (row.MinBergScoreSpeed == null)
{
row.MinBergScoreSpeed = row.MaxBergScoreSpeed;
row.MaxBergScoreSpeed = null;
}
}
Note that this requires the System.Threading.Tasks namespace, that's where the Parallel class is.

Can't implicity convert type 'string' error

I updated my code this but I always get a '0' value for REQ_INSP_APPROVAL field regardless. When a name should be value of 1 for that field and it still shows as 0:
W_USER usr = new W_USER
{
Name = Convert.ToString(dgvMaster.CurrentRow.Cells [dgvMaster.CurrentCell.ColumnIndex].Value)
};
//WINS_USER usr = Convert.ToString(o);
//IQueryable<WINS_USER> users = dc.CMB_USERs;
showLegend = loadedReports.Where(f => f.form.EXEMPTFROMIP == 0 && f.form.FORMHEADER.INSPAPPROVALPROCESS == 1 && f.form.SUPERAPPROVED == 1 && usr.REQ_INSP_APPROVAL == 1).Count() > 0;I updated the code to this:
if (dgvMaster.CurrentRow == null)
return;
object o = dgvMaster.CurrentRow.Cells[dgvMaster.CurrentCell.ColumnIndex].Value;
// Error on the following line
W_USER usr = Convert.ToString(dgvMaster.CurrentRow.Cells[dgvMaster.CurrentCell.ColumnIndex].Value);
showLegend = loadedReports.Where(f => f.form.EXEMPTFROMIP == 0 &&
f.form.FORMHEADER.INSPAPPROVALPROCESS == 1 &&
f.form.SUPERAPPROVED == 1 &&
usr.REQ_INSP_APPROVAL == 1)
.Count() > 0;
Also in my designer class file I updated the REQ_INSP_APPROVAL from this
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_REQ_INSP_APPROVAL", DbType="Int")]
public System.Nullable<int> REQ_INSP_APPROVAL
{
get
{
return this._REQ_INSP_APPROVAL;
}
set
{
if ((this._REQ_INSP_APPROVAL != value))
{
this.OnREQ_INSP_APPROVALChanging(value);
this.SendPropertyChanging();
this._REQ_INSP_APPROVAL = value;
this.SendPropertyChanged("REQ_INSP_APPROVAL");
this.OnREQ_INSP_APPROVALChanged();
}
}
}
to
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_REQ_INSP_APPROVAL", DbType="Int")]
public int REQ_INSP_APPROVAL
{
get
{
return this._REQ_INSP_APPROVAL;
}
set
{
if ((this._REQ_INSP_APPROVAL != value))
{
this.OnREQ_INSP_APPROVALChanging(value);
this.SendPropertyChanging();
this._REQ_INSP_APPROVAL = value;
this.SendPropertyChanged("REQ_INSP_APPROVAL");
this.OnREQ_INSP_APPROVALChanged();
}
}
}
Before updating I was getting null for the REQ_INSP_APPROVAL now I'm getting as I stated '0'.
I know this is a lot but I really need help.
What is W_USER? Seems like W_USER is a class and you are trying to store a string value in the object of the class. That's why it is throwing you error. store below in a string variable.
W_USER usr=new W_USER(); usr.Name=Convert.ToString(dgvMaster.CurrentRow.Cells[dgvMaster.CurrentCell.ColumnIndex].Value);

Generic filtering on query string parameters

I'm looking to convert our current API architecture to a more generic query-able structure that doesn't require us to hard card each possible parameter and build up a custom query. Here is an example of what our current architecture looks like,
[HttpGet]
[Route("Companies/{id:int}/Implementations/Tasks")]
public async Task<IApiResponse<List<CompanyIPTDTO>>> GetCompanyIPTs(int? id = null,
int? taskId = null, int? completedById = null, DateTime? dateCompletedStart = null,
DateTime? dateCompletedEnd = null, int page = 1, int? pageSize = null)
{
// Instantiate generic query
Expression<Func<CompanyIPT, bool>> query = null;
// Check parameters and build the lambda query
// Check if the parameter is given and if the query field is already filled so as to either set or add a query
if (id != null && query != null) query = query.And(t => t.CompanyID == id);
else if (id != null && query == null) query = t => t.CompanyID == id;
if (taskId != null && query != null) query = query.And(t => t.ProcessTaskID == taskId);
else if (taskId != null && query == null) query = t => t.ProcessTaskID == taskId;
if (completedById != null && query != null) query = query.And(t => t.CompletedByID == completedById);
else if (completedById != null && query == null) query = t => t.CompletedByID == completedById;
if ((dateCompletedStart != null && dateCompletedEnd != null) && query != null) query = query.And(a => a.DateCompleted >= dateCompletedStart && a.DateCompleted <= dateCompletedEnd);
else if ((dateCompletedStart != null && dateCompletedEnd != null) && query == null) query = a => a.DateCompleted >= dateCompletedStart && a.DateCompleted <= dateCompletedEnd;
// Execute the GET with the appended query and paging information
var result = _uow.CompanyIPTRepository.List(filter: query, page: page, pageSize: pageSize);
int totalPossibleRecords = _uow.CompanyIPTRepository.GetTotalRecords(filter: query);
return new ApiSuccessResponse<List<CompanyIPTDTO>>(HttpStatusCode.OK, result.Select(x => Mapper.Map<CompanyIPTDTO>(x)).ToList(), result.Count(), Request.RequestUri, totalPossibleRecords, pageSize);
}
And as you can see this gets very cumbersome for a large API on every get request to have to customize the query checks. I assume there must be some way to do this generically based on a query string parameter that comes in. For example in this case I would love to see a request come in that looks like,
https://www.example.com/api/Companies/15/Implementations/Tasks?q=[completedById=5,dateCompletedStart=1/15/18,dateCompletedEnd=1/17/18]
And after coming in like this I assume we could build something that uses Reflection to look at the object and verify these fields exist and build up a generic query to hit our DB?
Anyone know where to point us in the right direction?

How do I add multiple optional parameters to linq query

I Have to check and add the optional parameter in function but its taking lengthy code to go through IF-Else statement, If I choose switch statement then Cannot convert 'var' variable to string error keep coming up, How do I check and add optional parameters to linq query please help. Here is my code. (I will provide both the one with If statement and other one with switch statement which is throwing error)
Code 1 If-else statement:
public static void loadGrid(ref GridView gvMain, string cID, string desig = "All", string importancy = "All", string status = "All")
{
int _cId = Convert.ToInt32(cID);
List<clsclass> list = new List<clsclass>();
var db = new MyEntities();
if (_cId == 0 && desig == "All" && importancy == "All" && status == "All")
{
var query = from table in db.Members select table;
list.Clear();
foreach (var item in query)
{
clsclass ctl = new clsclass();
ctl.Id = Convert.ToInt32(item.LID);
ctl.Name = item.FirstName + " " + item.LastName;
ctl.Gender = item.Gender;
ctl.Age = Convert.ToInt32(item.Age);
ctl.Mobile = item.Mobile;
ctl.Workphone = item.WorkPhone;
ctl.Designation = item.Designation;
ctl.Importancy = item.Importancy;
list.Add(ctl);
}
}
else if (_cId != 0 && desig == "All" && importancy == "All" && status == "All")
{
var query = from table in db.Members where table.CID == _cId select table;
list.Clear();
foreach (var item in query)
{
clsclass ctl = new clsclass();
ctl.Id = Convert.ToInt32(item.LID);
ctl.Name = item.FirstName + " " + item.LastName;
ctl.Gender = item.Gender;
ctl.Age = Convert.ToInt32(item.Age);
ctl.Mobile = item.Mobile;
ctl.Workphone = item.WorkPhone;
ctl.Designation = item.Designation;
ctl.Importancy = item.Importancy;
list.Add(ctl);
}
}
//AND SO ON I HAVE TO CHECK THE OPTIONAL PARAMETERS......
//else if()
//{
//}
}
And In below code If I try to use switch statement to bind query based condition its throwing error:
Code 2:Switch statement:
public static void LoadGrid(ref GridView gvMain, string cID, string desig = "All", string importancy = "All", string status = "All")
{
int _cId = Convert.ToInt32(cID);
List<clsclass> list = new List<clsclass>();
var db = new MyEntities();
var query;
switch (query)
{
case _cId == 0 && desig == "All" && importancy == "All" && satus == "All":
query = from b in db.ConstituencyLeaders select b;
case _cId != 0 && desig == "All" && importancy == "All" && satus == "All":
query = from b in db.ConstituencyLeaders where b.ConstituencyID == _cId select b;
}
foreach (var item in query)
{
clsclass cl = new clsclass();
cl.LeaderId = item.LID;
//...remaining members add
list.Add(cl);
}
gvMain.DataSource = list;
gvMain.DataBind();
}
So basically I got two questions How to shorten the codes to capture the optional parameters if switch statement is better option then how would I achieve var query from Case:
any help much appreciated.
What you can do is.
var query = db.Members.AsQuerryable();
if(_cid != "")
{
query = query.where(table => table.CID == _cId);
}
Then use that in your statement
var result = from table in query where table.CID == _cId select table;
or we also used to do or statements.
var query= from table in query where (table.CID == _cId || _cId = "") select table;
so if the value is empty it just goes through or if there is a value it checks.

Categories