Linq / EF in ASP.NET Blazor - entity-framework

I am using Blazor.
I am trying to get a specific result from dbset.
I have two conditions, salary is 620 and deduction is for p2.
The difficult thing is range, btw 600~700 for salary. Then how I move to specific column to get the result for p2.
var result = await _db.TaxTable.......blah...blah...
In this case, I have to find the result 70
I have tried some code..but I failed everytime.
Could you share the exact knowledge?
Thank you in adv.

You have to locate the row. Then use a switch statement to get the appropriate value.
double GetDeduction(double salary, string discount)
{
var row = someData.SingleOrDefault(a => salary >= a.start && salary < a.end);
if(row == null) throw new SomeRowNotFoundException();
return discount switch
{
"p1" => row.p1,
"p2" => row.p2,
"p3" => row.p3,
_ => throw new SomeDiscountNotValidException();
}
}
You have to include one of the boundaries and exclude the other to avoid overlap. I arbitrarily chose to include start the alternative would be
someData.SingleOrDefault(a => salary > a.start && salary <= a.end)

Your query into your DbSet should look something like this to get the specific value:
using var dbContext = _factory.CreateDbContext();
dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var value = await dbContext.Set<TRecord>()
.SingleOrDefault(item => item.start <= this.salary && item.end >= this.salary)?.p2 ?? 0;
Here's a demo page.
#page "/"
<PageTitle>Index</PageTitle>
<input class="form-control" #bind-value=this.salary />
<div class="text-end m-2">
<button class="btn btn-primary" #onclick=Calc>Calculate</button>
<button class="btn btn-secondary" #onclick=Calc2>Calculate 2</button>
</div>
<div class="bg-dark text-white m-2 p-2">
P2 = #P2
</div>
#code {
private int salary;
private int P2;
private void Calc()
{
var record = deductions.SingleOrDefault(item => item.start <= this.salary && item.end >= this.salary);
P2 = record?.p2 ?? 0;
}
private void Calc2()
{
P2 = deductions.SingleOrDefault(item => item.start <= this.salary && item.end >= this.salary)?.p2 ?? 0;
}
private List<Deduction> deductions = new List<Deduction>
{
new Deduction(1,0,199,10,20,30),
new Deduction(2,200,299,20,30,40),
new Deduction(3,300,399,30,40,50),
new Deduction(4,400,499,40,50,60),
};
public record Deduction(int Id, int start, int end, int p1, int p2, int p3 );
}
Note: there's a problem in your dataset your ranges overlap!

Related

MVC app does not show selected values on a form reedition

I am building a Framework7 MVC app and found myself in a dead end alley. I have a form which I need to evaluate. This form contains selects. I am using localStorage to store the form values and everything works OK in that sense, I mean everything is stored correctly. ¿What is the issue? When I fill the form I answer some questions on textareas inputs, select inputs and inputs. everything goes fine until I try to reedit the form, then everything is display correctly on the form, including the score i got from my previous answers, but, the selects appears as if I have never touch them. Their previously selected value is stored but not display on the form. I have found that the issue is caused by the fact that I have set numerical values to the options values but what the form show is "yes" or "no". If I change the option values to "yes" or "no" then the form displays correctly but I need to set "5" or "0" because I need to evaluate the user's answers.
This is my code
The form
<li style="margin-top:-10px;">
<input style="visibility:hidden;height:1px;" value="0" name="choice" onchange="checkTotal()"/>
<input style="visibility:hidden;height:1px;" value="1" type="checkbox" name="choice" onchange="checkTotal()" checked="on">
</li>
<li><div class="item-content">1. ¿Sueles quejarte de sentirte mal?</div>
<div class="item-content">
<div class="item-inner">
<div class="item-input">
<select name="pr1" id="pr1" onchange="checkTotal()">
<option class="item-inner" value="5">No</option>
<option class="item-inner" value="0">Si</option>
</select>
</div>
</div>
</div>
<div class="item-content">En tal caso,</div>
<div class="item-content">
<div class="item-inner">
<div class="item-input">
<textarea class="resizable" id="pr1notes" placeholder="¿cuál es la causa?">{{model.pr1notes}}</textarea>
</div>
</div>
</div>
</li>
The functions on the editController
function init(query){
var protections = JSON.parse(localStorage.getItem("f7Protections"));
if (query && query.id) {
protection = new Protection(_.find(protections, { id: query.id }));
state.isNew = false;
}
else {
protection = new Protection({ isFavorite: query.isFavorite });
state.isNew = true;
}
View.render({ model: protection, bindings: bindings, state: state, doneCallback: saveProtection });
showSelectedValues();
}
function showSelectedValues(){
var fieldNames = protection.getSelectFields();
for (var i = 0, len = fieldNames.length; i < len; i++) {
var itemname = fieldNames[i];
var selectObj = document.getElementById(itemname);
if (selectObj!=null) {
var objOptions = selectObj.options;
var selIndex=0;
for (var j = 0, len2 = objOptions.length; j < len2; j++) {
if ((objOptions[j].label).localeCompare(protection[itemname])==0){
selIndex=j;
}
}
selectObj.options[selIndex].setAttribute("selected","selected");
}else{
}
}
}
and the model
Protection.prototype.setValues = function(inputValues, extras) {
for (var i = 0, len = inputValues.length; i < len; i++) {
var item = inputValues[i];
if (item.type === 'checkbox') {
this[item.id] = item.checked;
}
else {
this[item.id] = item.value;
}
}
for (var i = 0, len = extras[0].length; i < len; i++) {
var item = extras[0][i];
if((item.id).localeCompare("pr1notes")==0) {this[item.id] = item.value;}
}
console.log('starting loop for extras 3...');
for (var i = 0, len = extras[2].length; i < len; i++) {
var item = extras[2][i];
this[item.name] = item.value;
}
};
Protection.prototype.validate = function() {
var result = true;
if (_.isEmpty(this.prdate)
) {result = false;}
return result;
};
Protection.prototype.getSelectFields = function() {
return ['pr1'];
}
What should I change in order to keep my "5" or "0" values on the select options while the form options still show "yes" or "no" to the user just like this: <select name="pr1" id="pr1" onchange="checkTotal()"><option class="item-inner" value="5">No</option><option class="item-inner" value="0">Si</option></select>?
need anything else to help you understand the issue?
The simplest solution
function init(query){
var protections = JSON.parse(localStorage.getItem("f7Protections"));
if (query && query.id) {
protection = new Protection(_.find(protections, { id: query.id }));
state.isNew = false;
}
else {
protection = new Protection({ isFavorite: query.isFavorite });
state.isNew = true;
}
View.render({ model: protection, bindings: bindings, state: state, doneCallback: saveProtection });
showSelectedValues();
}
function showSelectedValues(){
var fieldNames = protection.getSelectFields();
for (var i = 0, len = fieldNames.length; i < len; i++) {
var itemname = fieldNames[i];
var selectObj = document.getElementById(itemname);
if (selectObj!=null) {
var objOptions = selectObj.options;
var selIndex=0;
for (var j = 0, len2 = objOptions.length; j < len2; j++) {
if ((objOptions[j].value).localeCompare(protection[itemname])==0){
selIndex=j;
}
}
selectObj.options[selIndex].setAttribute("selected","selected");
}else{
}
}
}
Just changed this line
if ((objOptions[j].label).localeCompare(protection[itemname])==0){
selIndex=j;
and changed .label for .value.

reactive forms: use one validator for multiple fields

I'm using angular 2 reactive forms and made a validator for a date of birth field. The validator is working, but it turns out the date of birth field is split into three new field: year, month, day. They all have their own validators. My question is, how can I change my code so my original date of birth validator works on three fields.
my original validator that checks one field.
input(2000/12/12) is valid
export function dobValidator(control) {
const val = control.value;
const dobPattern = /^\d{4}\/\d{2}\/\d{2}$/ ;
const comp = val.split('/');
const y = parseInt(comp[0], 10);
const m = parseInt(comp[1], 10);
const d = parseInt(comp[2], 10);
const jsMonth = m - 1;
const date = new Date(y, jsMonth, d);
const isStringValid = dobPattern.test(control.value);
const isDateValid = (date.getFullYear() === y && date.getMonth() === jsMonth && date.getDate() === d);
return (isStringValid && isDateValid) ? null : { invalidDob: ('Date of birth not valid') };
};
new html with 3 fields
year has a validator that checks the year
day has a validator that checks if the input is between 1 and 31
month has a validator that checks if the input is between 1 and 12.
I want to combine the above input of the three field into a new string and use my original date of birth validator.
<label>Date of birth :</label>
<div>
<div class="col-xs-1">
<input required type="text" formControlName="day" class="form-control" placeholder="dd" id="day"/>
<p *ngIf="form.controls.day.dirty && form.controls.day.errors">{{ form.controls.day.errors.invalidDay }}</p>
</div>
<div class="col-xs-1">
<input required type="text" formControlName="month" class="form-control" placeholder="mm" id="month"/>
<p *ngIf="form.controls.month.dirty && form.controls.month.errors">{{ form.controls.month.errors.invalidMonth }}</p>
</div>
<div class="col-xs-2">
<input required type="text" formControlName="year" class="form-control" placeholder="yyyy" id="year"/>
<p *ngIf="form.controls.year.dirty && form.controls.year.errors">{{ form.controls.year.errors.invalidYear }}</p>
</div>
</div>
<div>
<button type="submit" [disabled]="form.invalid">Submit</button>
</di>
I have created a validator for comparing two dates (their format is NgbDateStruct - as used in ng-bootstrap package's datepickers)
import { Directive, forwardRef, Attribute } from '#angular/core';
import { Validator, AbstractControl, NG_VALIDATORS, ValidatorFn } from '#angular/forms';
import { NgbDateStruct } from "#ng-bootstrap/ng-bootstrap";
import { toDate } from "../helpers/toDate";
export function dateCompareValidator(compareToControl: string, compareToValue: NgbDateStruct, compareType: string, reverse: boolean, errorName: string = 'dateCompare'): ValidatorFn {
return (c: AbstractControl): { [key: string]: any } => {
let compare = function (self: Date, compareTo: Date): any {
console.log('comparing ', compareType.toLowerCase());
console.log(self);
console.log(compareTo);
if (compareType.toLowerCase() === 'ge') {
if (self >= compareTo) {
return true;
} else {
return false;
}
} else if (compareType.toLowerCase() === 'le') {
if (self <= compareTo) {
return true;
} else {
return false;
}
}
return false;
};
// self value
let v = c.value;
// compare vlaue
let compareValue: Date;
let e;
if (compareToValue) {
compareValue = toDate(compareToValue);
} else {
e = c.root.get(compareToControl);
if (e) {
compareValue = toDate(e.value);
}
else {
// OTHER CONTROL NOT FOUND YET
return null;
}
}
let controlToValidate: AbstractControl = reverse ? e : c;
// validate and set result
let error = null;
let result = compare(toDate(c.value), compareValue);
if (result === true) {
console.log('clearing errors', compareToControl);
if (controlToValidate.errors) {
delete controlToValidate.errors[errorName];
if (!Object.keys(controlToValidate.errors).length) {
controlToValidate.setErrors(null);
}
}
else {
console.log('errors property not found in control', controlToValidate);
}
} else {
error = {};
error[errorName] = false;
controlToValidate.setErrors(error);
console.log(controlToValidate.errors);
console.log(controlToValidate.value);
console.log('Error Control', controlToValidate);
console.log('returning errors');
}
return reverse ? null : error;
}
}
Couldn't manage to modify much lot to best describe here as an answer but I believe you would get your query answered in this validator function code.
Note:
Function toDate() used in the code is a small function I created to convert NgbDateStruct into a javascript date object so that comparing dates can get easier. Here goes its implementation:
import { NgbDateStruct } from "#ng-bootstrap/ng-bootstrap"
export function toDate(ngbDate: NgbDateStruct): Date {
return ngbDate != null ? new Date(Date.UTC(ngbDate.year, ngbDate.month, ngbDate.day)) : null;
}

Some part of your SQL statement is nested too deeply

I have the following code
[WebGet]
public Bid GetHighestBidInOpenAuctions(int auctionEventId)
{
var auctionEvent = CurrentDataSource.AuctionEvents.Where(x => x.Id == auctionEventId).FirstOrDefault();
var auctionIds = CurrentDataSource.Auctions.Where(x => x.AuctionEventId == auctionEventId && x.Ends > DateTime.UtcNow).Select(x => x.Id).ToList();
var bids = CurrentDataSource.Bids.Where(x => auctionIds.Any(t => t == x.AuctionId));
// If the auction Event has not yet started or there are no bids then show auction with high pre-sale estimate.
if (bids.Count() == 0 || auctionEvent.Starts > DateTime.UtcNow)
{
return null;
}
var highestBid = bids.Where(b => b.IsAutobid == false).OrderByDescending(b => b.Amount).FirstOrDefault();
return highestBid;
}
This line throws the below exception
if (bids.Count() == 0 || auctionEvent.Starts > DateTime.UtcNow)
Some part of your SQL statement is nested too deeply. Rewrite the query or break it up into smaller queries.
What's wrong?
EDIT
I have tried doing this
IQueryable<Bid> bids = CurrentDataSource.Bids.Where(b => 0 == 1);
foreach(var auctionId in auctionIds)
{
int id = auctionId;
bids = bids.Union(CurrentDataSource.Bids.Where(b => b.AuctionId == id));
}
But I still get the same error.
Rather than using a subquery, try replacing the bid query with:
var bids = CurrentDataSource.Bids.Where(b => b.AuctionEventId == auctionEventId
&& b.Auction.AuctionEvent.Starts > DateTime.UtcNow
&& b.Auction.Ends > DateTime.UtcNow);
if (bids.Count() == 0
{
return null;
}
It seems when you have too many things in your database then you will get this error (auctionIds in my case) because the generated sql will be too deeply nested. To solve this I came up with this solution. If anyone can do better then do. I'm posting this because someone may have this error in the future and if they do, in the absence of a better solution this might help them.
[WebGet]
public Bid GetHighestBidInOpenAuctions(int auctionEventId)
{
/*
* This method contains a hack that was put in under tight time constraints. The query to
* get bids for all open auctions used to fail when we had a large number of open auctions.
* In this implementation we have fixed this by splitting the open auctions into groups of 20
* and running the query on those 20 auctions and then combining the results.
*/
const int auctionIdSegmentSize = 20;
var auctionEvent = CurrentDataSource.AuctionEvents.Where(x => x.Id == auctionEventId).FirstOrDefault();
var auctionIds = CurrentDataSource.Auctions.Where(x => x.AuctionEventId == auctionEventId && x.Ends > DateTime.UtcNow).Select(x => x.Id).ToList();
int numberOfSegments = auctionIds.Count/auctionIdSegmentSize;
if (auctionIds.Count % auctionIdSegmentSize != 0)
numberOfSegments++;
var bidsList = new List<IQueryable<Bid>>();
for (int i = 0; i < numberOfSegments; i++)
{
int start = i*auctionIdSegmentSize;
int end;
if (i == numberOfSegments - 1)
{
end = auctionIds.Count - 1;
}
else
{
end = ((i + 1)*auctionIdSegmentSize) - 1;
}
var subList = auctionIds.GetRange(start, (end - start) + 1);
bidsList.Add(CurrentDataSource.Bids.Where(b => subList.Any(id => id == b.AuctionId)));
}
// If the auction Event has not yet started or there are no bids then show auction with high pre-sale estimate.
if (IsBidsCountZero(bidsList) || auctionEvent.Starts > DateTime.UtcNow)
{
return null;
}
var highestBid = FindHighestBid(bidsList);
return highestBid;
}
private Bid FindHighestBid(List<IQueryable<Bid>> bidsList)
{
var bids = new List<Bid>();
foreach (var list in bidsList)
{
bids.Add(list.Where(b => b.IsAutobid == false).OrderByDescending(b => b.Amount).FirstOrDefault());
}
bids.RemoveAll(b => b == null);
if (bids.Count == 0)
return null;
bids.Sort(BidComparison);
return bids[0];
}
private int BidComparison(Bid bid1, Bid bid2)
{
if (bid1.Amount < bid2.Amount)
return 1;
if (bid1.Amount > bid2.Amount)
return -1;
return 0;
}
private bool IsBidsCountZero(List<IQueryable<Bid>> bidsList)
{
int count = 0;
foreach (var list in bidsList)
{
count += list.Count();
}
return count == 0;
}
The problem is with auctionIds.Any(t => t == x.AuctionId) where EF cannot create a correct query. You can change it to:
var bids = CurrentDataSource.Bids.Where(x => auctionIds.Contains(x.AuctionId));
Where EF can convert auctionIds to a collection and pass to DB.

Search string same how not working

I'm trying to perform a simple search and I cant find out what I have missed here
This is my ( I think very simple code)
public ActionResult WeeklyVorts(string sortOrder, string searchString, int page = 1 )
{
ViewData["corentSort"] = sortOrder;
ViewData["productSortParm"] = string.IsNullOrEmpty(sortOrder) ? "Product desc" : "";
var weeklyS = from c in _repository.List().OrderBy(x=>x.UParasha) select c;
if(!string.IsNullOrEmpty(searchString))
{
weeklyS = weeklyS.Where(v => v.UHeadLine.ToUpper().Contains(searchString.ToUpper())
|| v.UParasha.ToUpper().Contains(searchString.ToUpper())
|| v.Uvort.ToUpper().Contains(searchString.ToUpper())
);
}
switch (sortOrder)
{
case "Product desc":
weeklyS = weeklyS.OrderByDescending(s => s.UHeadLine);
break;
default:
weeklyS = weeklyS.OrderBy(d => d.UParasha);
break;
}
ViewData["weeklyS"] = _repository.List().ToList();
int hlist = (_repository.List().Count());
ViewData["TotalPages"] = (int)Math.Ceiling((double)hlist / PageSize);
ViewData["CurrentPage"] = page;
return View(_repository.List().Skip((page - 1) * PageSize).Take(PageSize));
}
My View
<div class="search">
<% using (Html.BeginForm())
{ %>
<p>
Find: <%=Html.TextBox("SearchString", ViewData["currentFilter"] as string) %>
<input type="submit" value="Search" />
</p>
<%} %>
</div>
//in a brackpoint I can c that the typed parameter is pass to
// if(!string.IsNullOrEmpty(searchString))
I know I have missed same thing in my view I just cand find out what
Thanks
It doesn't look like you are assigning the weeklyS variable into your ViewData["weeklyS"]
try this
ViewData["weeklyS"] = weeklyS;
instead of this
ViewData["weeklyS"] = _repository.List().ToList();
your code have some lines that I can not understand
why do you use _repository after searching should you use weeklyS variable?
try this
ViewData["weeklyS"] = weeklyS.ToList();
int hlist = weeklyS.Count();
ViewData["TotalPages"] = (int)Math.Ceiling((double)hlist / PageSize);
ViewData["CurrentPage"] = page;
return View(weeklyS.Skip((page - 1) * PageSize).Take(PageSize));

Select rows with checkbox in SlickGrid

I need to make a column where you can select grid rows with input:checkbox. Grids like ones used by Yahoo, Google etc have something like that.
I made something but I have some problems and I think that is not a good aproach also.
It's posible to have checkboxes in rows and click on them directly, not like in example4-model ?
My idea was :
< div id="inlineFilterPanel" class="slick-header-column" style="padding: 3px 0; color:black;">
<input type="checkbox" name="selectAll" id="selectAll" value="true" / >
< input type="text" id="txtSearch2" value="Desktops" />
</div>
d["check"] = '< INPUT type=checkbox value='true' name='selectedRows[]' id='sel_id_<?php echo $i; ?>' class='editor-checkbox' hideFocus />';
grid.onSelectedRowsChanged = function() {
selectedRowIds = [];
$('#myGrid' + ' :checkbox').attr('checked', '');
var rows = grid.getSelectedRows();
for (var i = 0, l = rows.length; i < l; i++) {
var item = dataView.rows[rows[i]];
if (item) {
selectedRowIds.push(item.id);
$('#sel_' + item.id).attr('checked', 'checked');
}
}
};
function selectAllRows(bool) {
var rows = [];
selectedRowIds = [];
for (var i = 0; i < dataView.rows.length; i++) {
rows.push(i);
if (bool) {
selectedRowIds.push(dataView.rows[i].id);
$('#sel_' + dataView.rows[i].id).attr('checked', 'checked');
} else {
rows = [];
$('#sel_' + dataView.rows[i].id).attr('checked', '');
}
}
grid.setSelectedRows(rows);
}
grid.onKeyDown = function(e) {
// select all rows on ctrl-a
if (e.which != 65 || !e.ctrlKey)
return false;
selectAllRows(true);
return true;
};
$("#selectAll").click(function(e) {
Slick.GlobalEditorLock.cancelCurrentEdit();
if ($('#selectAll').attr('checked'))
selectAllRows(true);
else
selectAllRows(false);
return true;
});
Thanks!
I've added a sample implementation of a checkbox select column to http://mleibman.github.com/SlickGrid/examples/example-checkbox-row-select.html
This is part of the upcoming 2.0 release.