I have never used JOIN. When is proper time? - asp.net-mvc

I have never used JOIN(INNER, OUTER), and I don't have any idea when is the best scenario:
Here I have two examples of ActionResults that uses 2 or 3 queries to get an object, isn't better to use a JOIN instead?
First Example:
public ActionResult JobTags(int id)
{
var jobTagsList = (from j in db.JobTags
where j.JobID == id
select j.TagID).ToList();
var tags = (from j in db.Tags
where jobTagsList.Contains(j.ID.ToString())
select j).ToList();
return View(tags);
}
Can I just JOIN this two tables and select that j at the end?
Second Example:
public ActionResult ImageListWhoApp(int id)
{
//We get here the ID from Job page using dbo.Jobs
var userIdList = (from j in db.Jobs
where j.ID == id
select j.ID.ToString()).ToList();
//We get here who applied at this job using dbo.AppliedJobs
var appJobIdList = (from j in db.AppliedJobs
where userIdList.Contains(j.JobID.ToString())
select j.UserID).ToList();
//Finally we get here the avatars of the user who applied at the job
//We are using this as a hyperlink to user profile.
var appUserImage = (from j in db.Images
where appJobIdList.Contains(j.UserID.ToString())
select j).ToList();
return View(appUserImage);
}
Isn't this approach getting ridiculous? Or is normal to do stuff like this in this manner? How do I make a JOIN from this 3 SQL statements? Is it possible? is it the better way?
Thank you for your time!

You don't need joins. You can use navigation properties:
var tagsQry =
from tag in db.Tags
where tag.JobTag.JobID == id
select tag;
var userImageQry =
from img in db.Images
from appJob in db.AppliedJobs
where (img.UserID == appJob.UserID) && (appJob.Job.ID == id)
select img;
Even if you have no navigation properties, you don't need joins:
var tagsQry =
from tag in db.Tags
from jobTag in sb.JobTags
where (jobTag.JobID == id) && (tag.ID == jobTag.TagID)
select tag;
var userImageQry =
from img in db.Images
from appJob in db.AppliedJobs
from job in db.Jobs
where (img.UserID == appJob.UserID) && (appJob.JobID == job.ID) && (job.ID == id)
select img;
You can however use joins if you prefer the syntax. The DB side query execution plan will be exactly the same:
var tagsQry =
from tag in db.Tags
join jobTag in sb.JobTags on tag.ID equals jobTag.TagID
where (jobTag.JobID == id)
select tag;
var userImageQry =
from appJob in db.AppliedJobs
join img in db.Images on appJob.UserID equals img.UserID
join job in db.Jobs on appJob.JobID equals job.ID
where (job.ID == id)
select img;
In the second example you only need the query (or join) to Jobs if you don't have a foreign key constraint on AppliedJobs.JobID. If you do, you can compare AppliedJobs.JobID directly with id.

Related

Stored Procedure not giving the correct results in MVC Project

The SP that I use works as it should in SQL Management studio but this is the only query that gets me the wrong results in my project.
The SP query is:
SELECT DISTINCT Vehicle_Model_Range.ModelRange_ID, Users.MapLat,
Users.MapLong, Users.User_ID, Users.Status_ID, Vehicle_Details.Approved,
Vehicle_Details.Vehicle_Type
FROM
Users INNER JOIN
Vehicle_Details ON Users.User_ID =
Vehicle_Details.User_ID INNER JOIN
Vehicle_Make ON Vehicle_Details.Make_ID =
Vehicle_Make.Make_ID INNER JOIN
Vehicle_Model ON Vehicle_Details.Model_ID =
Vehicle_Model.Model_ID INNER JOIN
Vehicle_Model_Range ON Vehicle_Model.ModelRange_Id =
Vehicle_Model_Range.ModelRange_ID
WHERE
(Vehicle_Details.Approved = 1)
AND (Users.Status_ID = 1)
AND (Vehicle_Details.Vehicle_Type = 'V')
AND (Users.MapLat IS NOT NULL)
AND (Users.MapLong IS NOT NULL)
AND (Vehicle_Model_Range.ModelRange_ID IS NOT NULL)
Here's the code in VS that uses it:
public ActionResult Search(string Location)
{
GoogleMapEntities GE = new GoogleMapEntities();
var GetVeh = db.GetMapSearch().Where(x =>
(x.ModelRange_ID.ToString().StartsWith(Location)) && (x.Vehicle_Type
== "V") && (x.Status_ID == 1) && (x.Approved == true)).ToList();
return Json(GetVeh, JsonRequestBehavior.AllowGet);
}
Basically, what happens is that it plots all the points onto the map and does not follow the where statement that says that it should only plot for the following where conditions:
WHERE
(Vehicle_Details.Approved = 1)
AND (Users.Status_ID = 1)
AND (Vehicle_Details.Vehicle_Type = 'V')
AND (Users.MapLat IS NOT NULL)
AND (Users.MapLong IS NOT NULL)
AND (Vehicle_Model_Range.ModelRange_ID IS NOT NULL)
I have updated the model a few times and the SP does not work.
EDIT:
I have just added those where conditions to the linq query but still does not work. Any ideas?
EDIT: Full Stored Proc
USE [X_DB]
GO
/****** Object: StoredProcedure [dbo].[sp_App_MapSearch] Script Date:
2017/06/26 9:16:10 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROC [dbo].[sp_App_MapSearch]
AS
BEGIN
SELECT DISTINCT Vehicle_Model_Range.ModelRange_ID, Users.MapLat,
Users.MapLong, Users.User_ID, Users.Status_ID, Vehicle_Details.Approved,
Vehicle_Details.Vehicle_Type
FROM Users INNER JOIN
Vehicle_Details ON Users.User_ID =
Vehicle_Details.User_ID INNER JOIN
Vehicle_Make ON Vehicle_Details.Make_ID =
Vehicle_Make.Make_ID INNER JOIN
Vehicle_Model ON Vehicle_Details.Model_ID =
Vehicle_Model.Model_ID INNER JOIN
Vehicle_Model_Range ON Vehicle_Model.ModelRange_Id =
Vehicle_Model_Range.ModelRange_ID
WHERE
(Vehicle_Details.Approved = 1)
AND (Users.Status_ID = 1)
AND (Vehicle_Details.Vehicle_Type = 'V')
AND (Users.MapLat IS NOT NULL)
AND (Users.MapLong IS NOT NULL)
AND (Vehicle_Model_Range.ModelRange_ID IS NOT NULL)
END

Get value of each comma separated ID from another table in Web Api-not working in live

I have a 'Skill' table where i store skills. And in 'Job' table i store all required skill when post job like UpWork. Employeers have checkbox to select all required skills. But i store skillID like: 1,5,6,8 in job table. When i retrieve the job details, i want to get name of the all skills because i want to show SkillName with other details of the Job from job table. My Web Api:
[HttpGet]
[Route("api/JobApi/BrowseJobs/")]
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();
}
private string GetSkillName(string reqSkill, Dictionary<int, string> skills)
{
if (reqSkill == null) return string.Empty;
var skillArr = reqSkill.Split(',');
var skillNameList = skillArr.Select(skillId => skills[Convert.ToInt32(skillId)])
.ToList();
return String.Join(",", skillNameList);
}
My Problem is that the code is working well in my VS 2013. But when i uploaded it on a Godaddy live server, it doesn't work! returns 500 internal server error
Now i want to Make a SQL query instead of Linq. Can i do SQL with my desired result?
===================Edited=====================
your sql code is well worked. But i have others condition to be put on.
1. I need to show those job which is not closed yet (ClosedJobs table take the closed jobs ID).If a job ID is found on ClosedJobs table, it will not return in the list.
join cj in db.ClosedJobs.DefaultIfEmpty()
on j.JobID equals cj.JobID into closedJob
where !closedJob.Any()
Those job which is not found on Contracts table(Contracts table take the jobID of a job that is started as contract)
2nd Edit===================
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)
EXP: Job table has relation with AppliedJobs table. AppliedJobs table has relation with JobOffers. JobOffers has relation with Contracts.
i don't want to show those jobs that are completed.(Contracts.CompletedDate != null). When a contract starts the field CompletedDate is set to null. After completing the contract ,it is changed null to the completed date.
Where i will apply the condition?
How can i do that? Can you help me? #John Cappelletti
EDIT - Removed OUTER APPLY
Below is a simple example of using Stuff() and XML. If the sequence is important, then we must split the string first.
To be clear #Skills and #YourData are table variables and simply demonstrative.
Example
Declare #Skills table (SkillID int,SkillName varchar(50))
Insert Into #Skills values
(1,'ASP')
,(2,'JavaScript')
,(3,'AngularJS')
,(4,'WordPress')
,(5,'Joomla')
Declare #YourData table (ID int,ReqSkill varchar(50))
Insert Into #YourData values
(1,'2,3,4,5,1')
,(2,'3')
,(3,'3,4,5,2')
,(4,null)
Select A.ID
,Skills = Stuff((Select ',' +SkillName
From #Skills
Where charindex(concat(',',SkillID,','),','+A.ReqSkill+',')>0
For XML Path ('')),1,1,'')
From #YourData A
-- Your WHERE Statement Here --
Returns
ID Skills
1 ASP,JavaScript,AngularJS,WordPress,Joomla
2 AngularJS
3 JavaScript,AngularJS,WordPress,Joomla
4 NULL

Linq left outer join not working using DefaultIfEmpty

Using the technique found on the MSDN article "How to: Perform Left Outer Joins (C# Programming Guide)", I attempted to create a left outer join in my Linq code. The article mentions using the DefaultIfEmpty method in order to create a left outer join from a group join. Basically, it instructs the program to include the results of the left (first) collection even if there are no results in the right collection.
The way this program executes, however, it does so as if the outer join has not been specified.
In our database, AgentProductTraining is a collection of courses our agents have taken. Normally you cannot enter a Course onto it's appropriate table without entering a corresponding value into the CourseMaterials table. However, occasionally this may happen, so we want to make sure we return results even when a Course is listed in AgentProductTraining without any corresponding information in CourseMaterials.
var training = from a in db.AgentProductTraining
join m in db.CourseMaterials on a.CourseCode equals m.CourseCode into apm
where
a.SymNumber == id
from m in apm.DefaultIfEmpty()
where m.EffectiveDate <= a.DateTaken
&& ((m.TerminationDate > a.DateTaken) | (m.TerminationDate == null))
select new
{
a.AgentProdTrainId,
a.CourseCode,
a.Course.CourseDescription,
a.Course.Partner,
a.DateTaken,
a.DateExpired,
a.LastChangeOperator,
a.LastChangeDate,
a.ProductCode,
a.Product.ProductDescription,
m.MaterialId,
m.Description,
a.Method
};
The MSDN example uses a new variable subpet:
var query = from person in people
join pet in pets on person equals pet.Owner into gj
from subpet in gj.DefaultIfEmpty()
select new { person.FirstName, PetName = (subpet == null ? String.Empty : subpet.Name) };
So you must use your own "subpet", I rewrote your code using the submat variable:
var training = from a in db.AgentProductTraining
join m in db.CourseMaterials on a.CourseCode equals m.CourseCode into apm
where
a.SymNumber == id
from submat in apm.DefaultIfEmpty()
where
(submat.EffectiveDate <= a.DateTaken || submat.EffectiveDate == null) &&
(submat.TerminationDate > a.DateTaken || submat.TerminationDate == null)
select new
{
a.AgentProdTrainId,
a.CourseCode,
a.Course.CourseDescription,
a.Course.Partner,
a.DateTaken,
a.DateExpired,
a.LastChangeOperator,
a.LastChangeDate,
a.ProductCode,
a.Product.ProductDescription,
MaterialId = (submat==null?-1:submat.MaterialId),
Description = (submat==null?String.Empty:submat.Description),
a.Method
};

How to write if condition inside where clause in linq

I want to write if condition inside where clause. because if first name or last name is null I don't wani to add it in where clause . other wise I want to add it.
so I write
var query1 = from opv in _opvRepository.Table
join o in _orderRepository.Table on opv.OrderId equals o.Id
join gr in _graduandRepository.Table on opv.graduand_id equals gr.graduand_id
join pv in _productVariantRepository.Table on opv.ProductVariantId equals pv.Id
join p in _productRepository.Table on pv.ProductId equals p.Id
where (opv.ceremony_id == ceremony_id) &&
(!o.Deleted) && (opv.IsHireItem == true) &&
(!p.Deleted) &&
(!pv.Deleted) && (opv.ceremony_id == ceremony_id)
// group opv by opv.OrderId into g
select new
{
opvTable = opv,
grTable = gr,
};
// This is not working. I have problem in here. How to add this??
if (!String.IsNullOrEmpty(Fname))
query1 = query1.Where(grTable = > grTable.first_name == Fname);
var result = query1.ToList().Select(x =>
{
return new HireItemReportLine()
{
OrderId = x.opvTable.OrderId,
OrderDate=x.opvTable.Order.CreatedOnUtc,
Amount= x.opvTable.Order.OrderSubtotalExclTax,
PaymentMethod = x.opvTable.Order.PaymentMethodSystemName,
paidDate = x.opvTable.Order.CreatedOnUtc,
Fname = x.grTable.first_name,
MName = x.grTable.middle_name,
LName = x.grTable.last_name,
};
}).ToList();
What is the wrong with my cording??
Note that your original query selects an anonymous type with two properties: opvTable and grTable. So, you need to use one of those properties in the subsequent Where clause, like this:
query1 = query1.Where(item => item.grTable.first_name == Fname);

adding a record to a LINQ object (concat) taking values from another

Hi i'm looking for some help in how to append rows to an existing LINQ object. In the controller method below I have two result sets, i'm looping the Sites and want to add a record to the 'results' object for each record in the Sites object.
I've tried concat etc but not getting anywhere, just need s small example to assist, many thanks in advance, J
public IQueryable<UsersToSite> FindAllUsersToSites(int userId,SystemType obj)
{
var results = (from usersToSite in this._db.UsersToSites
where usersToSite.UserId == userId &&
usersToSite.SystemTypeId == obj
orderby usersToSite.Site.SiteDescription
select usersToSite);
// Now for each remaining Site append a record thats not physically in the database. From the view the user will be able to click these records to ADD new
// I'll then build in a search
var sites = (from site in this._db.Sites
where !(from o in _db.UsersToSites where (o.UserId == userId && o.SystemTypeId == obj) select o.SiteId).Contains(site.SiteId)
orderby site.SiteDescription
select site);
foreach (var site in sites)
{
// HERE I want to create the new ROW in results object
//results = new[results] { new { UsersToSiteId = null, AccessTypeId = null } }.Concat(sites);
//SiteId=site.SiteId,
//UsersToSiteId = 0,
//AccessTypeId = 0,
//UserId = userId
}
return results;
}
I don't think you can, if you want to have keep queryable.
However, if you materialize the results with ToList(), then you can:
var sites = (from site in this._db.Sites
where !(from o in _db.UsersToSites where (o.UserId == userId && o.SystemTypeId == obj) select o.SiteId).Contains(site.SiteId)
orderby site.SiteDescription
select site)
.ToList();
sites.Add(new Site { UsersToSiteId = null, etc });
If it was LINQ to Objects, you could do Concat.
The problem here that it can't do ConcatLINQ query that will have one part from SQL and another from objects. You need to materialize results first and then concat to object.

Resources