Compare with list using linq - c#

I have a list cids that I am fetching like this
var cids = _service.Employee.Where(i => i.EmpID == _empID).Select(j => j.ClientID).ToList();
I want to compare this list with Patient Entity and get all the records of patients that matches the clientId in the cid list
Patient Entity is like this
class Patient
{
Int PatientID{ get; set;}
Int ClientID{get; set;}
string PatientName{get; set;}
}
Right now I am doing it like this
foreach(var item in cids)
{
var pp = from p1 in _service.Patients
where p1.ClientId == item
select new PatientDTO
{
PatientID = p1.PatientID,
PatientName = p1.PatientName,
};
prec.Add(pp);
}
Is there a way to do it with Linq without using foreach

You can use Contains on your List (you don't need the ToList, by the way : this would avoid 2 queries on db).
var allPp = _service.Patients.Where(p1 => cids.Contains(p1.ClientId))
.Select(m >= new PatientDTO) {
PatientID = m.PatientID,
PatientName = m.PatientName
});
But the most performant way, in a db world, would be a join
from emp in _service.Employee.Where(i => i.EmpID == _empID)
join patient in _service.Patients on emp.ClientId equals patient.ClientId
select new PatientDTO {
PatientID = patient.PatientID,
PatientName = patient.PatientName,
}

Use Enumberable.Intersect to fetch common records.
var commonClients = cids.Intersect<int>(_service.Patients.Select(x => x.ClientID));
var person = _service.Patients.Where(x => commonClients.Contains(x.ClientID));

Related

Linq Query Join to Subquery with In clause

I have a query from an old application that I am attempting to convert to an Entity Framework Core application. The relationship I am working with is a simple one to many, where one Order can have many OrderEvents. The old query looks something like this:
select Order.Id, mostRecent.*
from Order
left join OrderEvent mostRecent
on mostRecent.Id in (select top(1) Id
from OrderEvent
where OrderEvent.OrdId = Order.Id
and OrderEvent.PostDateTime is not null
order by OrderEvent.PostDateTime desc)
where Order.SomeColumn = 'some value'
I am struggling with figuring out how to write this query in LINQ. It doesnt seem that one can use anything other than equals when doing using join, so I first attempted something like:
var test = (from order in _context.Ord.AsNoTracking()
join mostRecentQuery in _context.OrdEvt.AsNoTracking()
on (from orderEvent in _context.OrdEvt.AsNoTracking()
where orderEvent.PostDateTime != null && orderEvent.OrdId == order.Id
orderby orderEvent.PostDateTime descending
select orderEvent.Id).FirstOrDefault()
equals mostRecentQuery.Id
into mostRecentResults
from mostRecent in mostRecentResults.DefaultIfEmpty()
select new
{
OrderId = order.Id,
OrderEvent = mostRecent
}).ToList();
Whatever sql this spit out, it appears to be so slow that I cant even run it connected to Sql Server. I am however able to run this query when using Sqlite and it generates the following sql:
SELECT 'big list of fields....'
FROM "Ord" AS "order"
LEFT JOIN "OrdEvt" AS "mostRecentQuery" ON COALESCE((
SELECT "orderEvent0"."Id"
FROM "OrdEvt" AS "orderEvent0"
WHERE "orderEvent0"."PostDateTime" IS NOT NULL AND ("orderEvent0"."OrdId" = "order"."Id")
ORDER BY "orderEvent0"."PostDateTime" DESC
LIMIT 1
), X'00000000000000000000000000000000') = "mostRecentQuery"."Id"
This is close do what I am going for, but Im not sure why the COALESCE function is being used.
Is it possible to represent the query I am trying to convert, in Linq query syntax?
I'm not sure what your problem is, because you left out why it doesn't compile.
Bute here and simple example whith a join and choosing one event for an order:
public class Order
{
public int OrderId { get; set; }
public string OrderName { get; set; }
}
public class OrderEvent
{
public int OrderId { get; set; }
public string EventName { get; set; }
public DateTime Date { get; set; }
}
public static void Main(string[] args) // Here our Exe-Args are delivered to our program..
{
List<Order> orders = new List<Order>()
{
new Order() { OrderId = 1, OrderName = "One" }
};
List<OrderEvent> orderEvents = new List<OrderEvent>()
{
new OrderEvent() { OrderId = 1, EventName = "EventTwo", Date = DateTime.Now.AddHours(-1) },
new OrderEvent() { OrderId = 1, EventName = "EventOne", Date = DateTime.Now },
new OrderEvent() { OrderId = 1, EventName = "EventThree", Date = DateTime.Now.AddHours(-2) },
new OrderEvent() { OrderId = 2, EventName = "EventX", Date = DateTime.Now },
};
var tmp = orders.GroupJoin( // Join something to our orders
orderEvents, // join all events
o => o.OrderId, // key of our order
e => e.OrderId, // foreign-key to order in our event
(o, es) => // lambda-expression "selector". One order "o" and multiple events "es"
es.OrderByDescending(e => e.Date) // We order our events
.Select(s => new // we build a new object
{
OrderId = o.OrderId,
OrderName = o.OrderName,
RecentEvent = s.EventName
}).First()); // we choose the object with biggest date (first after orderDesc)
foreach (var item in tmp)
{
Console.WriteLine(item.OrderId + ", " + item.OrderName + ", " + item.RecentEvent);
}
tmp = from o in orders
join e in orderEvents on o.OrderId equals e.OrderId into es
select new
{
OrderId = o.OrderId,
OrderName = o.OrderName,
RecentEvent = (from x in es orderby x.Date descending select x.EventName).First()
};
foreach (var item in tmp)
{
Console.WriteLine(item.OrderId + ", " + item.OrderName + ", " + item.RecentEvent);
}
}

Calculating product's quantity with nested EF Query

I want to calculate the quantity of every product. I want to use these tables for this.
I want take result like this.
StockId | StockName | Sum(ProductNumber) [actually product quantity]
I tried this code for can take right result but It is returning null value even though it is the condition that satisfies the conditions.
CimriContext context = new CimriContext();
public ICollection<StockDto.StockHeader> FillDataGrid(int userCompanyId)
{
ICollection<StockDto.StockHeader> Stocks = context.Stocks.Where(c => c.UserCompanyId==userCompanyId).
Select(c => new StockDto.StockHeader()
{
StockId = c.StockId,
StockName = c.StockName,
Piece=0
}).ToList();
ICollection<StockDto.StockHeader> ProductHeader = new List<StockDto.StockHeader>();
foreach (var products in Stocks)
{
products.Piece = context.ProductTransactions.Where(p => p.StockId==products.StockId).Sum(s => s.ProductNumber);
ProductHeader.Add(products);
}
return ProductHeader.ToList();
}
You want to retrieve ProductCount for per stock record. You can perform it by joining two tables and grouping StockId and StockNumber like this;
var query = from stocks in context.Stocks
join products in context.ProductTransactions ON stocks.StockId equals products.StockId
where stocks.UserCompanyId = userCompanyId
group stocks by new
{
stocks.StockId,
stocks.StockName
} into gcs
select new
{
StockId = gcs.Key.StockId,
StockName = gcs.Key.StockName,
ProductCounts = gcs.Count()
};

Entity Framework Linq to Object Mapping

I have one problem.
Database Shema
==================
|parts |
==================
| partId |textId |
==================
========================
texts |
========================
|TextId|LanguageId|text|
========================
============================
languages |
============================
|LanguageId|LanguageIsoCode|
============================
I want to map this result to the following object
public long PartId { get; set; }
public Dictionary<string,string> Name { get; set; }
eg.
{
PartId: 32020
Name: {["en": "Blah", "es": "Blah2"]}
}
this is what I have tried, but Im running into TimeOut with this query.
var query = (from p in _context.epc_parts
select new //select first dynamic object
{
PartId = p.PartID,
Code = p.PartName,
Name = (from trans in _context.epc_texts
join lang in _context.epc_languages on trans.LanguageID equals lang.LanguageID
where p.TextID == trans.TextID
select new
{
LanguageId = lang.shortname.ToLower(),
Caption = trans.Caption
})
}).AsEnumerable().Select(x => new SearchPartModel //transform it here when we can use dictionary
{
Code = x.Code,
PartId = x.PartId,
Name = x.Name.ToDictionary(t => t.LanguageId, t => t.Caption)
});
The parts table has about 60k rows for every row there are 7 translations. Navigation properties cant be used because the Shema doesn't use foreign keys and the model is generated from db.
I have solved it with this query. For the whole query it took about 20s to load everything what is ok for this purpose. Im using group by first.
(from p in _context.epc_parts
join trans in _context.epc_texts on p.TextID equals trans.TextID
join lang in _context.epc_languages on trans.LanguageID equals lang.LanguageID
select new
{
PartId = p.PartID,
Code = p.PartName,
Caption = trans.Caption,
LanguageId = lang.shortname.ToLower()
}).AsEnumerable().GroupBy(x => x.PartId).Select(g => new SearchPartModel
{
Code = g.Select(x => x.Code).FirstOrDefault(),
PartId = g.Key,
Name = g.Select(x => new
{
x.LanguageId,
x.Caption
}).Distinct().ToDictionary(y => y.LanguageId, y => y.Caption)
});
from p in _context.epc_parts
join trans in _context.epc_texts on p.TextID equals trans.TextID
join lang in _context.epc_languages on trans.LanguageID equals lang.LanguageID
select new {
PartId = p.PartID,
Code = p.PartName,
Name = new
{
LanguageId = lang.shortname.ToLower(),
Caption = trans.Caption
}
}
That should be better, otherwise in your current implementation for each part you're querying the texts table

linq combine 2 tables into one list

I have 2 tables in db - one is EmploymentRecords one is EmploymentVerificationRecords
I want to query both tables and return one List
I have a Model (simplified example):
Public Class Record
{
int ID {get; set;}
string name {get; set;}
bool IsVerification {get; set;}
}
I want to have some type of query in LINQ like :
var records = from a in _context.EmploymentRecords
join b in _context.EmploymentVerificationRecords on a.id equals b.id
where a.UserID = 1
select new Record() { .ID = a.id, .name = a.name, .IsVerification = false}
// I also want to select a new Record() for each b found
see - I also want a new Record() added to the results for each record found in the second table , for these results IsVerification would be True
You can select everything from DB as it is selected now (but I would rather use join/into to do that) and then flatten results into one big collection using LINQ to Objects.
Following should do the trick:
var records
= (from a in _context.EmploymentRecords
join b in _context.EmploymentVerificationRecords on a.id equals b.id into bc
where a.UserID = 1
select new {
a = new Record() { ID = a.id, name = a.name, IsVerification = false},
b = bc.Select(x => new Record() { ID = x.ID, name = b.name, IsVerification = true })
}).AsEnumerable()
.SelectMany(x => (new [] { x.a }).Concat(x.b));

C#, LInq, Entity Framework 4: Split a table in to a two dimensional array using Linq

I have an Entity like this:
public class Category
{
public int classid {get;set;}
public int itemid {get;set;}
public string label {get;set;}
}
So a List produces this JSON (three sizes and three colors
[{"classid":1,"itemid":1,"label":"Small"},
{"classid":1,"itemid":2,"label":"Medium"},
{"classid":1,"itemid":3,"label":"Large"},
{"classid":2,"itemid":1,"label":"Blue"},
{"classid":2,"itemid":2,"label":"Green"},
{"classid":2,"itemid":3,"label":"Red"},
{"classid":3,"itemid":1,"label":"Tee"},
{"classid":3,"itemid":2,"label":"Golf"},
{"classid":3,"itemid":3,"label":"Dress"}]
However the JavaScript client needs something like this myarray[][].label:
[[{"itemid":1,"label":"Small"},
{"itemid":2,"label":"Medium"},
{"itemid":3,"label":"Large"}],
[{"itemid":1,"label":"Blue"},
{"itemid":2,"label":"Green"},
{"itemid":3,"label":"Red"}],
[{"itemid":1,"label":"Tee"},
{"itemid":2,"label":"Golf"},
{"itemid":3,"label":"Dress"}]]
And this is smack dab in the middle of my Linq query.
How would I construct the Linq query to assemble the two dimensional array from the one dimensional array within Linq?
EDIT: Existing Query:
...
CATS = (from myP in myProduct.ProductCategories
select new ProductCategory
{
classid = myP.classid,
itemid = myP.itemid,
label = myP.label
}),
...
EDIT: Getting Closer:
CATS = (from myP in myProduct.ProductCategories
group myP by myP.classid into groups
select new resultClass
{ classid = groups.Key,
opts = groups.Select(x =>
new ProductOption
{ itemid = x.itemid,
label = x.label}) }),
I haven't tested this, but it's familiar territory and should work:
IEnumerable<Category> items = ...;
var groups = items.GroupBy(x => x.classid);
var arrays = groups.Select(x =>
x.Select(y => new { itemid = y.itemid, label = y.label }).ToArray()
).ToArray();

Categories