Convert a SQL query to EntityFramework - sql-server

How can I convert this query to Entity Framework Query?
select Price,
(
select Cost.Title
from Cost
where Cost.CostID= CostItem.CostID
) as nameCost
from CostItem
where ItemID= 11

var result = dbContext.CostItems
.Where(item => item.ItemId == 11)
.Select(item => new { Price = item.Price, nameCose = item.Cost.Title })
Just make sure you have you relations in entity objects properly set up

Your query can also be written with a LEFT JOIN:
SELECT
ci.Price,
NameCost = c.Title
FROM CostItem ci
LEFT JOIN Cost c
ON c.CostID = ci.CostID
WHERE ci.ItemID = 11
Converting this to Linq using C#, you get:
var t =
from ci in CostItem
join c in Cost on ci.CostID equals c.CostID into lc
from c in lc.DefaultIfEmpty()
where ci.ItemID == 11
select new {
Price = ci.Price,
NameCost = c.Title
};

Related

EF6 query that behaves strangely using contains

I have an EF6 SQL Server query that behaves strangely when it is supplied with a List<int> of IDs to use. If bookGenieCategory = a value it works. If selectedAges is empty (count = 0) all is well. If the selectedAges contains values that exist in the ProductCategory.CategoryId column, the contains fails and NO rows are returned.
Note: AllocationCandidates is a view, which works properly on its own.
CREATE VIEW dbo.AllocationCandidate
AS
SELECT
p.ProductID, p.SKU as ISBN, p.Name as Title,
pv.MSRP, pv.Price, pv.VariantID, pv.Inventory,
ISNULL(plt.DateLastTouched, GETDATE()) AS DateLastTouched,
JSON_VALUE(p.MiscText, '$.AgeId') AS AgeId,
JSON_VALUE(p.MiscText, '$.AgeName') AS AgeName
FROM
dbo.Product AS p WITH (NOLOCK)
INNER JOIN
dbo.ProductVariant AS pv WITH (NOLOCK) ON pv.ProductID = p.ProductID
LEFT OUTER JOIN
dbo.KBOProductLastTouched AS plt WITH (NOLOCK) ON plt.ProductID = p.ProductID
WHERE
(ISJSON(p.MiscText) = 1)
AND (p.Deleted = 0)
AND (p.Published = 1)
AND (pv.IsDefault = 1)
GO
Do I have a typo here or a misplaced parenthesis in the following query?
var returnList = (from ac in _db.AllocationCandidates
join pc in _db.ProductCategories on ac.ProductID equals pc.ProductID
where (bookGenieCategory == 0
|| bookGenieCategory == pc.CategoryID)
&&
(selectedAges.Count == 0 ||
selectedAges.Contains(pc.CategoryID))
orderby ac.AgeId, ac.DateLastTouched descending
select ac).ToList();
Firstly, I would recommend extracting the conditionals outside of the Linq expression. If you only want to filter data if a value is provided, move the condition check outside of the Linq rather than embedding it inside the condition. This is generally easier to do with the Fluent Linq than Linq QL. You should also aim to leverage navigation properties for relationships between entities. This way an AllocationCandidate should have a collection of ProductCategories:
var query = _db.AllocationCandidates.AsQueryable();
if (bookGenieCategory != 0)
query = query.Where(x => x.ProductCategories.Any(c => c.CategoryID == bookGenieCategory);
The next question is what does the selectedAges contains? There is an Age ID on the AllocationCandidate, but your original query is checking against the ProductCategory.CategoryId??
If the check should be against the AllocationCandidate.AgeId:
if (selectedAges.Any())
query = query.Where(x => selectedAges.Contains(x.AgeID));
If the check is as you wrote it against the ProductCategory.CategoryId:
if (selectedAges.Any())
query = query.Where(x => x.ProductCategories.Any(c => selectedAges.Contains(c.AgeID)));
Then add your order by and get your results:
var results = query.OrderBy(x => x.AgeId)
.ThenByDescending(x => x.DateLastTouched);
.ToList();

Get data from a table after joining based on null value of joined table using LINQ

I have some tables like "Job" "AppliedJob" "JobOffer" "Contract" "Employeer"
Description: When employeer post job it is stored in "Job" table with his ID. If a freelancer apply to the job it is stored in "AppliedJob" table with his ID. Then Employeer sees the application and send offer to the freelancer and it is stored in "JobOffer" table. If freelancer accept the offer it is then stored in "Contract" table. At first in "Contract" ContractID, OfferID and StratDate are stored and CompletedDate is stored as null. When the contract is completed the CompletedDate field is modified with date.
Want: I want to return all jobs with no completed contract
I tried:
[HttpGet]
[Route("api/PrivateApi/GetEmployeerPostedJob/")]
public object GetEmployeerPostedJob(int id)
{
var data = (from j in db.Jobs
where j.EmployeerID == id
join apl in db.AppliedJobs
on j.JobID equals apl.JobID
join o in db.JobOffers
on apl.AppliedJobID equals o.AppliedJobID
join con in db.Contracts
on o.OfferID equals con.OfferID
where con.CompletedDate == null
select new
{
j.JobTitle,
j.JobID,
j.Budget,
j.Deadline,
j.Employeer,
j.JobDetails,
j.PublishDate,
j.ReqSkill,
j.NoOFFreelancer,
j.Preference,
Category1=j.Category,
totalAppliedFreelancer=(from aple in db.AppliedJobs where j.JobID ==aple.JobID select aple).Count(),
Category = (from gg in db.Categories where gg.CategoryID == j.Category select gg.CategoryName).FirstOrDefault()
}).ToList();
return data.AsEnumerable();
}
But it returns no jobs.
How can i get all jobs which are not completed yet(CompletedDate == null in Contract table)?
I want to show the employeer's posted jobs on his page but only those jobs that are not completed
The above (die to one to many relationships involved) can be paraphrased as
return all jobs with no completed contract
while the way you wrote the query, besides the possible data duplication, it answers the question
return all jobs with existing, but not completed contract
i.e. is missing the jobs w/o applied job, applied job w/o offer and offer w/o contract.
The correct query would be something like this:
from job in db.Jobs
where job.EmployeerID == id
join jobContract in (
from appliedJob in db.AppliedJobs
join offer in db.JobOffers on appliedJob.AppliedJobID equals offer.AppliedJobID
join contract in db.Contracts on offer.OfferID equals contract.OfferID
select new { appliedJob, offer, contract }
) on job.JobID equals jobContract.appliedJob.JobID into jobContracts
where !jobContracts.Any(jobContract => jobContract.contract.CompletedDate != null)
select ...
The query could further be simplified by using navigation properties, but since I don't see navigation properties between AppliedJob and JobOffer, I'm leaving that for you.
Update: Here is the same query with navigation properties (by simplified I meant no need for join operators):
from job in db.Jobs
let completedContracts =
from appliedJob in job.AppliedJobs
from offer in appliedJob.JobOffers
from contract in offer.Contracts
where contract.CompletedDate != null
select contract
where !completedContracts.Any()
select ...
This LINQ query doesn't work on live server (sql-2008) But works on my local VS 2013. Is there any mistake if my live database is empty at first time?
#Ivan Stoev
public object BrowseJobs()
{
var skills = db.Skills.ToDictionary(d => d.SkillID, n => n.SkillName);
var jobData = (from j in db.Jobs where j.Preference==2
//from cj in j.ClosedJobs.DefaultIfEmpty()
join cj in db.ClosedJobs.DefaultIfEmpty()
on j.JobID equals cj.JobID into closedJob
where !closedJob.Any()
join c in db.Categories on j.Category equals c.CategoryID
join jobContract in
(
from appliedJob in db.AppliedJobs.DefaultIfEmpty()
from offer in appliedJob.JobOffers.DefaultIfEmpty()
from contract in db.Contracts.DefaultIfEmpty()
select new { appliedJob, offer, contract }
).DefaultIfEmpty()
on j.JobID equals jobContract.appliedJob.JobID into jobContracts
where !jobContracts.Any(jobContract => jobContract.contract.CompletedDate != null)
select new
{
JobTitle = j.JobTitle,
JobID = j.JobID,
ReqSkillCommaSeperated = j.ReqSkill,
Category = c.CategoryName,
Budget=j.Budget,
Deadline=j.Deadline,
JobDetails=j.JobDetails,
PublishDate=j.PublishDate,
TotalApplied=(from ap in db.AppliedJobs where j.JobID == ap.JobID select ap.AppliedJobID).DefaultIfEmpty().Count()
}).AsEnumerable()
.Select(x => new
{
JobID = x.JobID,
JobTitle = x.JobTitle,
Category = x.Category,
Budget = x.Budget,
Deadline = x.Deadline,
JobDetails = x.JobDetails,
PublishDate = x.PublishDate,
SkillNames = GetSkillName(x.ReqSkillCommaSeperated, skills),
TotalApplied = (from ap in db.AppliedJobs where x.JobID == ap.JobID select ap.AppliedJobID).DefaultIfEmpty().Count()
}).ToList();
return jobData.AsEnumerable();
}

How to check for NullReferenceException in LINQ result

I have a LINQ query that works fine with EF in my DAL:
using (var mLEntities = new myLab02Entities1())
{
var test = from c in mLEntities.Chemicals
from u in c.Usages
select new
{
cChemID = c.Chem_ID,
c.Name,
c.Supplier,
c.Grade,
c.OrderNo,
c.BatchNo,
c.EntryDate,
c.CreatedBy,
cUser = u.Person.PersName,
uChemID = u.Chem_ID,
u.Study_ID,
u.UsedBy,
uUser = u.Person.PersName,
u.UseDate,
u.Project.StudyNo,
u.Project.ProjectName,
};
Usages is a Navigation property of Chemicals (1 chem : n usa), and Person and Projects are both Navigation properties of Usages (both 1 : 1).
Then I wanted to put this query in my Business Logic and wrote:
IList<ChemicalBDO> chemicalListBDO = chemListDAO.GetChemicalsListFromDB();
var test = from c in chemicalListBDO
from u in c.Usages
select new
{
cChemID = c.Chem_ID,
c.Name,
c.Supplier,
c.Grade,
c.OrderNo,
c.BatchNo,
c.EntryDate,
c.CreatedBy,
cUser = u.Person.PersName,
uChemID = u.Chem_ID,
u.Study_ID,
u.UsedBy,
uUser = u.Person.PersName,
u.UseDate,
u.Project.StudyNo,
u.Project.ProjectName
};
That is, I first query my EF DBcontext and get my Chemicals Entity, and than I write a query against this Chemicals Entity.
For me the strange thing is that the last Code throws a System.NullReferenceExeption, because u.Person and u.Project can be NULL. But the first query does not throw exceptions, what is the reason for that?
How can I handle the NULL reference in the select query, can I check for NULL with "if", "?" or "??" ?
Btw: I thought having the complex query in the DAL is no good programming practice, is that true or can I let the Code there?
Any help is appreciated.
This should fix this problem:
IList<ChemicalBDO> chemicalListBDO = chemListDAO.GetChemicalsListFromDB();
var test = from c in chemicalListBDO
from u in c.Usages
select new
{
cChemID = c.Chem_ID,
c.Name,
c.Supplier,
c.Grade,
c.OrderNo,
c.BatchNo,
c.EntryDate,
c.CreatedBy,
cUser = u.Person != null ? u.Person.PersName : string.Empty,
uChemID = u.Chem_ID,
u.Study_ID,
u.UsedBy,
uUser = u.Person != null ? u.Person.PersName : string.Empty,
u.UseDate,
u.Project != null ? u.Project.StudyNo : -1,
u.Project != null ? u.Project.ProjectName : string.Empty
};

Linq query count

select count(tblVV.VNme) as total,
tblvV.VNme
from tblVV
inner join tblRV
on tblVV.MID=tblRV.ID
inner join tblRe
on tblRV.RID=tblRe.RID
where tblRe.StartDate>= '2016-07-01 00:00:00' and
tblRe.EndDate<= '2016-07-31 23:59:59' and
tblRe.Reg= 'uk' and
tblRV.RegNo='BR72' and
tblVV.VNme <>''
group by tblVV.VNme
For the above query I get:
total Vame
1 DDSB
11 MV
The above SQL query shows me correct data so now i try to convert above query to linq query
[WebMethod]
public static string GetVo(string RegNo)
{
string data = "[";
try
{
Ts1 DB = new Ts1();
var re = (from vehvoila in DB.tblVV
join regveh in DB.tblRV on vehvoila.MID equals regveh.ID
join reg in DB.tblReg on regveh.RID equals reg.RID
where regveh.RegNo == RegNo &&
vehvoila.Vame != ""
group vehvoila by vehvoila.Vame into g
select new
{
VNme = g.Key,
cnt = g.Select(t => t.Vame).Count()
}).ToList();
if (re.Any())
{
data += re.ToList().Select(x => "['" + x.Vame + "'," + x.cnt + "]")
.Aggregate((a, b) => a + "," + b);
}
data += "]";
}
linq query show me return data like this
[['DDSB',1],['DPSB',1],['DSB',109],['MV',39],['PSB',1]]
Whereas I want data this
[['DDSB',1],['MV',11]]
Now the data which return SQL query is correct so how I correct linq query
Note: forget fromdate,todate,region parameter in SQL query . because I have page in which I put dropdown and fromdate and todate picker and there is button so when I select values i.e. UK, and dates then data is display in table then when I click on any row in table then I want to get this data in data +=”]”;
actually above linq query work behind clicking on row
total Vame
1 DDSB
11 MV
You can write it all like this:
Ts1 db = new Ts1();
var result = (from vehvoila in db.tblVV
join regveh in db.tblRV on vehvoila.MID equals regveh.ID
join reg in db.tblReg on regveh.RID equals reg.RID
where reg.StartDate >= new DateTime(2016, 7, 1) &&
reg.EndDate < new DateTime(2016, 8, 1) &&
reg.Reg == "uk" &&
regveh == "BR72" &&
vehvoila != ""
group vehvoila by vehvoila.Vame into g
select $"[{g.Key},{g.Count()}]");
var data = $"[{string.Join(",", result)}]";
Because you only use the result for the creation of the string in the select I just return the string formatted for a single item and then later used string.Join instead of using the .Aggregate - I think a bit cleaner
The $"{}" syntax is the C# 6.0 string interpolation
In the condition of the EndDate I decided to use < instead of the <= with the change of the date - At least in oracle when you partition the table by date it is better for performance - maybe also in sql server
Without string interpolation:
Ts1 db = new Ts1();
var result = (from vehvoila in db.tblVV
join regveh in db.tblRV on vehvoila.MID equals regveh.ID
join reg in db.tblReg on regveh.RID equals reg.RID
where reg.StartDate >= new DateTime(2016, 7, 1) &&
reg.EndDate < new DateTime(2016, 8, 1) &&
reg.Reg == "uk" &&
regveh == "BR72" &&
vehvoila != ""
group vehvoila by vehvoila.Vame into g
select new { Key = g.Key, Count = g.Count()})
.AsEnumerable()
.Select(g => string.Format("[{0},{1}]",g.Key, g.Count));
var data = string.Format("[{0}]",string.Join(",", result));

SQL Query Help - searching on multiple 'pairs' or data

I'm struggling to work out how to do a SQL query on a database that I have.
I have a view (which can be changed) which shows the relationships between the tables.
This creates a view as follows:
What I need to be able to do is search on one or more 'Attribute Pairs'
for example
I want to search for records with:
(
(AttributeName='FileExtension' AND AttributeValue='.pdf')
AND (AttributeName='AccountNumber' AND AttributeValue='ABB001'
)
As you can tell, this is not working as AttributeName cant be two things at once. I have this working with an OR filter, but I want it to find records that have all attribute pairs
SELECT
dbo.SiconDMSDocument.SiconDMSDocumentID,
dbo.SiconDMSAttribute.SiconDMSAttributeID,
dbo.SiconDMSAttribute.AttributeFriendlyName,
dbo.SiconDMSAttribute.AttributeName,
dbo.SiconDMSDocumentAttribute.AttributeValue,
dbo.SiconDMSAttribute.DataType,
dbo.SiconDMSDocumentType.SiconDMSDocumentTypeID,
dbo.SiconDMSDocumentType.DocumentTypeName,
dbo.SiconDMSDocumentType.DocumentTypeFriendlyName,
dbo.SiconDMSModule.SiconDMSModuleID,
dbo.SiconDMSModule.ModuleName,
dbo.SiconDMSModule.ModuleFriendlyName,
dbo.SiconDMSDocument.SiconDMSDocumentTypeModuleID
FROM dbo.SiconDMSDocument
INNER JOIN dbo.SiconDMSDocumentAttribute ON dbo.SiconDMSDocument.SiconDMSDocumentID = dbo.SiconDMSDocumentAttribute.SiconDMSDocumentID
INNER JOIN dbo.SiconDMSAttribute ON dbo.SiconDMSDocumentAttribute.SiconDMSAttributeID = dbo.SiconDMSAttribute.SiconDMSAttributeID
AND
(
(dbo.SiconDMSAttribute.AttributeName = 'Reference' AND dbo.SiconDMSDocumentAttribute.AttributeValue='12345')
OR (dbo.SiconDMSAttribute.AttributeName = 'AccountNumber' AND dbo.SiconDMSDocumentAttribute.AttributeValue='ABB001')
)
INNER JOIN dbo.SiconDMSDocumentTypeModule ON dbo.SiconDMSDocument.SiconDMSDocumentTypeModuleID = dbo.SiconDMSDocumentTypeModule.SiconDMSDocumentTypeModuleID
INNER JOIN dbo.SiconDMSDocumentType ON dbo.SiconDMSDocumentTypeModule.SiconDMSDocumentTypeID = dbo.SiconDMSDocumentType.SiconDMSDocumentTypeID
INNER JOIN dbo.SiconDMSModule ON dbo.SiconDMSDocumentTypeModule.SiconDMSModuleID = dbo.SiconDMSModule.SiconDMSModuleID
WHERE
(dbo.SiconDMSDocument.Deleted = 0)
AND (dbo.SiconDMSDocumentAttribute.Deleted = 0)
AND (dbo.SiconDMSAttribute.Deleted = 0)
AND (dbo.SiconDMSDocumentType.Deleted = 0)
AND (dbo.SiconDMSDocumentTypeModule.Deleted = 0)
AND (dbo.SiconDMSModule.Deleted = 0)
Are there any SQL functions that will allow me to do something like this?
I'm not sure what your complicated query has to do with the question of searching for attribute pairs.
Assuming you want the document ids that have both attributes:
select SiconDMSDocumentID
from yourview y
where (AttributeName = 'FileExtension' AND AttributeValue = '.pdf') or
(AttributeName = 'AccountNumber' AND AttributeValue = 'ABB001'
group by SiconDMSDocumentID
having count(*) = 2;
Or, if the attributes could have multiple values:
having count(distinct AttributeName) = 2

Resources