Linq union all equivalent of sql code - sql

I have the following queries:
var majorClients = maj in dbContext.MajorClients
where (maj.startdate > startDate)
where (maj.status == "Active")
Select new Client{EntityPK = maj.mjPrimaryKey,Name = maj.name, Type = "Maj"};
var minorClients = min in dbContext.MinorClients
where (min.startdate > startDate)
where (min.status == "Active" || min.status== "Inactive")
Select new Client{EntityPK = min.mnPrimaryKey,Name = min.name, Type = "Min"};
There are clients that could appear in both major and minor tables. I would like to return a list of all occurrences of clients in both tables, however if there are matching clients by name, then I would only want to return the matching record from the majorClients table.
I have written a sql query to return the results:
SELECT mjPrimaryKey AS EntityPK,name,'Maj' AS TYPE
FROM majorClients
WHERE status = 'Active' AND startDate > #startDate
UNION ALL
SELECT mnPrimaryKey,name,'Min' FROM minorClients
WHERE status IN ('Active','Inactive') AND startDate > #startDate
WHERE name NOT IN (SELECT name FROM majorClients WHERE status = 'Active' AND startDate > #startDate)
How would I represent this query in linq?

Try this linq. To exclude duplicates from minorClients, I've used Contains method. To union all objects - Union method:
var majorClients = from maj in dbContext.MajorClients
where maj.startdate > startDate
&& maj.status == "Active"
select new Client
{
EntityPK = maj.mjPrimaryKey,
Name = maj.name,
Type = "Maj"
};
var minorClients = from min in dbContext.MinorClients
where min.startdate > startDate
&& min.status == "Active" || min.status== "Inactive"
&& !(from maj in dbContext.MajorClients
where maj.startdate > startDate
&& maj.status == "Active"
select maj.name).Contains(min.Name)
select new Client
{
EntityPK = min.mnPrimaryKey,
Name = min.name,
Type = "Min"
};
var allClients = majorClients.Union(minorClients);

Related

SQL lambda output not correct using nested select

I have 2 tables, Terms and Site_Program_Term:
Terms columns: Id, SiteId, Name, IsHoliday, DateStart, DateEnd, Year, IsActive
Site_Program_Term columns: Id, ProgName, SiteId, TermId, Year
Using the above 2 tables, I need to display output with primarily below columns
Name, StartDate, EndDate, NumberOfPrograms
I am getting the desired output but the 'NumberOfPrograms' is not showing the correct values. It should give me a count of all the Programs for a set of particular Term, Year and Site.
Thanks in advance.
Below is the base code.
var terms = db.Terms.Where(t => t.SiteId == id && t.IsActive).ToList().Select(t => new
{
Id = t.Id,
SiteId = t.SiteId,
Name = t.Name,
IsHoliday = t.IsHoliday,
DateStart = t.DateStart,
DateEnd = t.DateEnd,
Year = t.Year,
PubProgram = (
db.Site_Program_Term
.Where (spt => spt.SiteId == id && spt.Year == t.Year)
.Select(s => s).Count()
),
}).OrderBy(n => n.DateStart).ToList();
It should give me a count of all the
Programs for a set of particular Term, Year and Site.
But your Where condition only includes Year and Site, but not the Term. So
.Where(spt => spt.SiteId == id && spt.Year == t.Year)
should actually be:
.Where(spt => spt.SiteId == id && spt.Year == t.Year && spt.TermId == t.Id)
Note that if you are by any chance using Entity Framework (Core) and you have properly configured navigation property on the Term class such as
public class Term
{
// ...
public List<Site_Program_Term> SiteProgramTerms { get; set; }
}
then you can rewrite your query as
var terms = db.Terms
.Where(t => t.SiteId == id && t.IsActive)
.Select(t => new
{
Id = t.Id,
SiteId = t.SiteId,
Name = t.Name,
IsHoliday = t.IsHoliday,
DateStart = t.DateStart,
DateEnd = t.DateEnd,
Year = t.Year,
PubProgram = t.SiteProgramTerms.Where(spt => spt.SiteId == id && spt.Year == t.Year).Count()
})
.OrderBy(n => n.DateStart)
.ToList();
Note that this time you don't need to include spt.TermId == t.Id condition, because SiteProgramTerms property contains only site program terms with TermId that matches the Id of the Term. Also note that the first .ToList() should be omitted, because it causes query to be sent to the SQL server as multiple SELECT queries (as opposed to just one SELECT when .ToList() is not present).

Filter Data based on priority in LINQ

The fields in my Rate Table are Route, VehicleMasterId, VehicleType, Material, Client, UnitRate etc.
The priority order on which I have to fetch a single row is : VehicleNo > Route > Client > VehicleType, Material
Suppose I have 2 rows with same data except 1 has Client and Vehicle Type and the other one has VehicleNo.Then based on my priority, I should pick the rate of the row with VehicleNo.
To excute this In linq I have first picked all the rows with matching data. Here is my code.
public RateMasterDataModel GetRateMasterforCn(Consignment cn){
// I will always pass all the above fields in cn
var rateMaster = (from rate in Context.RateMaster
where rate.FromDate <= cn.Cndate
&& rate.ToDate >= cn.Cndate
&& (rate.VehicleTypeId != null ? rate.VehicleTypeId == cn.VehicleTypeId : true)
&& (rate.VehicleMasterId != null ? rate.VehicleMasterId == cn.VehicleMasterId : true)
&& (rate.ClientId != null ? rate.ClientId == cn.ClientId : true)
&& (rate.RouteId != null ? rate.RouteId == cn.RouteId : true)
&& (rate.MaterialMasterId != null ? rate.MaterialMasterId == cn.MaterialMasterId : true)
select new RateMasterDataModel
{
RateMasterId = rate.RateMasterId,
FromDate = rate.FromDate,
ToDate = rate.ToDate,
ClientId = rate.ClientId ,
VehicleMasterId = rate.VehicleMasterId,
VehicleTypeId = rate.VehicleTypeId,
MaterialMasterId = rate.MaterialMasterId,
UnitRate = rate.UnitRate,
LoadTypeId = rate.LoadTypeId,
LoadingPointId = rate.RouteId,
CalculationMasterId = rate.CalculationMasterId
}).ToList();
}
Please suggest how to filter after this.
You can use below code to get records ordered by VehicleNo > Route
.OrderBy(v=>v.VehicleNo).ThenBy(r=>r.RouteId)
Add multiple .ThenBy() clause as per your column requirement for sorting the data.
You mean to say if the row which doesn't have the vehicalno. filld-up then the row having Route must be selected.is it correct?

Convert SQL Server query to Entity Framework query

I have a SQL Server query like this:
select
month(fact_date) as month,
sum(case when beef_dairy_stat = 1 and param_id = 1 then 1 else 0 end) as cnt
from
user_behave_fact
where
YEAR(fact_date) = 2018
group by
month(fact_date)
order by
month
with a result of
month cnt
------------
1 10
2 20
Now I need to convert this query to its corresponding Entity Framework query.
This is my current attempt:
var sql_rez_ICC = new List<Tuple<int, int>>();
sql_rez_ICC = db.user_behave_fact
.Where(x => x.fact_date.Value.Year == selected_year)
.GroupBy(y => y.fact_date.Value.Month)
.Select(y =>new { month = y.Select(x=>x.fact_date.Value.Month), icc_count = y.Count(x => x.beef_dairy_stat == true && x.param_id == 1) })
.AsEnumerable()
.Select(y => new Tuple<int, int>(y.month, y.icc_count))
.ToList();
However on second .Select, I get an error on month which is
Cannot convert from System.Collection.Generic.IEnumrable to int
y.Select(x=>x.fact_date.Value.Month) returns an IEnumerable<int>. Use y.Key instead.

Losing Aliases when trying to group-by rows in linq sql query, how to group-by rows in this case

I am a newbie intern way over my head, I promise I have researched this thoroughly and tried many different things. The following linq query works, but I want to group rows by last and first name and then only show the rows that appear more than once. When I un-comment out the group by statement, all my aliases below become unrecognized and changing them to the actual db.table names doesn't help.
var query = from emps in db.Employees
join c in db.Cards on emps.SbiID equals c.SbiID
where c.StateID == 0 && c.CardNumberNumeric > 100000
//group emps by new {emps.Surname, emps.Name};
//orderby grp.Count() // something like 'where grp.Count > 1
select new
{
Surname = emps.Surname,
Name = emps.Name,
CorpID = emps.Identifier,
CardNum = c.CardNumber,
CostCenter = emps.EmployeeUserField.UF13,
Supervisor = (from e in db.Employees
where
e.Identifier.Equals(emps.EmployeeUserField.UF5)
select e.Surname).FirstOrDefault()
+ ", "
+ (from e in db.Employees
where e.Identifier.Equals(emps.EmployeeUserField.UF5)
select e.Name).FirstOrDefault(),
SupervisorID = emps.EmployeeUserField.UF5,
EmpCommence = emps.CommencementDateTime,
CardCommence = c.CommencementDateTime,
WorkPhone = emps.Telephone,
State = (from cf in db.ComboFields
from sp in db.StringProperties
where cf.ComboIndex.Equals(c.StateID)
&& cf.StringID.Equals(sp.StringID)
&& cf.TableName.Equals("Card")
&& cf.FieldName.Equals("StateID")
select sp.DefaultValue).FirstOrDefault()
};
this.tagsGridView.DataSource = query;
this.tagsGridView.DataBind();
I think the problem you're running into is that you're not flattening out your groups appropriately. For example:
var duplicateEmployees = db.Employees
.GroupBy(emp => emp, new EmployeeComparer())
.Where(grp => grp.Count() > 1)
.SelectMany(grp => grp.AsEnumerable());
var duplicateEmployeeInfo =
from emps in duplicateEmployees
join c in db.Cards on emps.SbiID equals c.SbiID
where c.StateID == 0 && c.CardNumberNumeric > 100000
select new
{
... what to select
};
With:
public class EmployeeComparer : IEqualityComparer<Employee>
{
public bool Equals(Employee x, Employee y)
{
return x.Surname == y.Surname && x.Name == y.Name;
}
public int GetHashCode(Employee obj)
{
unchecked { return (17 * obj.Surname.GetHashCode()) ^ (23 * obj.Name.GetHashCode()); }
}
}
This groups the employees by name, finds the groups that have a count > 1, then returns the elements of those groups. No guarantees on performance, but this should solve your issue.

SQL to Entity Framework query for distinct instances

I need to translate the following query from SQL into an Entity Framework query. Can anyone please help.
var query3 = string.Format(#"
SELECT DISTINCT
Boxes.BoxName,
Employees.EmployeeNumber,
Boxes.Port,
Boxes.SerialNumber
FROM
Eventlog
INNER JOIN Boxes
ON Eventlog.SerialNumber = Boxes.SerialNumber
INNER JOIN Employees
ON Eventlog.EmployeeId = Employees.EmployeeId
WHERE
ActionId = {4}
AND Boxes.Deactivated = 0
AND ( ('*' = '{0}')
OR (Boxes.SerialNumber = '{0}') )
AND ( (-1 = {1})
OR (Employees.EmployeeId = '{1}') )
AND EventTime >= '{2}'
AND EventTime <= '{3}'
", boxFilter3, ReportEmployeeIdFilter, ReportStartDate, ReportEndDate, actionFilter);
Something like this should work:
var query = (from log in context.Eventlog
join box in context.Boxes
on log.SerialNumber equals box.SerialNumber
join employee in context.Employees
on log.EmployeeId equals employee.EmployeeId
where log.ActionId == actionFilter
&& box.Deactivated == 0
&& (boxFilter3 == "*" || box.SerialNumber == boxFilter3)
&& (ReportEmployeeIdFilter == -1 || employee.EmployeeId == ReportEmployeeIdFilter)
&& log.EventTime >= ReportStartDate
&& log.EventTime <= ReportEndDate
select new
{
box.BoxName,
employee.EmployeeNumber,
box.Port,
box.SerialNumber
})
.Distinct();