How to use PredicateBuilder together with Inner Join - sql

Database
SQL
SELECT * FROM City as a
inner join Country as b
on a.CountryCode= b.Code
where b.CountryName like %countryName%
LINQ
from city in db.Set<City>()
join country in db.Set<Country>() on city.CountryCode equals country.Code
where DbFunctions.Like(country.Name, searchParam.SearchValue)
select city;
How can I apply the LINQ into PredicateBuilder which is going use for the search function for the later on.
var Predicate = PredicateBuilder.New<City>(true);
if (!string.IsNullOrEmpty(searchParam.SearchValue))
{
switch (searchParam.SearchBy)
{
case "SearchCity":
Predicate = Predicate.And(x =>
x.Name.Contains(searchParam.SearchValue)
);
break;
default:
break;
}
}
I tested with this line in order to display all the corresponding data for my datatable
result = querys.Where(a => a.CountryCode.Contains(searchParamInString.SearchValue));
But CountryCode still didn't equals to Code because when I tried using
a.Code
it still display City doesn't contain Code

Related

How do I translate my SQL Query with Having MAX in LINQ?

I'd like to translate this SQL Query in LINQ with EF
SELECT Agts.AgtNum, Agts.AgtLastname, Agts.AgtFirstname, COUNT(Co.CoEnd) FROM [dbo].Agts AS Agts
INNER JOIN [dbo].[Contracts] AS Co ON Agts.AgtNum = Co.AgtNum
GROUP BY Agts.AgtNum, Agts.AgtLastname, Agts.Firstname
HAVING MAX(Co.CoEnd) <= '2020-05-17'
ORDER BY AgtNum asc
I tried that :
public List<AgentToPurge> AgentsToPurge(DateTime datePurge)
{
return (from agent in this.Entities.Agts
join contract in this.Entities.Contracts on agent.AgtNum equals contract.AgtNum
group agent by agent.AgtNum into g
where g.CoEnd <= datePurge
select new AgentToPurge
{
Id = g.Key,
Lastname = g.Key.AgtLastname,
Firstname = g.Key.AgtFirstname,
Contract_Deleted = g.Key.CoEnd.Count()
}).ToList();
}
But the line
where g.CoFin <= datePurge
doesn't work.
I think my "select new" isn't correct either.
Could you help me to solve this ?
Try the following query:
public List<AgentToPurge> AgentsToPurge(DateTime datePurge)
{
return (from agent in this.Entities.Agts
join contract in this.Entities.Contracts on agent.AgtNum equals contract.AgtNum
group contract by new { agent.AgtNum, agent.AgtLastname, agent.AgtFirstname } into g
where g.Max(x => x.CoEnd) <= datePurge
select new AgentToPurge
{
Id = g.Key.AgtNum,
Lastname = g.Key.AgtLastname,
Firstname = g.Key.AgtFirstname,
Contract_Deleted = g.Sum(x => x.CoEnd != null ? 1 : 0)
}).ToList();
}
Note that LINQ query is built from classes and navigation properties and probably you will not need JOIN, if you have properly defined Model.

Left outter join linq

How do i change the training events into a left outer join in training events im very basic at linq so excuse my ignorance its not retrieve records that don't have any trainnevent reference attached to it
var q = from need in pamsEntities.EmployeeLearningNeeds
join Employee e in pamsEntities.Employees on need.EmployeeId equals e.emp_no
join tevent in pamsEntities.TrainingEvents on need.TrainingEventId equals tevent.RecordId
where need.EmployeeId == employeeId
where need.TargetDate >= startdate
where need.TargetDate <= enddate
orderby need.TargetDat
It's best to use where in combination with DefaultIfEmpty.
See here: LEFT JOIN in LINQ to entities?
var query2 = (
from users in Repo.T_Benutzer
from mappings in Repo.T_Benutzer_Benutzergruppen.Where(mapping => mapping.BEBG_BE == users.BE_ID).DefaultIfEmpty()
from groups in Repo.T_Benutzergruppen.Where(gruppe => gruppe.ID == mappings.BEBG_BG).DefaultIfEmpty()
//where users.BE_Name.Contains(keyword)
// //|| mappings.BEBG_BE.Equals(666)
//|| mappings.BEBG_BE == 666
//|| groups.Name.Contains(keyword)
select new
{
UserId = users.BE_ID
,UserName = users.BE_User
,UserGroupId = mappings.BEBG_BG
,GroupName = groups.Name
}
);
var xy = (query2).ToList();
Which is equivalent to this select statement:
SELECT
T_Benutzer.BE_User
,T_Benutzer_Benutzergruppen.BEBG_BE
-- etc.
FROM T_Benutzer
LEFT JOIN T_Benutzer_Benutzergruppen
ON T_Benutzer_Benutzergruppen.BEBG_BE = T_Benutzer.BE_ID
LEFT JOIN T_Benutzergruppen
ON T_Benutzergruppen.ID = T_Benutzer_Benutzergruppen.BEBG_BG

IQueryable LINQ ordering and grouping

I have the following (incorrect) LINQ function (updated):
public IQueryable<ClassUsageReport> GetClassUsage()
{
//Class Code, Title, Usage, FiscalYear
var queryable = (from agencyplan in _agencyPlansList
join classSchedule2012 in _classSchedule2012List
on agencyplan.Id equals classSchedule2012.AgencyPlanId
join classes in _classesList
on classSchedule2012.Class.Id equals classes.Id
orderby agencyplan.PlanYear.FiscalYear descending, classes.ClassCode.Count() descending
group agencyplan by new
{
agencyplan.PlanYear.FiscalYear,
classes.ClassCode,
classes.Title
} into gcs
select new ClassUsageReport
{
ClassCode = gcs.Key.ClassCode,
Title = gcs.Key.Title,
Usage = gcs.Key.ClassCode.Count(),
FiscalYear = gcs.Key.FiscalYear
}
);
return queryable.AsQueryable();
}
I am having trouble with the Group By and Order By clauses. Also with the COUNT().
I have written the correct SQL statement, that produces the results as needed (and expected):
select py.fiscalyear, c.classcode, c.title, count(c.classcode) as usage from classschedule2012 cs
inner join classes c on cs.class_id = c.id
inner join agencyplans ap on cs.agencyplanid = ap.Id
inner join planyears py on ap.planyear_id = py.id
group by py.fiscalyear, c.classcode, c.title
order by py.fiscalyear desc, usage desc
What am I doing wrong with the grouping and ordering in my LINQ statement? I would like it to include "usage" like my SQL has. How can I get count to properly reflect the true count? As the query is at the moment, it only returns "9" in every row. This does not match my SQL, as the real results should be "55, 44, 14, 13" etc....
EDIT: 11/14/2013
Here is the final result:
public IQueryable<ClassUsageReport> GetClassUsage()
{
//Class Code, Title, Usage, FiscalYear
var queryable = (from agencyplan in _agencyPlansList
join classSchedule2012 in _classSchedule2012List
on agencyplan.Id equals classSchedule2012.AgencyPlanId
join classes in _classesList
on classSchedule2012.Class.Id equals classes.Id
where classes.Active = true
orderby agencyplan.PlanYear.FiscalYear descending
group agencyplan by new
{
agencyplan.PlanYear.FiscalYear,
classes.ClassCode,
classes.Title
} into gcs
select new ClassUsageReport
{
ClassCode = gcs.Key.ClassCode,
Title = gcs.Key.Title,
Usage = gcs.Count(),
FiscalYear = gcs.Key.FiscalYear
}
);
return queryable.AsQueryable().OrderByDescending(x => x.FiscalYear).ThenByDescending(x => x.Usage);
}
Once you group, you only have access to the columns you've grouped by and aggregate data of the other columns (like SUM or COUNT). In your query's select portion, you need to use g. instead of classes..
Try using g.Key in the select statement.

JOIN and LEFT JOIN equivalent in LINQ with Method Syntax

I am converting a SQL query to LINQ that creates a left join with 1-to-1 mapping, and it has to be in Method Syntax. I have been pulling off my hair trying to accomplish this to no veil. I can do it in Lambda Syntax. Below is the example query I am trying to run. They are not actual code. Would someone point out what I am doing wrong?
SQL:
SELECT item.*, item_status.*
FROM item
LEFT JOIN item_status
ON item.ID = item_status.itemID
AND item_status.FLAGGED = true
WHERE item.published_date > "2008-06-19"
LINQ:
var linq_query = (
from selected_item in item
join selected_item_status in item_status
on selected_item.ID equals item_status.itemID into joined
from item_status in joined.DefaultIfEmpty()
where item_status.FLAGGED = true
select new {selected_item, selected_item_status}).ToList();
The join ... into becomes a GroupJoin and the second from becomes a SelectMany:
var linq_query = Item
.GroupJoin(
item_status.Where(x => x.selected_item_status.FLAGGED), // EDIT: Where clause moved here.
selected_item => selected_item.ID,
selected_item_status => selected_item_status.itemID,
(selected_item, joined) => new
{
selected_item,
statuses = joined.DefaultWithEmpty(),
})
.SelectMany(x => x.statuses.Select(selected_item_status => new
{
x.selected_item,
selected_item_status,
}))
// EDIT: Removed where clause.
.ToList();
It looks like the Where makes the left outer join unnecessary, as null statuses will be filtered out anyway.
EDIT: No, upon reviewing the SQL it looks like your LINQ query is slightly incorrect. It should be:
var linq_query = (
from selected_item in item
join selected_item_status
in (
from status in item_status
where status.FLAGGED
select status)
on selected_item.ID equals item_status.itemID into joined
from item_status in joined.DefaultIfEmpty()
select new {selected_item, selected_item_status}).ToList();

Performing a left outer join when an nhibernate filter is applied

I am trying to perform a LEFT OUTER JOIN with nhibernate criteria. I also have a filter that gets applied to my queries.
The problem I have is the filter stops the left outer join working properly if the join result is null.
As a very simple example I want to return all the musicians, and if they are in a band then also their band
NHibernate generates the following sql
SELECT this_.Name, band2_.Name
FROM Musicians this_
left outer join [Band] band2_
on this_.BandID = band2_.ID
WHERE (band2_.IsDeleted = 0)
which won't return the musicians if they aren't in a band. What I want is something like
SELECT this_.Name, band2_.Name
FROM Musicians this_
left outer join [Band] band2_
on this_.BandID = band2_.ID
WHERE this_.ID = 4894 /* #p3 */
(band2_.ID IS NULL OR band2_.IsDeleted = 0)
Is this possible with nhibernate?
UPDATE
var projections = new[]
{
Projections.Property("Musician.Name").As("MusicianName"),
Projections.Property("Band.Name").As("BandName")
};
return this.sessionProvider.GetSession().CreateCriteria<Musician>("Musician")
.CreateCriteria("Musician.Band", "Band", JoinType.LeftOuterJoin)
.SetProjection(projections)
.Add(Restrictions.Eq("Musician.ID", parameters.MusicianId))
.SetResultTransformer(Transformers.AliasToBean<MusicianDetailsResult>())
.UniqueResult<MusicianDetailsResult>();
The filter is defined with FluentNHibernate
this.WithName(FilterName).WithCondition("IsDeleted = 0")
This is a bug in NHibernate.
I used proposed workaround and set useManyToOne on the filter to false. This property isn't currently in FluentNhibernate so I just do it in ExposeConfiguration
foreach (var key in cfg.FilterDefinitions.Keys)
{
filter = cfg.FilterDefinitions[key];
cfg.FilterDefinitions[key] = new FilterDefinition(
filter.FilterName,
filter.DefaultFilterCondition,
filter.ParameterTypes, false);
}
Firstly, this is much easier if you simply map Band to Musician as a reference:
public class MusicianDbMap : ClassMap<Musician>
{
public MusicianDbMap()
{
...
References(x => x.Band)
.Nullable()
.Not.LazyLoad(); // Or lazy load... either way
}
}
Then you can just run a simple query - here it is in Linq-2-NHibernate:
Session.Linq<Musician>()
.Where(x => x.Band == null || !x.Band.IsDeleted)
.ToList();
Secondly, I'm not sure about this statement of yours: "which won't return the musicians if they aren't in a band"... I'm not sure if that is correct. A left outer join should return all rows, regardless of whether they are in a band or not - are you sure that you haven't made an error somewhere else?