Get result using condition not works properly (C#) - c#

I trying to get data from datatabase and assign it to list
Here is 2 conditions. 1 - I have only categoryId and 2 - I have category and subcategoryId
I wrote code like this
public async Task<List<TimelineItemDto>> GetFilteredClasses(int? categoryId, int? subcategoryId)
{
List<TimelineItemDto> filteredClasses;
if (categoryId != null)
{
filteredClasses = await _context.Events
.Where(x => x.CategoryId == categoryId && x.EventType == EntityType.Class)
.ProjectTo<TimelineItemDto>()
.ToListAsync();
}
if (categoryId != null && subcategoryId != null)
{
filteredClasses = await _context.Events
.Where(x => x.CategoryId == categoryId && x.SubcategoryId == subcategoryId &&
x.EventType == EntityType.Class)
.ProjectTo<TimelineItemDto>()
.ToListAsync();
}
else
{
filteredClasses = await _context.Events.Where(x =>
x.EventType == EntityType.Class).ProjectTo<TimelineItemDto>()
.ToListAsync();
}
return filteredClasses;
}
but at first if I got this
A second if and at else all okay and it's executed and filling list
How I can solve this?

Well I would do something like below :
public async Task<List<TimelineItemDto>> GetFilteredClasses(int? categoryId, int? subcategoryId)
{
var filteredClasses = _context.Events.Where(x => x.EventType == EntityType.Class);
if (categoryId != null)
{
filteredClasses = filteredClasses.
.Where(x => x.CategoryId == categoryId);
}
if (categoryId != null && subcategoryId != null)
{
filteredClasses = filteredClasses.Where(x => x.SubcategoryId == subcategoryId );
}
return await filteredClasses.ProjectTo<TimelineItemDto>()
.ToListAsync();;
}
This way you will avoid materializing multiple queries.

You should update the condition flow as below:
if (categoryId != null && subcategoryId != null)
{
...
}
else if (categoryId != null)
{
...
}
else
{
...
}
With above, the filteredClasses will not be overridden by last else condition. Your current code first evaluate if and then if & else. Both are different code blocks and last else is always getting executed.

Related

C# - Wait and Check three times before throwing exception

Here is the existing code. I am trying to refactor this code.
What is the best way to implement this using C#
The first time, I want to wait for 200ms, 2nd time 400 and 3rd time 600
await Task.Delay(200);
var category = this.categoryRepository.Categories.SingleOrDefault(x => x.CategoryId == categoryId);
if (category == null)
{
await Task.Delay(400);
category = this.categoryRepository.Categories.SingleOrDefault(x => x.CategoryId == categoryId);
if (category == null)
{
await Task.Delay(600);
category = this.categoryRepository.Categories.SingleOrDefault(x => x.CategoryId == categoryId);
if (category == null)
{
throw NullReferenceException;
}
}
}
Add a counter and use a loop:
int numTries = 0;
Category category = null;
do
{
numTries++;
await Task.Delay(200 * numTries);
category = this.categoryRepository.Categories.SingleOrDefault(x => x.CategoryId == categoryId);
} while (category == null && numTries < 3);
if (category == null)
{
throw new NullReferenceException();
}
Similar to the above only slightly cleaner in my opinion
int retires = 6;
Category category = null;
while (retries-- > 0 && catagory == null)
{
await Task.Delay(200);
category = this.categoryRepository.Categories.SingleOrDefault(x => x.CategoryId == categoryId);
}
if (category == null)
{
throw NullReferenceException;
}
I wouldn't wait longer each time as it will just slow down performance, instead just increase the number of retries.

The cast to value type System.Boolean failed because the materialized value is null, result type's generic parameter must use a nullable type

This code was working before but now I've got this error: The cast to value type 'System.Boolean' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.
public async Task<ActionResult> BankDepositVoucher(BankDepositVoucherSearchViewModel search, int? PageNo)
{
var model = new BankDepositVoucherListViewModel
{
Search = search ?? new BankDepositVoucherSearchViewModel()
};
if (search != null)
{
search.StartDate = search.StartDate.ToStartOfDay();
search.EndDate = search.EndDate.ToEndOfDay();
}
try
{
var Vouchers = DbManager.Invoices.Include(x => x.BankDepositVoucher)
.Where(x => x.Type == InvoiceType.BankDepositVoucher
&& (x.VoucherNumber == search.VoucherNo || search.VoucherNo == null)
&& (x.BankDepositVoucher.SlipNo.Contains(search.SlipNo) || search.SlipNo == null)
&& (x.BankDepositVoucher.ChequeNo.Contains(search.ChequeNo) || search.ChequeNo == null)
&& (x.BankDepositVoucher.Bank.AccountName.Contains(search.BankDetails)
|| search.BankDetails == null)
&& (x.BankDepositVoucher.AccountName.Contains(search.AccountName) || search.AccountName == null)
&& (x.BankDepositVoucher.Narration.Contains(search.Narration) || search.Narration == null)
&& (x.TotalAmount == search.Amount || search.Amount == null)
&& (x.Date >= search.StartDate || search.StartDate == null)
&& (x.Date <= search.EndDate || search.EndDate == null));
//model.Pager = new Pager(await Vouchers.CountAsync(), PageNo, 10);
model.Vouchers = await Vouchers.OrderByDescending(x => x.VoucherNumber)
//.Skip((model.Pager.CurrentPage - 1) * model.Pager.PageSize)
//.Take(model.Pager.PageSize)
.Select(x => new BankDepositVoucherBaseViewModel
{
Id = x.Id,
VoucherNumber = x.VoucherNumber,
AccountName = x.BankDepositVoucher.AccountName,
BankAccountName = x.BankDepositVoucher.Bank.AccountName,
Date = x.Date,
ChequeNo = x.BankDepositVoucher.ChequeNo,
Narration = x.BankDepositVoucher.Narration,
SlipNo = x.BankDepositVoucher.SlipNo,
TotalAmount = x.TotalAmount,
IsCleared = x.BankDepositVoucher.IsCleared
}).ToListAsync();
}
catch (Exception ex)
{
Console.WriteLine("", ex.Message);
}
return PartialView(model);
}
This is the part throwing above mentioned exception
model.Vouchers = await Vouchers.OrderByDescending(x => x.VoucherNumber)
//.Skip((model.Pager.CurrentPage - 1) * model.Pager.PageSize)
//.Take(model.Pager.PageSize)
.Select(x => new BankDepositVoucherBaseViewModel
{
Id = x.Id,
VoucherNumber = x.VoucherNumber,
AccountName = x.BankDepositVoucher.AccountName,
BankAccountName = x.BankDepositVoucher.Bank.AccountName,
Date = x.Date,
ChequeNo = x.BankDepositVoucher.ChequeNo,
Narration = x.BankDepositVoucher.Narration,
SlipNo = x.BankDepositVoucher.SlipNo,
TotalAmount = x.TotalAmount,
IsCleared = x.BankDepositVoucher.IsCleared
}).ToListAsync();
The issue is likely that when populating the view model it cannot deal with the fact that a record may not have a BankDepositVoucher.
For instance:
IsCleared = x.BankDepositVoucher.IsCleared
This should probably be:
IsCleared = x.BankDepositVoucher?.IsCleared ?? false
One other thing to improve performance considerably:
While it may look concise in the code to write statements like this:
.Where(x => x.Type == InvoiceType.BankDepositVoucher
&& (x.VoucherNumber == search.VoucherNo || search.VoucherNo == null)
&& (x.BankDepositVoucher.SlipNo.Contains(search.SlipNo) || search.SlipNo == null)
&& (x.BankDepositVoucher.ChequeNo.Contains(search.ChequeNo) || search.ChequeNo == null)
&& (x.BankDepositVoucher.Bank.AccountName.Contains(search.BankDetails)
|| search.BankDetails == null)
&& (x.BankDepositVoucher.AccountName.Contains(search.AccountName) || search.AccountName == null)
&& (x.BankDepositVoucher.Narration.Contains(search.Narration) || search.Narration == null)
&& (x.TotalAmount == search.Amount || search.Amount == null)
&& (x.Date >= search.StartDate || search.StartDate == null)
&& (x.Date <= search.EndDate || search.EndDate == null));
It is more efficient to write it out as:
.Where(x => x.Type == InvoiceType.BankDepositVoucher);
if(!string.IsNullOrEmpty(search.VoucherNo))
Voucher = Voucher.Where(x => x.VoucherNumber == search.VoucherNo);
if(!string.IsNullOrEmpty(search.SlipNo))
Voucher = Voucher.Where(x => x.BankDepositVoucher.SlipNo.Contains(search.SlipNo))
// etc.
The reason is that in the first case you are generating a much larger SQL statement to be sent to the database, and it is quite easy to "slip up" on conditions if that query is ever edited in the future. (missing parenthesis, etc.) The second example only adds conditions to the query if they are needed, keeping the resulting SQL statement much more compact.

Filtering a list of objects

I have a list of Object Product :
public Class Product
{
public int ID { get; set; }
public string Title { get; set; }
public string Status { get; set; }
}
I have a list of the above product :
List<Product> p ;
I am trying to filter this List , based on Search Criteria ID, Title, Status.
Example :
Id Title Status
1 ABC OPEN
2 CDE CLOSED
3 FGH RESOLVED
4 IJK PROPOSED
5 LMN SET
6 OPQ CLOSED
7 MNO OPEN
8 STU CLOSED.
If Search Fields ID 1 is entered : It should return
1 ABC OPEN
If search Fields Status OPEN is entered : It should return
1 ABC OPEN
7 MNO OPEN
If Search Fields Title "MNO" and Status "OPEN" are entered it should return :
7 MNO OPEN
If Id = "" and Title = "" and Status = "ALL" it should return all the elements.
I am going to bind this List of objects to an asp.net grid view.
So far the code I have is below :
var results = new List<Product>();
foreach (var prod in Product)
{
if (prod.ID == txtProd)
{
results.Add(prod);
}
if (prod.Title.ToUpper() == txtTitle)
{
results.Add(prod);
}
if (prod.Status.ToUpper() == strStatus)
{
results.Add(prod);
}
}
Can you please tell me how I can modify this code to achieve my results ?
Basically you want to use AND between your conditions, what you are currently doing is an OR, and you will add the same item twice when it satisfies more than one condition.
You could built a dynamic linq query based on parameters:
var query = Product.AsQueryable();
query = txtProd != string.Empty ? query.Where(x => x.ID == txtProd) : query;
query = txtTitle != string.Empty ? query.Where(x => x.Title == txtTitle) : query;
query = strStatus != string.Empty ? query.Where(x => x.Status == strStatus) : query;
var results = query.ToList();
As a single Linq query it would look like this:
var results = p.Where(x =>
(string.IsNullOrEmpty(txtProd) || x.ID == Convert.ToInt32(txtProd))
&& (string.IsNullOrEmpty(txtTitle) || x.Title == txtTitle)
&& (string.IsNullOrEmpty(strStatus) || x.Status == strStatus)).ToList();
By the way, in the question the List results is of type Task and you try to add Products, this is not possible.
Try this:
results = p.Where(((product.ID < yourIDLowerBound) || (product.ID == yourID))
&& (string.IsNullOrEmpty(product.yourTitle) || product.Title == yourTitle)
&& (string.IsNullOrEmpty(product.yourStatus) || product.Status == yourStatus)).ToList();
var results = new List < Product > ();
if (strStatus == "ALL" || txtProd == "" || txtTitle == "")
results = p;
else
foreach(var prod in p) {
if (prod.ID == Int32.Parse(txtProd)) {
results.Add(prod);
}
if (prod.Title.ToUpper() == txtTitle) {
results.Add(prod);
}
if (prod.Status.ToUpper() == strStatus) {
results.Add(prod);
}
}
results = results.Distinct()
.ToList();
How about creating a product query method. I think this meets all of requirements, I don't think any other covered the "ALL" requirement.
public List<Product> ProductQuery(List<Product> Products
, int? IDCriteria
, string TitleCriteria
, string StatusCriteria)
{
var query = Products.AsQueryable();
if (IDCriteria != null)
{
query.Where(x => x.ID == IDCriteria);
}
if (!String.IsNullOrEmpty(TitleCriteria))
{
query.Where(x => x.Title == TitleCriteria);
}
if (!String.IsNullOrEmpty(StatusCriteria))
{
if (StatusCriteria.Equals("all", StringComparison.CurrentCultureIgnoreCase))
{
query.Where(x => x.Status.Length > 0 || String.IsNullOrEmpty(x.Status)); //will return any status
}
else
{
query.Where(x => x.Status == StatusCriteria);
}
}
return query.ToList();
}

Dynamic EF Where Clause raising ArgumentNullException

I'm trying to code a method that, in it's class given the values of some of the attributes, returns a filtered DbSet. The code, so far, is:
public IEnumerable<Pesquisa> Pesquisas {
get {
PrometheusDBContext db = new PrometheusDBContext();
var temp = db.Pesquisas;
if ((this.Filtro.Nome != null) && (this.Filtro.Nome.Trim() != ""))
{
temp = (temp.Where(p => SqlFunctions.PatIndex(this.Filtro.Nome, p.Nome) > 0) as DbSet<Pesquisa>);
}
if ((this.Filtro.CodTipoPesquisa != null) && (this.Filtro.CodTipoPesquisa.Trim() != ""))
{
temp = (temp.Where(p => p.CodTipoPesquisa == this.Filtro.CodTipoPesquisa.Trim()) as DbSet<Pesquisa>);
}
if ((this.Filtro.IDStatusPesquisa != null) && (this.Filtro.IDStatusPesquisa > 0))
{
temp = (temp.Where(p => p.IDStatusPesquisa == this.Filtro.IDStatusPesquisa) as DbSet<Pesquisa>);
}
if ((this.Filtro.DataCriacao_Inicial != null) && (this.Filtro.DataCriacao_Final != null))
{
temp = (temp.Where(p => (p.DataCriacao >= this.Filtro.DataCriacao_Inicial) && (p.DataCriacao <= this.Filtro.DataCriacao_Final)) as DbSet<Pesquisa>);
}
else
{
if (this.Filtro.DataCriacao_Inicial != null)
{
temp = (temp.Where(p => p.DataCriacao >= this.Filtro.DataCriacao_Inicial) as DbSet<Pesquisa>);
}
if (this.Filtro.DataCriacao_Final != null)
{
temp = (temp.Where(p => p.DataCriacao <= this.Filtro.DataCriacao_Final) as DbSet<Pesquisa>);
}
}
return temp
.Include(p => p.Usuario)
.Include(p => p.StatusPesquisa)
.Include(p => p.TipoPesquisa)
.Include(p => p.ModeloTermoAdesao)
.Include(p => p.Pacientes)
.ToList();
}
Problem is: everytime one of the attributes is filled with some value (i.e.: this.Filtro.Nome = "test" ), the ToList() raises an ArgumentNullExcpetion. Any ideas?
You shouldn't cast to DbSet at the end of each line.
Also, declare
IQueryable<Pesquisa> temp = db.Pesuisas;
// your code follows.
The reason behind it is that although you start with a DbSet, applying operators changes its type. Your dynamic cast returns null then.

Handling null result

I have a db request that could return null:
Pony MyPony = db.Pony.Where(p => p.PonyOwnerId == user.UserId).First();
If there is no row in my db, there is an error message.
How to accept an empty query?
You can use FirstOrDefault
Pony myPony = db.Pony.Where(p => p.PonyOwnerId == user.UserId).FirstOrDefault();
if (myPony == null)
{
..
}
You can write:
Pony myPony = db.Pony.Where(p => p.PonyOwnerId == user.UserId).FirstOrDefault();
if( myPony != null ) {
// Do something
}
var MyPony = db.Pony.FirstOrDefault(p => p.PonyOwnerId != null && p.PonyOwnerId == user.UserId);
or
var MyPony = db.Pony.Where(p => p.PonyOwnerId != null && p.PonyOwnerId == user.UserId).FirstOrDefault();
or
if (db.Pony.FirstOrDefault(p => p.PonyOwnerId != null && p.PonyOwnerId == user.UserId) != null)
{
//Do stuff
}

Categories

Resources