Get single column from using asp.net mvc ExecuteStoreQuery - asp.net-mvc

I want to return top 1 CustomerId from my table like this:
string nxtCustId = db.ExecuteStoreQuery<string>("SELECT TOP 1 CustId FROM CustomerMaster WHERE Id >=(SELECT Max(Id) FROM CustomerDetail ) ORDER BY Id ").ToString();
But it returns System.Data.Objects.ObjectResult1[System.String]
I want to do it with only ExecuteStoreQuery OR ExecuteStoreCommand.

string nxtCustId = db.ExecuteStoreQuery<string>(
"SELECT TOP 1 CustId FROM CustomerMaster WHERE Id >=(SELECT Max(Id) FROM CustomerDetail ) ORDER BY Id ")
.FirstOrDefault();
Having said that, don't create "IDs" this way; it's not multi-user safe. Use an autoincrement field or a generator/sequence.

Related

Using LINQ in an MVC project, how can I orderby a joined table's value?

I have two classes that I join together:
Item
(a bunch of properties)
(Foreign Key) int Category
Category
(Primary Key) int ID (this is referenced in Item)
string Name
Using LINQ in my MVC 5 project, I need to get and sort by the Name value from the category table using the ID in the Item table. With the code below, it is sorting in the order of the integer (1,2,3,4) instead of by the Name property in the Category table. How can I sort by the category table?
Controller code:
var items = from s in db.Items
join c in db.Categories on s.Category equals c.ID
select s;
switch (sortOrder)
{
case "Category_Desc":
//This is where it is selecting the integer ID instead of the string Name
items = items.OrderByDescending(s => s.Category);
break;
default:
items = items.OrderBy(s => s.Category);
break;
}
The Category property of your Item class is an int, so it is going to order those as it would any other integer. Right now your join serves no purpose since you are selecting only the items at the end of your query. Select an anonymous object instead which contains both the category and item, then you will have access to the properties of your Category class and can sort by the name and select only the Item.
var query= from s in db.Items
join c in db.Categories on s.Category equals c.ID
select new { item = s, cat = c };
switch (sortOrder)
{
case "Category_Desc":
//This is where it is selecting the integer ID instead of the string Name
items = items.OrderByDescending(s => s.cat.Name);
break;
default:
items = items.OrderBy(s => s.cat.Name);
break;
}
var items = query.Select(s => s.item);
You can try following
You could try following.
var result = db.Items
.Join(db.Categories,i=> i.Category, c=>c.Id,(i,c)=>new {item =i, category=c})
.OrderBy(x=>x.category.Name).Select(x=>x.item);
The crux is creating an interim structure, which comprises of Category.Name.

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

How to send a value from a select statement in MVC controller to Viewbag

I want to return just a value to ViewBag with the LINQ query below
var myCompanyName = (from c in db.Companies
where c.CompanyId == CompanyID
select c.CompanyName).ToString();
ViewBag.myCompanyName = myCompanyName;
In my MVC controller but I get the following output in my View.
SELECT [Extent1].[CompanyName] AS [CompanyName] FROM [dbo].[Companies] AS [Extent1] WHERE [Extent1].[CompanyId] = #p__linq__0 Company Name from Controller Action
The result ViewBag expected from view bag should be something like: CompanyName XYZ. Please how do I make this right?
Your not materializing your query, and I suspect you want to return a single value (not IEnumerable<string>) so you need to replace .ToString() with .FirstOrDefault()
var myCompanyName = (from c in db.Companies
where c.CompanyId == CompanyID
select c.CompanyName).FirstOrDefault();
ViewBag.myCompanyName = myCompanyName;
or if you did want a collection of string, then it would be .ToList()

Elegant linq solution for left joins with unique data

I woud like to inquire if my Linq solution below is a good solution or if there is a better way. I am new to using Linq, and am most familiar with MySQL. So I've been converting one of my past projects from PHP to .NET MVC and am trying to learn Linq. I would like to find out if there is a better solution than the one I came up with.
I have the following table structures:
CREATE TABLE maplocations (
ID int NOT NULL AUTO_INCREMENT,
name varchar(35) NOT NULL,
Lat double NOT NULL,
Lng double NOT NULL,
PRIMARY KEY (ID),
UNIQUE KEY name (name)
);
CREATE TABLE reservations (
ID INT NOT NULL AUTO_INCREMENT,
loc_ID INT NOT NULL,
resDate DATE NOT NULL,
user_ID INT NOT NULL,
PRIMARY KEY (ID),
UNIQUE KEY one_per (loc_ID, resDate),
FOREIGN KEY (user_ID) REFERENCES Users (ID),
FOREIGN KEY (loc_ID) REFERENCES MapLocations (ID)
);
CREATE TABLE Users (
ID INT NOT NULL AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
email VARCHAR(50) NOT NULL,
pass VARCHAR(128) NOT NULL,
salt VARCHAR(5) NOT NULL,
PRIMARY KEY (ID),
UNIQUE KEY unique_names (name),
UNIQUE KEY unique_email (email)
);
In MySQL, I use the following query to get the ealiest reservation at each maplocation with a non null date for any locations that don't have a reservation.
SELECT locs.*, if(res.resDate,res.resDate,'0001-01-01') as resDate, res.Name as User
FROM MapLocations locs
LEFT JOIN (
SELECT loc_ID, resDate, Name
FROM Reservations, Users
WHERE resDate >= Date(Now())
AND user_ID = Users.ID
ORDER BY resDate
) res on locs.ID = res.loc_ID
group by locs.ID
ORDER BY locs.Name;
In Linq, with Visual studio automatically creating much of the structure after connecting to the database, I have come up with the following equivalent to that SQL Query
var resList = (from res in Reservations
where res.ResDate >= DateTime.Today
select res);
var locAndRes =
(from loc in Maplocations
join res in resList on loc.ID equals res.Loc_ID into join1
from res2 in join1.DefaultIfEmpty()
join usr in Users on res2.User_ID equals usr.ID into join2
from usr2 in join2.DefaultIfEmpty()
orderby loc.ID,res2.ResDate
select new {
ID = (int)loc.ID,
Name = (string)loc.Name,
Lat = (double)loc.Lat,
Lng = (double)loc.Lng,
resDate = res2 != null ?(DateTime)res2.ResDate : DateTime.MinValue,
user = usr2 != null ? usr2.Name : null
}).GroupBy(a => a.ID).Select(b => b.FirstOrDefault());
So, I'm wondering is there a better way to perform this query?
Are these equivalent?
Are there any good practices I should be following?
Also, one more question, I'm having trouble getting this from the var to a List. doing something like this doesn't work
List<locAndResModel> locList = locAndRes.AsQueryable().ToList<locAndResModel>();
In the above snippet locAndResModel is just a class which has variables to match the int, string, double double, DateTime, string results of the query. Is there an easy way to get a list without having to do a foreach and passing the results to a constructor override? Or should I just add it to ViewData and return the View?
You'll want to take advantage of the automatic joins performed by the Entity Framework. Give this a try and let me know if it does what you want:
var locAndRes = from maplocation in MapLocations
let earliestReservationDate = maplocation.Reservations.Min(res => res.resDate)
let earliestReservation = (from reservation in mapLocation.Reservations
where reservation.resDate == earliestReservationDate && reservation.resDate >= DateTime.Today
select reservation).FirstOrDefault()
select new locAndResModel( maplocation.ID, maplocation.name, maplocation.Lat, maplocation.Lng, earliestReservation != null ? earliestReservation.resDate : DateTime.MinValue, earliestReservation != null ?earliestReservation.User.name : null)

Is it possible to group a LINQ set into a dictionary with one query?

Given a table of order items (OrderItems) that relates to a table of orders (Orders), which in turn relates to a table of users (Users), is it possible to retrieve all the OrderItems and group them into a dictionary by OrderId with just one query? ie. without performing an iteration over either the OrderItems result set or performing a query for each order.
Desired controller pseudo-code
Dictionary<int,IEnumerable<OrderItem>> OrderItems = DataContext.OrderItems.ToDictionary(Key => oi.OrderId, Value => oi.ToList());
Desired usage:
IEnumerable<OrderItem> currentOrderItems = OrderItems[123]; // where 123 is OrderId
Current Method
In my Controller I presently retrieve a user's orders and order items to pass to the Orders view:
ViewData["Orders"] = (from o in orders
where o.UserId equals CurrentUserId
orderby o.DateCreated descending)
.ToList();
ViewData["OrderItems"] = (from oi in DataContext.OrderItems
join o in DataContext.Orders
on oi.OrderId equals o.OrderId
where o.UserId equals CurrentUserId
select oi)
.ToList();
Then in my view, I retrieve all order items:
IEnumerable<OrderItem> orderItems = ViewData["OrderItems"] as IEnumerable<OrderItem>;
and use LINQ to group and display each order's order items:
IEnumerable<OrderItem> currentOrderItems = orderItems.Where(
i => i.OrderId == order.OrderId
);
This is fairly efficient as only two queries are passed to the database and some processing is done in the view. But ideally, this should be done in the controller.
Solved it! With ToLookup(...)
ViewData["OrderItems"] = (from oi in DataContext.OrderItems
join o in DataContext.Orders
on oi.OrderId equals o.OrderId
where o.UserId == UserId
select oi).ToLookup(oi => oi.OrderId, oi => oi);
And in my view:
ILookup<int,OrderItem> orderItems = ViewData["OrderItems"] as ILookup<int,OrderItem>;
foreach (Order order in orders)
{
DisplayOrder(order);
// Now display this order's items:
foreach(OrderItem item in orderItems[order.OrderId])
{
DisplayOrderItem(item);
}
}
A trace shows only one query to create the lookup.
Looks like I'm making a habit out of answering my own questions...
I think your best bet is to create a method that accepts a lambda for the key and a list to be inserted into the dictionary and then simply enumerates the list and adds to the dictionary using the key provided in the lambda. The method could be an Extension Method of IDictionary and let's call it say, AddRangeWithKeyType()

Resources