How to use TimeZoneInfo.ConvertTimeFromUtc in linq to sql? - c#

I have an user table called zeekuser in which I am storing Time Zone information related to user. while retrieving I using below code,
var v = (from s in dc.UserWebSites
join zk in dc.ZeekUsers on s.aspnet_User.UserId equals zk.UserId
where s.aspnet_User.LoweredUserName.Equals(strUsername.ToLower())
select new UserWebSiteInfo
{
CreateDt = TimeZoneInfo.ConvertTimeFromUtc(s.CreateDt, TimeZoneInfo.FindSystemTimeZoneById(zk.TimeZoneID)),
LastUpdateDt = TimeZoneInfo.ConvertTimeFromUtc(s.LastUpdate, TimeZoneInfo.FindSystemTimeZoneById(zk.TimeZoneID)),
LogoImage = s.LogoImage,
Nickname = s.Nickname,
Title1 = s.Title1,
Title2 = s.Title2,
SiteID = s.SiteID.ToString(),
TemplateID = s.TemplateID.ToString(),
TemplateName = s.WebSiteTemplate.ThemeName,
IsActive = s.IsActive,
IsRedirect = s.IsRedirect,
RedirectURL = s.RedirectURL,
UPID = s.UPID.ToString(),
UserId = s.aspnet_User.UserId.ToString(),
Username = s.aspnet_User.UserName,
UserProductName = s.UserProductDetail.Nickname,
PageCount = s.UserWebSitePages.Count(),
AuthorName = s.AuthorName,
AuthorURL = s.AuthorURL
}).OrderByDescending(y => y.LastUpdateDt);
info = v.ToList();
but I am getting below error
Method 'System.TimeZoneInfo FindSystemTimeZoneById(System.String)' has no supported translation to SQL.
Each different user can have different time zones. How can I resolve this?

I doubt that you can do that within the query that's sent to SQL Server. Instead, use AsEnumerable to change context to perform the final step on the .NET side:
var query = from s in dc.UserWebSites
join zk in dc.ZeekUsers on s.aspnet_User.UserId equals zk.UserId
where s.aspnet_User.LoweredUserName.Equals(strUsername.ToLower())
orderby s.LastUpdate descending
select new { Site = s, ZoneId = zk.TimeZoneID };
// Do the rest of the query in-process, so we can use time zones.
var results = (from pair in query.AsEnumerable()
let site = pair.Site
let zone = TimeZoneInfo.FindSystemTimeZoneById(pair.ZoneId)
select new UserWebSiteInfo {
// Select all your properties here
}).ToList();
This is assuming that there's not much more information in UserWebSites than you'll be using to construct the UserWebSiteInfo; if there is a load of information which is irrelevant, you should select the relevant parts explicitly in your initial db-side query.

Related

SQL to LINQ issue

I am working on a composite ranking website. I am trying to query the most recent ranking and the previous ranking side by side.
This query works great in SSMS, but I am unable to make this work in my C# code:
SELECT r.Name, l.RankValue AS currentValue, l.RankDT as CurrentDT, p.RankValue AS prevVal, p.RankDT AS prevDate
FROM RankLookupTB L
JOIN RankingsTB R ON L.RankID = R.RankID
FULL JOIN (SELECT rankid, rankvalue, RankDT FROM RankLookupTB WHERE Obselete = 1 and TeamID = 356) AS P ON l.RankID = p.RankID
WHERE l.TeamID = 356 and Obselete = 0
ORDER BY r.Name
Here is what I have in my Program:
var ranks = from r in _context.RankLookupTbs
where r.TeamId == id && r.Obselete == false
join s in _context.RankingsTbs on r.RankId equals s.RankId
join t in _context.RankLookupTbs on new { id = r.RankId, obsolete = r.Obselete } equals new { id = t.RankId, obsolete = true }
select new { Name = s.Name, CurrentValue = r.RankValue, CurrentDT = r.RankDt, PastValue = t.RankValue, PastDT = t.RankDt };
I am sure that I am not far away from the answer. The join seems to be the problem because I am getting everything in the result set.
Lastly, I downloaded LINQPad, but it is not giving me anything at all.
Thanks for all insights

Grouping on virtual (predefined) column in linq

I am trying to write a linq query for one of my dashboard which retrieves data based on some conditions. I want to display records count based on the different status available in my table.
Following is the SQL query in which I am trying to convert into Linq.
select count(id) cnt, 'Available' label from table where date = sysdate
Above query is returning below result in DB IDE. This is the result I want with linq
cnt label
0 Available
I've tried with following linq query but it is returning 0 count and hence result is not being retrieved.
var data = (from a in context
where a.date = System.DateTime.Now
group a in a.id into g
select new {
cnt = g.Count(),
label = 'Available'
}).ToList();
How do I achieve above mentioned result in linq. Your help will be appreciated.
Thanks
-------------EDIT----------------
Updated LINQ query
var data = (from a in context.TableA
where a.id = uniqueID
group a in a.id into g
select new {
cnt = g.Count(),
label = 'Available'
}).Concat(from a in context.TableB
where a.id = uniqueID
group a in a.id into g
select new {
cnt = g.Count(),
label = 'WIP'
}).ToList();
To count the number of elements matching a predicate in a linq query simply use the where clause:
var results =
from a in context
where a.date.Date == DateTime.Now.Date
&& a.id == someIdHere
select a;
var data = new {
count = results.Count(),
label = "Available"
};
Or, in extension method syntax (which I prefer):
var results = context.Where(a => a.date.Date == DateTime.Now.Date && a.id == someIdHere);
var data = new {
count = results.Count(),
label = "Available"
};
Also be careful when comparing a DateTime object with regards to what results you desire; comparing DateTime.Now to a date will likley return false since it will compare the time code as well, use the DateTime.Date property to obtain only the date from the object for the purposes of comparison.

Use multiple left joins to set DTO property inside select new linq query

I have the following code inside an MVC 6 (beta8) controller:
public IActionResult Get()
{
var districtsdetails = from districts in _ctx.District
select new
{
Id = districts.Id,
CountyFP = districts.County.FIPSCode,
DirectorName = districts.DirectorName,
Email = districts.Email,
EstStudentPop = districts.EstStudentPop,
Name = districts.Name,
Phone = districts.Phone,
Ranking = districts.Ranking,
RANumber = districts.RANumber,
SchoolCount = districts.SchoolCount,
Coop = districts.Coop.Name,
County = districts.County.Name,
Distributors = (from district in _ctx.District
join districtdistributor in _ctx.DistrictDistributor on district.Id equals districtdistributor.DistrictId
into group1
from g1 in group1.DefaultIfEmpty()
join distributor in _ctx.Distributor on g1.DistributorId equals distributor.Id
into group2
from g2 in group2.DefaultIfEmpty()
where district.Id == districts.Id
select new { g2.Id, g2.Name })
};
if (districtsdetails == null)
return HttpNotFound();
return new JsonResult(districtsdetails);
}
The problem is in the Distributors property setter.
I have District, DistrictDistributor, and Distributor entities in my context (and matching tables in my db). There is a many to many relationship between District and Distributor, with DistrictDistributor mapping the many to many relationship between the two. In my DistrictDetailsDTO I'm attempting to bridge the DistrictDistributor gap so I can just do DistrictDetailsDTO.Distributors ... All this is being serialized to Json as you can see by the JsonResult().
In the Distributor = (...) I am trying to effectively reproduce this SQL:
select (...)
from [District] D
left join [DistrictDistributor] DD on
DD.DistrictId = D.Id
left join [Distributor] Db on
Db.Id = DD.DistributorId
where id = 57
However, in my linq 57 would be districts.Id since I'm returning all Districts.
Please HELP I'm going CRAZY! No matter what I try along these lines produces a:
HTTP Error 502.3 - Bad Gateway
The specified CGI application encountered an error and the server terminated the process.
Here is how I think it could be resolved.
First, your query - the hard way. You don't need left joins here at all. They would be needed if you were producing a joined result set (SelectMany), but since that's not the case, you can use the following and let EF do it's magic to make it work:
var query =
from district in _ctx.District.AsNoTracking()
select new
{
Id = district.Id,
Name = district.Name,
// the rest of the district related fields
// ...
Distributors =
from dd in _cxt.DistrictDistributor
where dd.DistrictId == district.Id
join d in _ctx.Distributor on dd.DistributorId equals d.Id
select new { d.Id, d.Name }
};
Second - the easy way. One of the cool things of EF is to describe your model with navigation properties and properly configured relationships. This way you can almost forget about manual joins and let EF do whatever is necessary to satisfy your queries. In your case, the proper model would have District.Distributors and Distributor.Districts navigation properties, and the same result could be achieved with the following simple query:
var query =
from district in _ctx.District.AsNoTracking()
select new
{
Id = district.Id,
Name = district.Name,
// the rest of the district related fields
// ...
Distributors = district.Distributors.Select(d => new { d.Id, d.Name })
};

linq join code doesn't work

I have 2 records in tblMaterials and zero record in tblMaterialTenderGroups
But when I fetch the data to gridview it shows me the two records, and the join doesn't work
public List<tblMaterial> ShowPresentMaterialInGroup()
{
List<tblMaterial> q = (from i in dbconnect.tblMaterials.AsEnumerable()
join b in dbconnect.tblMaterialTenderGroups on i.materialId equals b.materialId
where b.MaterialGroupId == _materialGroupId
select new tblMaterial()
{
existAmout = i.existAmout,
materialId = i.materialId,
name = i.name,
needAmount = i.needAmount,
requestAmount = i.requestAmount,
unit = i.unit,
requestId = i.requestId
}).ToList();
return q;
}
Can you please try this
List<tblMaterial> q = from i in dbconnect.tblMaterials
join b in dbconnect.tblMaterialTenderGroups on i.materialId equals b.materialId
select new { existAmout = i.existAmout,
materialId = i.materialId,
name = i.name,
needAmount = i.needAmount,
requestAmount = i.requestAmount,
unit = i.unit,
requestId = i.requestId}.ToList();
May be using returning the two records..
I read something here
Using AsEnumerable will break off the query and do the "outside part"
as linq-to-objects rather than Linq-to-SQL. Effectively, you're
running a "select * from ..." for both your tables and then doing the
joins, where clause filter, ordering, and projection client-side.

Can I use a compiled query as a source in a second query?

I have a compiled query that works great. I pass it a product_id and it returns the product review information for that product.
Is it possible to use this compiled query as a source for a sub-query? Example:
from cat in ctx.cat_table
join prod in ctx.prod_table on cat.category_id equals prod.category_id
select new
{
cat_id = cat.category_id,
prod_id = prod.product_id,
name = prod.product_name,
descript = prod.product_description,
price = prod.price,
reviews = (from mcq in mycompiledquery(ctx, prod.product_id)
select new
{
rating = mcq.review_rating,
review = mcq.review_text
}
}
My early attempts at doing something like this raises an error:
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities
One alternative I've thought about is to replace my compiled query with a SQL view, but I'm concerned about a negative performance hit.
Many thanks for any suggestions you can offer.
You can use compiled query in other query but you can't make it dependent on the outer query. Examples
// You can do
var someParams = 10;
var dataQuery = from x in ctx.SomeData
join y in myCompiledQuery.Invoke(ctx, someParams)
on x.Id equals y.Id
where x.Name = "ABC"
select new { x, y };
// You can't do - this example will not compile but let's use it for description
var dataQuery = from x in ctx.SomeData
join y in myCompiledQuery.Invoke(ctx, x.SomeParams)
on x.Id equals y.Id
where x.Name = "ABC"
select new { x, y };
The difference is that first example just executes delegate (compiled query is a delegate) and returns IQueryable. The second example can't execute delegate because it is dependent on outer query data so it takes it as something that must be added to expression tree and eveluated during query execution. This fails because EF provider is not able to translate delegate invocation.
You can combine and embed queries, but I do not think you can use compiled queries. It really shouldn't matter much though, because EF will only compile the combined query once and then cache it (and the database backend should cache the associated query plan).
You could therefore use something along these lines:
var reviewQuery = from mcq in reviews
select new
{
prod_id = mcq.prod_id
rating = mcq.review_rating,
review = mcq.review_text
};
from cat in ctx.cat_table
join prod in ctx.prod_table on cat.category_id equals prod.category_id
select new
{
cat_id = cat.category_id,
prod_id = prod.product_id,
name = prod.product_name,
descript = prod.product_description,
price = prod.price,
reviews = from r in reviewQuery where r.prod_id == prod_id select r
}

Categories