DB:
I'm trying to bring back data only when All of the ReviewItems meet the condition of ReviewItemStatus==3. This works.
Problem: But then I want to narrow the scope of All to all ReviewItems where ReviewerID==1000
// I want ALL groupAccountLinks only for ReviewerID==1000 and AccountID
// 0) (and thus ReviewItems) for Account Charlie have ReviewItemStatusID==3
var xx = Accounts.Where(acc => acc.GroupAccountLinks.All(gal =>
// do ANY of the (1) associated reviewItems contain ri.ReviewItemStatusID == 3
gal.ReviewItems.Any(ri => ri.ReviewItemStatusID == 3)
// This doesn't work
//&& ri.Review.ReviewerID == 1000
)
&& acc.AccountID == 1002 // Charlie
);
Will be going against EF4.1 Currently testing using Linqpad and LinqToSQL test db.
You have && Condition .So, I think your table not have all AccountId=1002 and All ReviewItemStatusID =3 . So Change && condition to || condition.
The first thing I would do would be to take the && acc.AccountID == 1002 off and make sure that you're getting the entire unfiltered set of Accounts that have a ReviewItem in status 3. If that looks good try doing your filter this way:
var xx = Accounts
.Where(acc => acc.GroupAccountLinks
.All(gal => gal.ReviewItems
.Any(ri => ri.ReviewItemStatusID == 3))
.FirstOrDefault(acc => acc.AccountID == 1002);
Thanks to Jesse, Slauma and RemeshRams which lead me to this:
var xxx = Accounts.Where(
// do All Accounts satisfy condition
u => u.Accounts.All(
// do All GroupAccountLinks (and thus ReviewItems) for Account meet the condition of ReviewItemStatusID==3
acc => acc.GroupAccountLinks.All(
// for ReviewItems where ReviewerID==1000, do they All have ReviewItemStatusID==3
gal => gal.ReviewItems.Where(
ri => ri.Review.ReviewerID == 1000)
.All(
ri => ri.ReviewItemStatusID == 3
)
// Make sure there are some ReviewItems
&& gal.ReviewItems.Any()
)
)
);
Related
All:
Lets say I have the following table:
RevisionID, Project_ID, Count, Changed_Date
1 2 4 01/01/2016: 01:02:01
2 2 7 01/01/2016: 01:03:01
3 2 8 01/01/2016: 01:04:01
4 2 3 01/01/2016: 01:05:01
5 2 15 01/01/2016: 01:06:01
I am ordering the records based on Updated_Date. A user comes into my site and edits record (RevisionID = 3). For various reasons, using LINQ (with entity framework), I need to get the previous record in the table, which would be RevisionID = 2 so I can perform calculations on "Count". If user went to edit record (RevisionID = 4), I would need to select RevisionID = 3.
I currently have the following:
var x = _db.RevisionHistory
.Where(t => t.Project_ID == input.Project_ID)
.OrderBy(t => t.Changed_Date);
This works in finding the records based on the Project_ID, but how then do I select the record before?
I am trying to do the following, but in one LINQ statement, if possible.
var itemList = from t in _db.RevisionHistory
where t.Project_ID == input.Project_ID
orderby t.Changed_Date
select t;
int h = 0;
foreach (var entry in itemList)
{
if (entry.Revision_ID == input.Revision_ID)
{
break;
}
h = entry.Revision_ID;
}
var previousEntry = _db.RevisionHistory.Find(h);
Here is the correct single query equivalent of your code:
var previousEntry = (
from r1 in db.RevisionHistory
where r1.Project_ID == input.Project_ID && r1.Revision_ID == input.Revision_ID
from r2 in db.RevisionHistory
where r2.Project_ID == r1.Project_ID && r2.Changed_Date < r1.Changed_Date
orderby r2.Changed_Date descending
select r2
).FirstOrDefault();
which generates the following SQL query:
SELECT TOP (1)
[Project1].[Revision_ID] AS [Revision_ID],
[Project1].[Project_ID] AS [Project_ID],
[Project1].[Count] AS [Count],
[Project1].[Changed_Date] AS [Changed_Date]
FROM ( SELECT
[Extent2].[Revision_ID] AS [Revision_ID],
[Extent2].[Project_ID] AS [Project_ID],
[Extent2].[Count] AS [Count],
[Extent2].[Changed_Date] AS [Changed_Date]
FROM [dbo].[RevisionHistories] AS [Extent1]
INNER JOIN [dbo].[RevisionHistories] AS [Extent2] ON [Extent2].[Project_ID] = [Extent1].[Project_ID]
WHERE ([Extent1].[Project_ID] = #p__linq__0) AND ([Extent1].[Revision_ID] = #p__linq__1) AND ([Extent2].[Changed_Date] < [Extent1].[Changed_Date])
) AS [Project1]
ORDER BY [Project1].[Changed_Date] DESC
hope I understood what you want.
Try:
var x = _db.RevisionHistory
.FirstOrDefault(t => t.Project_ID == input.Project_ID && t.Revision_ID == input.Revision_ID -1)
Or, based on what you wrote, but edited:
_db.RevisionHistory
.Where(t => t.Project_ID == input.Project_ID)
.OrderBy(t => t.Changed_Date)
.TakeWhile(t => t.Revision_ID != input.Revision_ID)
.Last()
We are using EF6.1 and dotConnect for Oracle.
Trying to debug why our development performs poorly in one of customers server, I turned on the DatabaseLogger Interceptor feature to get the queries executed in DB and try to improve them. One thing I've found is that in some queries there is some delay of seconds between the query has been executed and the connection has been closed. For example:
Connection opened at 17/06/2014 9:47:42 +02:00
SELECT
"top". (...)
FROM ( SELECT
"Project1". (...)
FROM ( SELECT
"Extent1". (...)
"Extent2". (...)
FROM (...)
WHERE (...)
) "Project1"
ORDER BY (...)
) "top"
WHERE ROWNUM <= 1
-- p__linq__0: '589' (Type = Int32, IsNullable = false)
-- Executing in 17/06/2014 9:47:43 +02:00
-- Completed in 288 ms with result: aj
Connection closed at 17/06/2014 9:47:51 +02:00
As you can see, there's a delay of many seconds. This query is runned many times, but the delay does not appear in every instance, others just have 2 or 3 seconds of delay, and others just none.
I don't really know where to begin to investigate. Is it something related to EF or to dotConnect Oracle? What job is done after the query has been executed and the connection closed?
EDIT: This is the code I'm using to retrieve the info from DB:
var users = db.USUARIO
.Where(x => x.COORDENADA.Any(c => c.LATITUD != 0 && c.LONGITUD != 0))
.OrderBy(x => x.NOMBRE).AsQueryable();
(...)
var list = users.ToList()
.Select(x => new
{
Usuario = x,
LastCoord = db.COORDENADA
.Include(c => c.TIPO)
.Where(c => c.USUARIOID == x.USUARIOID && c.LATITUD != 0 && c.LONGITUD != 0)
.OrderByDescending(c => c.FECHAHORAPDA)
.ThenBy(c => c.TIPO.RUTA).FirstOrDefault()
})
.Select(x => new ListItem
{
ID = x.LastCoord.COORDENADAID,
Marcadores = new List<COORDENADA>(new[] { x.LastCoord }),
Principal = x.Usuario.NOMBRE.ToTitleCase(),
Inferior1 = x.LastCoord.FECHAHORAPDA.ToString("dd/MM HH:mm"),
Color = x.LastCoord.TIPO.COLOR
});
The db.COORDENADA... is the query I exposed before.
I have 2 tables:
'AllowedDates'
- DayID int PK
- Day datetime
'AllowedTimes'
- TimeID int PK
- DayID int FK
- Hour int
- Minute int
also I have table 'Users':
- ID int PK
- FirstName nvarchar(max)
...
and table 'UserDeniedTimes':
DayID int FK
UserID int FK
Hour int
Minute int
I need to select users, which don't have deny time (record in UserDeniedTimes) for concrete DayID/Hour/Minute
I try to do the following:
var result = from i in _dbContext.Users
where i.UserDeniedTimes.All(
p => (!p.AllowedDate.AllowedTimes.Any(
a1 => a1.DayID == aTime.DayID
&& a1.Hour == aTime.Hour
&& a1.Minute == aTime.Minute
))
)
select new ...
it works correctly, but with one exception. If user has record in UserDeniedTimes for some day, but another time, this user is not selected too. For example, UserDeniedTimes has record:
DayID = 10
UserID = 20
Hour = 14
Minute = 30
this user will be not selected if aTime has the following values:
DayID = 10
Hour = 9
Minute = 30
but will be selected if DayID = 11. Why?
[ADDED]
it works correctly when I limit only by day:
var result = from i in _dbContext.Users
where i.UserDeniedTimes.All(
p => (!p.AllowedDate.AllowedTimes.Any(
a1 => a1.DayID == aTime.DayID
))
)
select new ...
but not works when I write:
var result = from i in _dbContext.Users
where i.UserDeniedTimes.All(
p => (!p.AllowedDate.AllowedTimes.Any(
a1 => a1.Hour == 14
))
)
select new ...
why? What is difference between magic DayID and Hour ?
[ADDED #2]
((time == null) || i.UserDeniedTimes.All(p =>
//p.AllowedDate.AllowedTimes.Any(a1 => a1.DayID != 33) &&
(p.AllowedDate.AllowedTimes.Any(a2 => a2.Hour != 14)
))) &&
does not work
((time == null) || i.UserDeniedTimes.All(p =>
p.AllowedDate.AllowedTimes.Any(a1 => a1.DayID != 33) &&
//(p.AllowedDate.AllowedTimes.Any(a2 => a2.Hour != 14)
))) &&
works
why?
Sometimes it helps to rephrase the problem: if I read you well, you don't want users, that have a deny time with at least one specified DayID/Hour/Minute:
where !i.UserDeniedTimes.Any(
p => (p.AllowedDate.AllowedTimes.Any(
a1 => a1.DayID == aTime.DayID
&& a1.Hour == aTime.Hour
&& a1.Minute == aTime.Minute
))
)
This should select the users you want. If not, please tell in some more words what exactly you
are trying to achieve.
in the following code i've commented on the line that SLOWS my page right down. I did some speed test to reveal the CONTAINS LINQ expression is the problem.
Does anyone know how to change this one line to be more efficient using something else instead. I'm also curious as to why its so slow.
Any ideas (thanks in advance):
var allWaste = _securityRepository.FindAllWaste(userId, SystemType.W);
var allWasteIndicatorItems = _securityRepository.FindAllWasteIndicatorItems();
// First get all WASTE RECORDS
var searchResults = (from s in allWaste
join x in allWasteIndicatorItems on s.WasteId equals x.WasteId
where (s.Description.Contains(searchText)
&& s.Site.SiteDescription.EndsWith(searchTextSite)
&& (s.CollectedDate >= startDate && s.CollectedDate <= endDate))
&& x.EWC.EndsWith(searchTextEWC)
select s).Distinct();
var results = searchResults.AsEnumerable();
if (hazardous != "-1")
{
// User has requested to filter on Hazardous or Non Hazardous only rather than Show All
var HazardousBoolFiltered = (from we in _db.WasteIndicatorItems
.Join(_db.WasteIndicators, wii => wii.WasteIndicatorId, wi => wi.WasteIndicatorId, (wii, wi) => new { wasteid = wii.WasteId, wasteindicatorid = wii.WasteIndicatorId, hazardtypeid = wi.HazardTypeId })
.Join(_db.HazardTypes, w => w.hazardtypeid, h => h.HazardTypeId, (w, h) => new { wasteid = w.wasteid, hazardous = h.Hazardous })
.GroupBy(g => new { g.wasteid, g.hazardous })
.Where(g => g.Key.hazardous == true && g.Count() >= 1)
select we).AsEnumerable(); // THIS IS FAST
// Now join the 2 object to eliminate all the keys that do not apply
if (bHazardous)
results = (from r in results join x in HazardousBoolFiltered on r.WasteId equals x.Key.wasteid select r).AsEnumerable(); //This is FAST
else
results = (from r in results.Where(x => !HazardousBoolFiltered
.Select(y => y.Key.wasteid).Contains(x.WasteId)) select r).AsEnumerable(); // This is DOG SLOW 10-15 seconds !--- THIS IS SLOWING EXECUTION by 10 times --!
}
return results.AsQueryable();
I suggest using a logging / tracing framework like smart inspect or log4net combined with a debug text writer.
http://www.codesprouts.com/post/View-LINQ-To-SQL-Statements-Using-A-Debug-TextWriter.aspx
another possibility is to use the sql server profiler and see what sql linq2sql produces.
also a very nice way is to use the mvc mini profiler in combination with the Profiled DB Connection and the SqlFormatters.SqlServerFormatter.
Try Any (MSDN)
Try this:
results = (from r in results
.Where(x => !HazardousBoolFiltered
.Any(y => y.Key.wasteid == r.WasteId)))
.AsEnumerable()
Or Count:
results = (from r in results
.Where(x => HazardousBoolFiltered
.Count(y => y.Key.wasteid == r.WasteId) == 0))
.AsEnumerable()
In my code below, is there any way I can use the results in the object 'WasteRecordsExcluded' to join with searchResults, essentially excluding the WasteId's I don't want.
If I debug to the last line I get the error :
base {System.SystemException} = {"The query contains references to items defined on a different data context."}
Or if joining is impossible then i could change bHazardous from TRUE to FALSE and FALSE to TRUE and do some kind of 'NOT IN' comparison.
Going bananas with this one, anyone help? Kind Regards :
var allWaste = _securityRepository.FindAllWaste(userId, SystemType.W);
var allWasteIndicatorItems = _securityRepository.FindAllWasteIndicatorItems();
// First get all WASTE RECORDS
var searchResults = (from s in allWaste
join x in allWasteIndicatorItems on s.WasteId equals x.WasteId
where (s.Description.Contains(searchText)
&& s.Site.SiteDescription.EndsWith(searchTextSite)
&& (s.CollectedDate >= startDate && s.CollectedDate <= endDate))
&& x.EWC.EndsWith(searchTextEWC)
select s).Distinct();
var results = searchResults;
if (hazardous != "-1")
{
// User has requested to filter on Hazardous or Non Hazardous only rather than Show All
var WasteRecordsExcluded = (from we in _db.WasteIndicatorItems
.Join(_db.WasteIndicators, wii => wii.WasteIndicatorId, wi => wi.WasteIndicatorId, (wii, wi) => new { wasteid = wii.WasteId, wasteindicatorid = wii.WasteIndicatorId, hazardtypeid = wi.HazardTypeId })
.Join(_db.HazardTypes, w => w.hazardtypeid, h => h.HazardTypeId, (w, h) => new { wasteid = w.wasteid, hazardous = h.Hazardous })
.GroupBy(g => new { g.wasteid, g.hazardous })
.Where(g => g.Key.hazardous == bHazardous && g.Count() >= 1)
select we);
// Now join the 2 object to eliminate all the keys that do not apply
results = results.Where(n => WasteRecordsExcluded.All(t2 => n.WasteId == t2.Key.wasteid));
}
return results;
Maybe something like this:
.....
var results = searchResults.ToList();
.....
.....
.Where(g => g.Key.hazardous == bHazardous && g.Count() >= 1)
select we).ToList();
.....