Ordering issue with Groupby in Linq - c#

I am facing issues in using order by with group by in linq queries. when I apply group by after order by the ordering is being lost using the following code.
I want to sort all the conversations where type is in ascending. I doubt using Select(x=>x.FirstOrDefault()) is creating some issue.
I am using LINQ queries like this
DateTime? convStartDate = DateTime.Now.AddDays(-90);
DateTime? convEndDate = DateTime.Now;
var limit = 1000;
var offset = 0;
var query = (from conversation in db.textMessagesconversation
join msgParticipants in db.participants on conversation.Id equals msgParticipants.ConversationId
join msg in db.MsgMessages on conversation.Id equals msg.ConversationId
where msgParticipants.UserId == userID && ( (String.IsNullOrEmpty(convStartDate.ToString()) || msg.DateCreatedTime >= convStartDate)
&& (String.IsNullOrEmpty(convEndDate.ToString()) || msg.DateCreatedTime <= convEndDate)
select new RawConversation
{
LastMessageContent = msg.Content,
LastMessageDateTime = msg.DateCreatedTime,
IsAttachment = msg.IsAttachment,
SenderId = msg.SenderId,
MessageId = msg.Id,
Type = conversation.Type,
Name = conversation.Name,
Id = conversation.Id
});
query = query.OrderBy(x => x.Type);
var textmessagesList= query.GroupBy(x=>x.Id).Select(x=>x.FirstOrDefault()).Skip(offset).Take(limit).ToList();

Related

Linq between dates

So i have a query that is getting data correctly but as soon as I try to filter out the linq statement with a where between dates, I consistently get zero results.
var query= Enumerable.Empty<CustomClass>().AsQueryable();
query= (from auto in db.AutoInvs
join deal in db.Deals on new { inv = auto.INVUID, client = auto.CLIENTID, acct = auto.ACCOUNT} equals new {inv = deal.INVUID,client = deal.CLIENTID, acct = (int?) deal.ACCOUNT}
join dmCust in db.DMCusts on new {inv = auto.INVUID, client = auto.CLIENTID, acct = auto.ACCOUNT.ToString()} equals new {inv = dmCust.INVUID, client = dmCust.CLIENTID, acct = dmCust.ACCOUNT}
join act in db.Acts on new { inv = auto.INVUID, client = auto.CLIENTID, acct = auto.ACCOUNT.ToString()} equals new { inv = act.INVUID, client = act.CLIENTID, acct = act.Key }
where auto.DATAPROCESSEDDATE == null && auto.INVUID != ""
select new CustomClass()
{
AutoInv = auto,
Deal = deal,
DmCust = dmCust,
Act = act
});
var filteredData = query.Where(c => c.AutoInv.DATESOLD >= dateFrom.Value && c.AutoInv.DATESOLD <= dateTo.Value).AsQueryable();
Console.WriteLine(filteredData.ToList().Count);
Using this stripped down version (and my own data), it works for me:
var query = Enumerable.Empty<Tbl1>().AsQueryable();
DateTime? dateFrom = new DateTime(2017, 5, 10);
DateTime? dateTo = new DateTime(2017, 5, 20);
query = (from auto in db.Tbl1s
select auto);
var filteredData = query.Where(c => c.StartDate >= dateFrom.Value
&& c.StartDate <= dateTo.Value).AsQueryable();
filteredData.Dump();
One possible problem you may be having is that dateTo would be the exclusive end point --- Unless DATESOLD is exactly midnight, you won't get any that are on the end date.

Linq to SQL grouping with embedded lists causes too many queries

I am developing a query to grab and join some SQL tables in C# and am having some trouble with grouping and enumerables within the dataset. My query is below. This gives me the data in the format I'm looking for, but it takes way too long when I try to add the enumerated list as indicated below. When I look under the hood I can see it is executing way too many SQL queries. I'd like to get it to just one. Using LinqPad:
void Main()
{
var nightlyRuns = (from a in LoadTestSummaries
join b in LoadTestTestSummaryData
on a.LoadTestRunId equals b.LoadTestRunId
where a.TargetStack == "LoadEnv" &&
a.TestGuid != null &&
a.StartTime != null &&
a.LoadTestRunId != null
orderby a.StartTime
group new {a, b} by new
{
a.TestGuid,
a.Name,
a.Description,
a.StartTime,
a.Duration,
a.NumAgents,
a.NumHosts,
a.PassFail,
a.ResultsFilePath,
a.Splunk
}
into g
let scenarioStart = g.Min(s => s.a.StartTime) ?? g.Min(s => s.a.DateCreated)
let testCases = g.Select(s => s.b)
orderby scenarioStart
select new
{
TestGuid = g.Key.TestGuid,
ScenarioRun = new
{
Name = g.Key.Name,
Description = g.Key.Description,
StartTime = scenarioStart,
Duration = g.Key.Duration,
NumAgents = g.Key.NumAgents,
NumHosts = g.Key.NumHosts,
Result = g.Key.PassFail,
ResultsFilePath = g.Key.ResultsFilePath,
SplunkLink = g.Key.Splunk,
// PROBLEM: Causes too many queries:
TestRuns = from t in testCases select t.TestCaseId
}
}).ToLookup(g => g.TestGuid, g => g.ScenarioRun);
nightlyRuns["ba593f66-695f-4fd1-99c3-71253a2e4981"].Dump();
}
The "TestRuns" line is causing the excessive queries. Any idea what I am doing wrong here?
Thanks for any insight.
Tough answer to test but I think we can avoid the grouping and multiple queries with something like this: (https://msdn.microsoft.com/en-us/library/bb311040.aspx)
var nightlyRuns = (from a in LoadTestSummaries
join b in LoadTestTestSummaryData
on a.LoadTestRunId equals b.LoadTestRunId
where a.TargetStack == "LoadEnv" &&
a.TestGuid != null &&
a.StartTime != null &&
a.LoadTestRunId != null
into testGroup
select new
{
TestGuid = a.TestGuid,
ScenarioRun = new
{
Name = a.TestGuid,
Description = a.Description,
StartTime = a.StartTime ?? a.DateCreated,
Duration = a.Duration,
NumAgents = g.Key.NumAgents,
NumHosts = a.NumHosts,
Result = a.PassFail,
ResultsFilePath = a.ResultsFilePath,
SplunkLink = a.Splunk,
// PROBLEM: Causes too many queries:
TestRuns =testGroup
}
}).OrderBy(x=>x.StartTime).ToLookup(x => x.TestGuid, x => x.ScenarioRun);
nightlyRuns["ba593f66-695f-4fd1-99c3-71253a2e4981"].Dump();

How to debug query in c# program?

I want to write query more efficient.
I do not want before the end of the query, the list of data to extract.
var UserTimeLineNews = (from l in _newsService.NewsQuery()
where l.UserId == UserId && l.IsActive == true
orderby l.CreateDate descending
select new UserTimeLine
{
EventDate = l.CreateDate,
CreateDate = l.CreateDate,
NewsId = l.NewsId,
TimeLineType = TimeLineType.CreateNews,
Title = l.Title,
Abstract = l.NewsAbstract,
CommentCount = l.CommentCount,
LikeCount = l.LikeCount,
ViewsCount = l.ViewsCount,
Storyteller = l.Storyteller
}).AsQueryable();//Take(NumberOfNews).ToList();
var UserTimeLineLikeNews = (from l in _likeNewsService.LikeNewsQueryable()
where l.UserId == UserId
orderby l.CreateDate descending
select new UserTimeLine
{
EventDate = l.CreateDate,
CreateDate = l.CreateDate,
NewsId = l.NewsId,
TimeLineType = TimeLineType.LikeNews,
Title = l.News.Title,
Abstract = l.News.NewsAbstract,
CommentCount = l.News.CommentCount,
LikeCount = l.News.LikeCount,
ViewsCount = l.News.ViewsCount,
Storyteller = l.News.Storyteller
}).AsQueryable();//Take(NumberOfNews).ToList();
var UserTimeLineComments = (from l in _commentService.CommentQueryable()
where l.UserId == UserId && l.IsActive == true
orderby l.CreateDate descending
select new UserTimeLine
{
EventDate = l.CreateDate,
CreateDate = l.CreateDate,
NewsId = l.NewsId,
TimeLineType = TimeLineType.Comment,
Title = l.News.Title,
Abstract = l.News.NewsAbstract,
CommentContent = l.Content,
CommentCount = l.News.CommentCount,
LikeCount = l.News.LikeCount,
ViewsCount = l.News.ViewsCount,
Storyteller = l.News.Storyteller
}).AsQueryable();//Take(NumberOfNews).ToList();
var item = (UserTimeLineNews
.Union(UserTimeLineLikeNews)
.Union(UserTimeLineComments))
.OrderByDescending(e => e.EventDate)
.Distinct()
.Take(NumberOfNews)
.ToList();
After running the following error appears
Error:
The type 'UserTimeLine' appears in two structurally incompatible initializations within a single LINQ to Entities query.
A type can be initialized in two places in the same query, but only if the same properties are set in both places and those properties are set in the same order.
The first two queries don't initialize the CommentContent property. Add that to the initializer in the first two queries (or remove it in the last query) and the final query should work.

How to write this LINQ Query

Hi i have a datatable with following fields
DAT_START
GROUPBY
TXT_LATITTUDE
TXT_LONGITUDE
INT_DIRECTION
INT_CALL_DATA_TYPE
LNG_DURATION
And following is the LINQ query i am using
var data = (from r in dt.AsEnumerable()
where ((r.Field<DateTime>("DAT_START").TimeOfDay.Hours < 20) && (r.Field<DateTime>("DAT_START").TimeOfDay.Hours >= 4))
group r by new { CID = r["GroupBy"], CLatitude = r["TXT_LATITUDE"], CLongitude = r["TXT_LONGITUDE"],CDirection = r["INT_DIRECTION"],
CCallType = r["INT_CALL_DATA_TYPE"],CDuration = r["LNG_DURATION"] }
into groupedTable
select new
{
CellID = groupedTable.Key.CID,
CallCount = groupedTable.Count(),
Longitude = groupedTable.Key.CLongitude,
Latitude = groupedTable.Key.CLatitude,
Direction = groupedTable.Key.CDirection,
CallType = groupedTable.Key.CCallType,
Duration = groupedTable.Key.CDuration
}).OrderByDescending(s => s.CallCount);
It gives me result like this
CellID = 4057,CallCount = 84,Longitude = "",Latitude = "",Direction = "Incoming",CallType = "Voice",Duration = 50
CellID = 4057,CallCount = 8,Longitude = "",Latitude = "",Direction = "Outgoing",CallType = "Voice",Duration =97
CellID = 4057,CallCount = 56,Longitude = "",Latitude = "",Direction = "Incoming",CallType ="SMS" ,Duration = 0
CellID = 4057,CallCount = 41,Longitude = "",Latitude = "",Direction = "Outgoing",CallType = "SMS",Duration = 0
Now i want result like this
CellID = 4057, TotalCommCount = 204, TotalDuration = 147, INSMSCount = 56,OutSMSCount = 41, INVoiceCount = 84,OutVoiceCount = 8,InVoiceDuration =50,OutVoiceDuration = 47
How can i do this. I am struck over here..
It looks like you're grouping by far too much at the moment, which is why you're getting multiple rows. I suspect you want something like this:
from r in dt.AsEnumerable()
where r.Field<DateTime>("DAT_START").TimeOfDay.Hours < 20 &&
r.Field<DateTime>("DAT_START").TimeOfDay.Hours >= 4
group r r["GroupBy"] into g
select new
{
CellID = g.Key,
TotalCommCount = g.Count(),
TotalDuration = g.Sum(r => r.Field<long>("LNG_DURATION")),
InSMSCount = g.Count(r => r.Field<string>("DIRECTION") == "Incoming" &&
r.Field<string>("CALL_TYPE") == "SMS"),
OutSMSCount = g.Count(r => r.Field<string>("DIRECTION") == "Outgoing" &&
r.Field<string>("CALL_TYPE") == "SMS"),
InVoiceCount = g.Count(r => r.Field<string>("DIRECTION") == "Incoming" &&
r.Field<string>("CALL_TYPE") == "Voice"),
OutVoiceCount = g.Count(r => r.Field<string>("DIRECTION") == "Outgoing" &&
r.Field<string>("CALL_TYPE") == "Voice"),
InVoiceDuration = g.Where(r => r.Field<string>("DIRECTION") == "Incoming" &&
r.Field<string>("CALL_TYPE") == "Voice")
.Sum(r => r.Field<long>("DURATION"))
OutVoiceDuration = g.Where(r => r.Field<string>("DIRECTION") == "Outgoing" &&
r.Field<string>("CALL_TYPE") == "Voice"),
.Sum(r => r.Field<long>("DURATION"))
} into summary
order by summary.TotalCommCount descending
select summary;
I suggest you create a view in your SQL database where you can simply aggregate what you need and then you use that view in your Linq query - this will perform fast and it is easy to write.
Sketch of design:
Since the description of your requirements is not totally clear, I have made assumptions.
Create a SQL view such as (it's just to show the idea, change it according to your needs):
CREATE VIEW [dbo].[vSumDurations]
AS
select c.CellId, j1.SumDuration1 as TotalDuration,
j2.SumDuration2 as GroupedDuration, j1.CallCount
from (select distinct t.CID as CellId from [dbo].[YourTable] t) c
left join (select t1.CID as CellId, sum(LNG_Duration) as SumDuration1,
count(*) as CallCount from [dbo].[YourTable] t1
Group By t1.CID) j1
on c.CellId=j1.CellId
left join (select t2.CID as CellId, sum(LNG_Duration) as SumDuration2
from [dbo].[YourTable] t2
Group by t2.CID, t2.Direction, t2.CallType) j2
on c.CellId=j2.CellId
(You know you can easily add this view to your *.EDMX by using "update model from database" in the context menu of the entity diagram page and then tick-mark the view vSumDurations in the "tables/views" section of the dialog which pops up.)
After this preparation your Linq query is very simple because everything is already done in the view. Hence, the code looks like:
var dc = this; // in LinqPad you can set your data context
var data = (from d in dc.vSumDurations select d).OrderByDescending(s => s.CallCount);
data.Dump();
Note: The example is made for LinqPad - you will need a different data context in your real code. Linqpad does not need dc, but it is easier if you declare it for convenience reasons because in your real code you have to provide it.

Linq to select data from one table not in other table

Hi i have the following code to select data from one table not in other table
var result1 = (from e in db.Users
select e).ToList();
var result2 = (from e in db.Fi
select e).ToList();
List<string> listString = (from e in result1
where !(from m in result2
select m.UserID).Contains(e.UserID)
select e.UserName).ToList();
ViewBag.ddlUserId = listString;
Am getting value inside listString .But got error while adding listString to viewbag.
Unable to cast object of type 'System.Collections.Generic.List`1[System.String]' to type 'System.Collections.Generic.IEnumerable`1[Main.Models.Admin.User]'.
First, could you update your question with the entire method so that we can see what might be going on with the ViewBag? Because your code should work just fine, assigning whatever value to the ViewBag is no problem normally:
ViewBag.property1 = 0;
ViewBag.property1 = "zero";
works just fine. ViewBag is dynamic. Now, you could get that error if you would later try to assing ViewBag.ddlUserId to something that actually is the wrong type.
I would like you to rewrite your statement as well, let me explain why. Assume for a moment that you have a lot ( > 100.000) of User records in your db.Users and we assume the same for Fi as well. In your code, result1 and result2 are now two lists, one containing >100.000 User objects and the other >100.000 Fi objects. Then these two lists are compared to each other to produce a list of strings. Now imagine the resource required for your web server to process this. Under the assumption that your actually using/accessing a separate SQL server to retrieve your data from, it would be a lot better and faster to let that server do the work, i.e. producing the list of UserID's.
For that you'd either use Kirill Bestemyanov's answer or the following:
var list = (from user in db.Users
where !db.Fi.Any(f => f.UserID == user.UserID)
select user.UserName).ToList()
This will produce just one query for the SQL server to execute:
SELECT
[Extent1].[UserName] AS [UserName]
FROM [dbo].[Users] AS [Extent1]
WHERE NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Fi] AS [Extent2]
WHERE [Extent2].[UserID] = [Extent1].[UserID]
)}
which in the end is what you want...
Just to clarify more:
var list = (from user in db.Users
where !db.Fi.Any(f => f.UserID == user.UserID)
select user.UserName).ToList()
can be written as the following lambda expression as well:
var list = db.Users.Where(user => !db.Fi.Any(f => f.UserID == user.UserID))
.Select(user => user.UserName).ToList()
which from the looks of it is slightly different from Kirill Bestemyanov's answer (which I slightly modified, just to make it look more similar):
var list = db.Users.Where(user => !db.Fi.Select(f => f.UserID)
.Contains(user.UserID))
.Select(user => user.UserName).ToList();
But, they will in fact produce the same SQL Statement, thus the same list.
I will rewrite it to linq extension methods:
List<string> listString = db.Users.Where(e=>!db.Fi.Select(m=>m.UserID)
.Contains(e.UserID))
.Select(e=>e.UserName).ToList();
try it, it should work.
Try this it is very simple.
var result=(from e in db.Users
select e.UserID).Except(from m in db.Fi
select m.UserID).ToList();
var res = db.tbl_Ware.where(a => a.tbl_Buy.Where(c => c.tbl_Ware.Title.Contains(mtrTxtWareTitle.Text)).Select(b => b.Ware_ID).Contains(a.ID));
This mean in T-SQL is:
SELECT * FROM tbl_Ware WHERE id IN (SELECT ware_ID, tbl_Buy WHErE tbl_Ware.title LIKE '% mtrTxtwareTitle.Text %')
getdata = (from obj in db.TblManageBranches
join objcountr in db.TblManageCountries on obj.Country equals objcountr.iCountryId.ToString() into objcount
from objcountry in objcount.DefaultIfEmpty()
where obj.IsActive == true
select new BranchDetails
{
iBranchId = obj.iBranchId,
vBranchName = obj.vBranchName,
Addressline1 = obj.Addressline1,
Adminemailid = obj.Adminemailid,
BranchType = obj.BranchType,
Country = objcountry.vCountryName,
CreatedBy = obj.CreatedBy,
CreatedDate = obj.CreatedDate,
iArea = obj.iArea,
iCity = obj.iCity,
Infoemailid = obj.Infoemailid,
Landlineno = obj.Landlineno,
Mobileno = obj.Mobileno,
iState = obj.iState,
Pincode = obj.Pincode,
Processemailid = obj.Processemailid,
objbranchbankdetails = (from objb in db.TblBranchesBankDetails.Where(x => x.IsActive == true && x.iBranchId == obj.iBranchId)
select new ManageBranchBankDetails
{
iBranchId = objb.iBranchId,
iAccountName = objb.iAccountName,
iAccountNo = objb.iAccountNo,
iBankName = objb.iBankName,
iAccountType = objb.iAccountType,
IFSCCode = objb.IFSCCode,
SWIFTCode = objb.SWIFTCode,
CreatedDate = objb.CreatedDate,
Id = objb.Id
}).FirstOrDefault(),
objbranchcontactperson = (from objc in db.tblbranchcontactpersons.Where(x => x.Isactive == true && x.branchid == obj.iBranchId)
select new ManageBranchContactPerson
{
branchid = objc.branchid,
createdate = objc.createdate,
Id = objc.Id,
iemailid = objc.iemailid,
ifirstname = objc.ifirstname,
ilandlineno = objc.ilandlineno,
ilastname = objc.ilastname,
imobileno = objc.imobileno,
title = objc.title,
updateddate=objc.updateddate,
}).ToList(),
}).OrderByDescending(x => x.iBranchId).ToList();
getdata = (from obj in db.TblManageBranches join objcountr in db.TblManageCountries on obj.Country equals objcountr.iCountryId.ToString() into objcount from objcountry in objcount.DefaultIfEmpty() where obj.IsActive == true
select new BranchDetails
{
iBranchId = obj.iBranchId,
vBranchName = obj.vBranchName,
objbranchbankdetails = (from objb in db.TblBranchesBankDetails.Where(x => x.IsActive == true && x.iBranchId == obj.iBranchId)
select new ManageBranchBankDetails
{
iBranchId = objb.iBranchId,
iAccountName = objb.iAccountName,
}).FirstOrDefault(),
objbranchcontactperson = (from objc in db.tblbranchcontactpersons.Where(x => x.Isactive == true && x.branchid == obj.iBranchId)
select new ManageBranchContactPerson
{
branchid = objc.branchid,
createdate = objc.createdate,
Id = objc.Id,
iemailid = objc.iemailid,
}).ToList(),
}).OrderByDescending(x => x.iBranchId).ToList();

Categories