LINQ using Contains with entity - c#

Am using ASP.NET MVC 5 to create an Application for billing, now i have thing function which receive a filter object with different variables, am having a problem with contains when i search, what am i doing wrong
public static List<Quote> getCustomerQuotes(QuoteFilter filter)
{
using (var db = new AppDBContext())
{
var q = db.Quotes.Where(u => u.entryDate > 0); ;
if (filter.type != null)
{
q = q.Where(u => u.quoteType == filter.type);
}
if (filter.only_permitable != null)
{
q = q.Where(u => !Values.NON_PERMITABLE_QUOTES.Contains(u.quoteType));
}
if (filter.quote_status != null)
q = q.Where(u => u.quote_status == (int)filter.quote_status);
if (filter.quotenumber != null)
{
q = q.Where(u => u.quote_number.Contains(filter.quotenumber));
}
if (filter.permitnumber != null)
q = q.Where(u => u.permit_number.Contains(filter.permitnumber));
if (filter.permit_status != null)
q = q.Where(u => u.permit_status == (int)filter.permit_status);
if (filter.quoteId != null)
q = q.Where(u => u.Id == (int)filter.quoteId);
if (filter.customer_id != null)
q = q.Where(u => u.customer_id == (int)filter.customer_id);
q = q.OrderByDescending(u => u.Id);
FileLogger.Log("getCustomerQuotes", q.ToString());
return q.ToList();
}
}
When i call the function and pass quotenumber, the contains doesnt search, it returns nothing

You have to evaluate your expression, before you apply the OrderByDescending.
q = q.Where(u => u.quote_number.Contains(filter.quotenumber)).ToList();
This should be happen also to the rest places.

Is quote number alpha-numeric? If yes, as Contains is case sensitive can you try comparison by first turning source and target to same case ? like
q = q.Where(u => u.quote_number.ToLower().Contains(filter.quotenumber.ToLower()));
Cheers

Ok, am answering my own question after finding a solution or i may call it a hack
public static List<Quote> getCustomerQuotes(QuoteFilter filter)
{
using (var db = new AppDBContext())
{
var q = db.Quotes.Where(u =>
(filter.type != null ? u.quoteType == filter.type : u.quoteType > 0) &&
(filter.only_permitable != null ? !Values.NON_PERMITABLE_QUOTES.Contains(u.quoteType) : u.permitType > 0) &&
(filter.quote_status != null ? u.quote_status == filter.quote_status : u.quote_status > -100) &&
(!string.IsNullOrEmpty(filter.quotenumber) ? u.quote_number.Contains(filter.quotenumber) || u.groupName.Contains(filter.quotenumber) : u.quoteType > 0) &&
(!string.IsNullOrEmpty(filter.permitnumber) ? u.permit_number.Contains(filter.permitnumber) || u.groupName.Contains(filter.permitnumber) : u.quoteType > 0) &&
(filter.permit_status != null ? u.permit_status == filter.permit_status : u.quoteType > 0) &&
(filter.quoteId != null ? u.Id == filter.quoteId : u.Id > 0) &&
(filter.customer_id != null ? u.customer_id == filter.customer_id : u.customer_id > -1)
).OrderByDescending(u => u.Id);
//FileLogger.Log("getCustomerQuotes", q.ToString());
return q.ToList();
}
}
i dont know why it didn't work the first time but now it works.

Related

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.

Change condition in LINQ by another condition

I have these two LINQ lines which are only different in one condition.
node.Image.Tag == null and node.Image.Tag != null
if (treeSelectedNode.Image.Tag == null)
{
radNode = tree.Find(node => node.Level == 0 && node.Image.Tag == null
&& node.Text.Equals(treeSelectedNode.Text));
}
else
{
radNode = tree.Find(node => node.Level == 0 && node.Image.Tag != null
&& node.Text.Equals(treeSelectedNode.Text));
}
Is there any way to create the condition before the LINQ line and then use it, so that I can remove the extra line?
I know I can do something like this:
radNode = treeSelectedNode.Image.Tag == null ? tree.Find(node => node.Level == 0
&& node.Image.Tag == null && node.Text.Equals(treeSelectedNode.Text)) :
tree.Find(node => node.Level == 0 && node.Image.Tag != null
&& node.Text.Equals(treeSelectedNode.Text));
But it's just not what I want.
Check for the the outcome of condition node.Image.Tag == null being the same as the outcome of treeSelected.Image.Tag == null:
radNode = tree.Find(node => node.Level == 0 && ((node.Image.Tag == null) == (treeSelectedNode.Image.Tag == null))
&& node.Text.Equals(treeSelectedNode.Text))
Update
Addressing #KhanTo's performance concern, in part:
Boolean selectedImgTagIsNull = treeSelected.Image.Tag == null;
radNode = tree.Find(node => node.Level == 0 && ((node.Image.Tag == null) == selectedImgTagIsNull)
&& node.Text.Equals(treeSelectedNode.Text))
However, I suspect that JIT optimization would have a high likelihood of resulting in the same thing even for my original code.
Maybe that oneliner will be ok for you?
radNode = tree.Find(node => node.Level == 0
&& ((treeSelectedNode.Image.Tag == nulL
&& node.Image.Tag == null)
|| (treeSelectedNode.Image.Tag != nulL
&& node.Image.Tag != null))
&& node.Text.Equals(treeSelectedNode.Text));
Technically you can build that kind of query using Expression, it need extra works, here is a simple example:
private static Expression<Func<T, bool>> AndCombined<T>(Expression<Func<T, bool>> exp1, Expression<Func<T, bool>> exp2)
{
ParameterExpression p = exp1.Parameters.Single();
return Expression.Lambda<Func<T, bool>>(Expression.And(exp1.Body, Expression.Invoke(exp2, p)), exp1.Parameters.Single());
}
static void Main(string[] args)
{
var b = new List<int>() { 30, 15, 5 };
Expression<Func<int, bool>> test1 = f => f > 10;
Expression<Func<int, bool>> test2 = f => f < 20;
var combinedAndQuery = AndCombined(test1, test2);
var reuslt1 = b.Find(new Predicate<int>(combinedAndQuery.Compile()));
Expression<Func<int, bool>> test3 = f => f < 40;
var combinedAndQuery2 = AndCombined(test1, test3);
var reuslt2 = b.Find(new Predicate<int>(combinedAndQuery2.Compile()));
}

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.

How to write below sql query in linq c# where some of paramteres will be null sometimes

I have following query in sql,
select * from dbo.WaitingLists
where WaitingListTypeId in (1)
or StakeBuyInId in (Select StakeBuyInId from dbo.WaitingLists where StakeBuyInId in (5) and
WaitingListTypeId = 2)
in this, sometimes StakeBuyInId will be null or WaitingListTypeId will ne null. I want to perform this query via linq c# in following code.
public GameListItem[] GetMyWaitingList(Guid UserId, int LocalWaitingListTypeId, int GlobalWaitingListTypeId, int[] StakeBuyInIds)
{
ProviderDB db = new ProviderDB();
List<GameListItem> objtempGameListItem = new List<GameListItem>();
List<GameTables> objGameTablesList = new List<GameTables>();
var objWaitingListUser = db.WaitingLists.Where(x => x.UserId.Equals(UserId));
if (LocalWaitingListTypeId > 0 || (GlobalWaitingListTypeId > 0 && StakeBuyInIds != null))
{
objWaitingListUser = objWaitingListUser.Where(x => x.WaitingListTypeId == LocalWaitingListTypeId || (x.WaitingListTypeId == GlobalWaitingListTypeId
&& StakeBuyInIds != null ? StakeBuyInIds.Contains((Int32)x.StakeBuyInId) : true)
);
}
return objtempGameListItem.ToArray();
}
Here StakeBuyInIds int[] will be sometimes null, then how will i perform linq operation for above sql query. Thanks for any help.
You could probably just check for null outside of your expression, like this:
if (LocalWaitingListTypeId > 0 || (GlobalWaitingListTypeId > 0 && StakeBuyInIds != null))
{
if (StakeBuyInIds != null)
{
objWaitingListUser = objWaitingListUser.Where(
x => x.WaitingListTypeId == LocalWaitingListTypeId ||
(x.WaitingListTypeId == GlobalWaitingListTypeId &&
StakeBuyInIds.Contains((Int32)x.StakeBuyInId));
} else {
objWaitingListUser = objWaitingListUser.Where(
x => x.WaitingListTypeId == LocalWaitingListTypeId ||
x.WaitingListTypeId == GlobalWaitingListTypeId);
}
}
You might also be able to do this:
if (LocalWaitingListTypeId > 0 || (GlobalWaitingListTypeId > 0 && StakeBuyInIds != null))
{
var arrayNull = StakeBuyInIds != null;
var array = StakeBuyInIds ?? new int[0];
objWaitingListUser = objWaitingListUser.Where(
x => x.WaitingListTypeId == LocalWaitingListTypeId ||
(x.WaitingListTypeId == GlobalWaitingListTypeId &&
(arrayNotNull || array.Contains((Int32)x.StakeBuyInId)));
}
It effect it tests for null outside of the query, but ensures that it cannot be null when actually executing the query.
The waitingListTypeId and stakeBuyinId should be nullable int in your relational object WaitingList.
List<int?> WaitingListTypeIds=new List(new int?[]{1});
var StakeBuyInIds=from w in WaitingListsCollection where new List<int?>(new int?[]{5}).Contains(w.StakeBuyInId) && w.WaitingListTypeId = 2;
var output= from w in WaitingListsCollection where WaitingListTypeIds.Contains(w.WaitingListTypeId) || StakeBuyInIds.Contains(w.StakebuyInId)

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