Linq - conditional Contains() - c#

I have the following method for filtering shops by the criteria specified in parameters:
public int[] GetShopIds(IEnumerable<Guid> OrderCreaatorIds, IEnumerable<Guid> OrderItemCategoryIds, int StatusId)
{
var query = from s in _db.Shops
join o in _db.Orders on s.Id equals o.ShopId
join oi in _db.OrderItems on o.Id equals oi.OrderId
where
OrderCreaatorIds.Contains(o.CreatorId)
&& OrderItemCategoryIds.Contains(oi.CategoryId)
&& (int)o.StatusId == StatusId
select s.Id;
return query.ToArray();
}
The thing is: OrderCreaatorIds, OrderItemCategoryIds can be null and StatusId can be 0. In that case I do not want to have those where clauses, e.g. if OrderCreaatorIds is null then the query should work as follows:
public int[] GetShopIds(IEnumerable<Guid> OrderCreaatorIds, IEnumerable<Guid> OrderItemCategoryIds, int StatusId)
{
var query = from s in _db.Shops
join o in _db.Orders on s.Id equals o.ShopId
join oi in _db.OrderItems on o.Id equals oi.OrderId
where
OrderItemCategoryIds.Contains(oi.CategoryId)
&& (int)o.StatusId == StatusId
select s.Id;
return query.ToArray();
}
etc.
Unfortunately where OrderCreaatorIds != null && OrderCreaatorIds.Contains(o.CreatorId) is not working.

public int[] GetShopIds(IEnumerable<Guid> OrderCreaatorIds, IEnumerable<Guid> OrderItemCategoryIds, int StatusId)
{
var query = from s in _db.Shops
join o in _db.Orders on s.Id equals o.ShopId
join oi in _db.OrderItems on o.Id equals oi.OrderId
select new { s = s, o = o, oi = oi };
if (null != OrderCreaatorIds)
query = query.Where(x_ => OrderCreaatorIds.Contains(x_.o.CreatorId));
if (null != OrderItemCategoryIds)
query = query.Where(x_ => OrderItemCategoryIds.Contains(x_.oi.CategoryId));
if (0 < StatusId)
query = query.Where(x_ => (int)x_.o.StatusId == StatusId);
return query.select(x_ => x_.s.Id).ToArray();
}
Maybe you will have to add some casting to IQueryable<> to make it compilable. I did not check it in compiler.

Try something like the following:
var query = from s in _db.Shops
join o in _db.Orders on s.Id equals o.ShopId
join oi in _db.OrderItems on o.Id equals oi.OrderId
where
(OrderCreaatorIds==null || OrderCreaatorIds.Contains(o.CreatorId))
&&
(OrderItemCategoryIds==null || OrderItemCategoryIds.Contains(oi.CategoryId))
&&
(StatusId==0 || (int)o.StatusId == StatusId)
select s.Id;
As you can see for each part of the where clause I have changed it from your simple predicate to an or check of two predicates. So now you have three things that are formed like A || B. Due to the way or logic works if A is true then B will be ignored. So in this case if OrderItemCategoryIds is null then it won't do the OrderItemCategoryIds.Contains check.

You can prepare the dynamic parts of the query in variables outside the query, and then use the variables inside like this:
public int[] GetShopIds(IEnumerable<Guid> OrderCreaatorIds, IEnumerable<Guid> OrderItemCategoryIds, int StatusId)
{
var orders = _db.Orders.AsQueryable();
if (StatusId != 0)
orders = orders.Where(o => o.StatusId == StatusId);
if (OrderCreaatorIds != null)
orders = orders.Where(o => OrderCreaatorIds.Contains(o.CreatorId));
var orderItems = _db.OrderItems;
if (OrderItemCategoryIds != null)
orderItems = orderItems.Where(oi => OrderItemCategoryIds.Contains(oi.CategoryId));
var query = from s in _db.Shops
join o in orders on s.Id equals o.ShopId
join oi in orderItems on o.Id equals oi.OrderId
select s.Id;
return query.ToArray();
}

Related

Linq SQL with Select MAX Sub Query

I have the following SQL query which has a sub query so that only the max value is in the result set:
Select
t.ID,
r.ResultIdentifier,
p.ProductID,
r.Status,
r.Start
from Result r , Transact t, Product p
WHERE r.ResultIdentifier = (Select MAX(r2.ResultIdentifier) from Result r2
where r2.Status = 'Fail'
and r2.ID = r.ID
and r2.Start >= getdate() - 30)
and r.ID = t.ID
and p.productID = 9
and t.productID = p.productID
I'm trying to convert this to a LINQ query
var failures = from result in db.Results
join transact in db.Transacts on result.ID equals transact.ID
join product in db.Products on transact.ProductID equals product.ProductID
where result.ResultIdentifier == ??
.....
select new{ ID = transact.ID,
...etc
I'm really struggling with the max ResultIdentifier in the LINQ - tried multiple variations with .MAX() but cant seem to get it right.Any suggestions welcome.
You can use the max keyword, Sorry for using method syntax as I can see you are using query :(
Should look something like the following
where result.ResultIdentifier == (Results.Max().Where(x => x.Status.equals("Fail") && x.id == result.id && x.start => Datetime.Now().Add(-30)).Select(x => x.ResultIdentifier))
Try the following query:
var results = db.Results;
var failedResults = results
.Where(r => r.Status == "Fail" && r.Start >= DataTime.Date.AddDays(-30));
var failures =
from result in results
join transact in db.Transacts on result.ID equals transact.ID
join product in db.Products on transact.ProductID equals product.ProductID
from failed in failedResults
.Where(failed => failed.ID == result.ID)
.OrderByDescending(failed => failed.ResultIdentifier)
.Take(1)
where result.ResultIdentifier == failed.ResultIdentifier
.....
select new{ ID = transact.ID,
...etc

Pass parameters to linq queries

I have the following part of code that works perfectly.
public Task<List<RsvItemsViewModel>> GetReservations(int company_ID)
{
try
{
// we cannot pass parameter as company_id . we use hard coded values as 1 for CompanyId.Must find a way to overcome this
return ((from a in gTravelDbContext.Set<Frsvitem>()
join d in gTravelDbContext.Set<Freserv>()
on a.Rsinum equals d.Rsvnum into gd from d in gd.Where(p1 => p1.CompanyId == 1)
join c in gTravelDbContext.Set<Fsupplier>()
on a.SupplId equals c.SupplId into gc from c in gc.Where(p1=>p1.CompanyId == 1)
join i in gTravelDbContext.Set<Fzone>()
on a.Rsizone equals i.Zoneid into gi
from i in gi.DefaultIfEmpty() where i.CompanyId == 1
join g in gTravelDbContext.Set<Fservtype>()
on a.Rsisertype equals g.Stypecode
join b in gTravelDbContext.Set<Fcustomer>()
on d.CustId equals b.CustId
join e in gTravelDbContext.Set<Fpaykind>()
on d.Rsvpaymethod equals e.Payid into ge
from e in ge.DefaultIfEmpty()
join f in gTravelDbContext.Set<Fsalesman>()
on d.Rsvsalescode equals f.Salescode into gf
from f in gf.DefaultIfEmpty()
join h in gTravelDbContext.Set<Fpinake>()
on d.Rsvakirosi equals h.Tblid into gh
from h in gh.Where(p => p.Tblcd == "yesno")
select new RsvItemsViewModel
{
Rsinum = a.Rsinum,
Stypename = g.Stypename,
Cuname = b.Cuname,
Rsvcuname = d.Rsvcuname,
Sumame = c.Suname,
Rsvakirosi = d.Rsvakirosi,
Yesno = h.Tbltext ,
Paytext = e.Paytext,
Salesname = f.Salesname,
Stypegroup = g.Stypegroup,
Company_id =d.CompanyId.GetValueOrDefault(),
Zonename = i.Zonename,
Rsisertype = a.Rsisertype,
Suppl_id = a.SupplId,
Xrhsh = d.Xrhsh,
Bpar_id = a.BparId
}
).ToListAsync());
}
catch (Exception)
{
throw;
}
}
The problem is that I want to pass company_ID as a parameter in linq and I want to substitute the Where(p1 => p1.CompanyId == 1) with Where(p1 => p1.CompanyId == company_ID )
I would be grateful if someone could help me.
Thank you
You have used GroupJoin in way, which is not supported by EF Core. GroupJoin has a lot of limitations and use it only if you need LEFT JOIN.
I have rewritten your query to be translatable:
var query =
from a in gTravelDbContext.Set<Frsvitem>()
from d in gTravelDbContext.Set<Freserv>().Where(d => d.Rsvnum == a.Rsinum && d.CompanyId == company_ID)
from c in gTravelDbContext.Set<Fsupplier>().Where(c => a.SupplId == c.SupplId && c.CompanyId == company_ID)
from i in gTravelDbContext.Set<Fzone>().Where(i => a.Rsizone == i.Zoneid && c.CompanyId == company_ID).DefaultIfEmpty()
join g in gTravelDbContext.Set<Fservtype>()
on a.Rsisertype equals g.Stypecode
join b in gTravelDbContext.Set<Fcustomer>()
on d.CustId equals b.CustId
join e in gTravelDbContext.Set<Fpaykind>()
on d.Rsvpaymethod equals e.Payid into ge
from e in ge.DefaultIfEmpty()
join f in gTravelDbContext.Set<Fsalesman>()
on d.Rsvsalescode equals f.Salescode into gf
from f in gf.DefaultIfEmpty()
from h in gTravelDbContext.Set<Fpinake>().Where(h => d.Rsvakirosi == h.Tblid && h.Tblcd == "yesno")
select new RsvItemsViewModel
{
Rsinum = a.Rsinum,
Stypename = g.Stypename,
Cuname = b.Cuname,
Rsvcuname = d.Rsvcuname,
Sumame = c.Suname,
Rsvakirosi = d.Rsvakirosi,
Yesno = h.Tbltext ,
Paytext = e.Paytext,
Salesname = f.Salesname,
Stypegroup = g.Stypegroup,
Company_id =d.CompanyId.GetValueOrDefault(),
Zonename = i.Zonename,
Rsisertype = a.Rsisertype,
Suppl_id = a.SupplId,
Xrhsh = d.Xrhsh,
Bpar_id = a.BparId
}

C# Linq get data if exists two records

I'm very bad right now in making queries but I'm trying to learn from my mistakes. I have three tables Table1, Table2 and Table3. From Table1 I want to get all the records that have in Table3 a row with Name Attribute1 and value F AND another row with Name Attribute2 and value S.
What I've tried is:
from i in entities.Table1.AsNoTracking().Where(i => (i.IsDeleted == false))
join se in entities.Table2.AsNoTracking() on i.Id equals se.SId
join set in entities.Table3.AsNoTracking().Where(i => (i.Name == "Attribute1" && i.Value.Contains("F"))
&& (i.Name == "Atrribute2" && i.Value.Contains("S")))
on i.Id equals set.SId
select new
{
Name = i.Name,
Id = i.Id
};
but it doesn't return anything. What am I doing wrong?
Try this one
from i in entities.Table1.AsNoTracking().Where(i => (i.IsDeleted == false))
join se in entities.Table2.AsNoTracking() on i.Id equals se.SId
join set in entities.Table3.AsNoTracking().Where(i => (i.Name == "Attribute1" && i.Value.Contains("F")))
on i.Id equals set.SId
join set2 in entities.Table3.AsNoTracking().Where(i => (i.Name == "Atrribute2" && i.Value.Contains("S")))
on i.Id equals set2.SId
select new
{
Name = i.Name,
Id = i.Id
};

Join two linq queries on one key column to get one result set

Here I want to join the out put of the first query(one column) to the result of the 2nd query to get a one result set. How can I merge them.(CONCAT doesn't work as required. eg: var query2 = query.concat(query1);)
var query = (from PP in _db.paymentPlans
join APP in _db.Applications on PP.applicationID equals APP.ApplicationId
join C in _db.Courses on APP.courseID equals C.courseID
where PP.active == true && APP.agentID == agentID
orderby C.courseID ascending
group new {C,PP} by new {C.courseID} into totalRecievable
select new PdPpAppCourseModel
{
courseID = totalRecievable.Key.courseID,
totalAmount = totalRecievable.Sum(x => x.PP.totalAmount)
}).ToList();
var query1=(from PD in _db.paymentDetails
join PP in _db.paymentPlans on PD.paymentPlanID equals PP.paymentPlanID
join APP in _db.Applications on PP.applicationID equals APP.ApplicationId
join C in _db.Courses on APP.courseID equals C.courseID
where PP.active == true && APP.agentID == agentID
orderby C.courseID ascending
group new { C,PD } by new { C.courseID, C.cricosCode, C.courseName } into paymentsCourseWise
select new PdPpAppCourseModel
{
courseID = paymentsCourseWise.Key.courseID,
cricosCode = paymentsCourseWise.Key.cricosCode,
courseName = paymentsCourseWise.Key.courseName,
paidAmount = paymentsCourseWise.Sum(x => x.PD.paidAmount)
}).ToList();
You could join query1 and query like this
var result = (from q1 in query1
join q in query on q1.courseID = q.courseID
select new PdPpAppCourseModel
{
courseID = q1.Key.courseID,
cricosCode = q1.Key.cricosCode,
courseName = q1.Key.courseName,
paidAmount = q1.Sum(x => x.PD.paidAmount),
totalAmount = q.totalAmount
}).ToList();

Linq to entities query with nested query on the same table

I have a SQL query:
SELECT distinct A.stock_value_site,
A.BALANCE_QUANTITY,
A.BALANCE_NOMINAL_VALUE,
A.BALANCE_INDEXED_VALUE,
V.STOCK_VALUE_ORDER,
U.BALANCE_QUANTITY
FROM svr A,
svt V,
svu U
WHERE V.Code = 500 and
A.Id = U.ID (+) and
A.Id = (SELECT max(B.id)
FROM svr B,
sts
WHERE A.stock_value_site = B.stock_value_site and
B.Id = sts.ID(+) and
B.item = _item and
B.date < _from_date and
B.Id IS NULL)
I tried to convert this query to Linq to entities:
var data = (from A in _context.svr
join V in _context.svt on A.svtId equals V.Code
join U in _context.svu on A.Id equals U.Id into groupA
from gA in groupA.DefaultIfEmpty()
where V.Code == _openBalanceRecordId &&
A.Id == (from B in _context.svr
join st in _context.sts on B.Id equals st.Id into groupB
from gB in groupB.DefaultIfEmpty()
where A.svsId == B.svsId &&
B.ItemId == _item &&
B.Date < _startDate.Date
select B.Id).Max()
select new
{
A.stock_value_site,
A.BALANCE_QUANTITY,
A.BALANCE_NOMINAL_VALUE,
A.BALANCE_INDEXED_VALUE,
V.STOCK_VALUE_ORDER,
gA == null ? 0 : gA.BALANCE_QUANTITY
}).Distinct().ToList();
When I run the SQL query in oracle I get 33 records back. But when I run it using Linq to entities I don't get any record.
What am I doing wrong?
I believe there are still some issues with you're original query, if I understand what you're trying to do, this should work better:
var results =
(from a in _context.svr
from v in _context.svt.Where(t => t.Code == 500)
join u in _context.svu on u.Id equals a.Id into gU
from x in gU.DefaultIfEmpty()
where a.Id ==
(from b in _context.svr
join s in _context.sts on b.Id equals s.Id
where b.item = _item
and b.date < _from_date
and b.svsId == a.svsId
select b.Id).Max()
select new
{
a.stock_value_site,
a.BALANCE_QUANTITY,
a.BALANCE_NOMINAL_VALUE,
a.BALANCE_INDEXED_VALUE,
v.STOCK_VALUE_ORDER,
x == null ? 0 : x.BALANCE_QUANTITY
}).Distinct().ToList();
Or possibly this:
var results =
(from a in _context.svr
from v in _context.svt.Where(t => t.Code == 500)
join u in _context.svu on u.Id equals a.Id into gU
from x in gU.DefaultIfEmpty()
let subQuery =
(from b in _context.svr
join s in _context.sts on b.Id equals s.Id
where b.item = _item
and b.date < _from_date
select new { b.Id, b.svsId })
join y in subQuery on a.svsId equals y.svsId into gY
where a.Id = y.Max(b => b.Id)
select new
{
a.stock_value_site,
a.BALANCE_QUANTITY,
a.BALANCE_NOMINAL_VALUE,
a.BALANCE_INDEXED_VALUE,
v.STOCK_VALUE_ORDER,
x == null ? 0 : x.BALANCE_QUANTITY
}).Distinct().ToList();

Categories