everyone! I'm trying to do a rather simple LINQ query to find available rooms in a hotel. (That is, find a available room from a pool of rooms, and check that there are no pending cleaning etc in the room).
But when I try to execute the third query, I get the exception you see in the title. I don't actually get the exception when I execute it, but when I try to use the "unfinishedTasksInPool" variable.
I tried turning the "unfinishedTasksInPool" into a list, too see if that would help, but whenever I try to use "unfinishedTasksInPool", I get the exception.
EDIT : Whenever I exclude "availableRoomsFromPool.Contains(tasks.roomId" in the where clause in the third query, everything seems to work normally. But that doesn't exactly solve the problem tho.
var pendingReservation = database.Reservations.Where(res => res.reservationID == resId).First();
var reservationsInSameGroup = from otherReservations in database.GetTable<Reservation>()
where (otherReservations.beds == pendingReservation.beds
&& otherReservations.rank == pendingReservation.rank
&& otherReservations.roomID != null)
select otherReservations.roomID;
var availableRoomsFromPool = from rooms in database.GetTable<Room>()
where (!reservationsInSameGroup.Contains(rooms.roomId)
&& rooms.beds == pendingReservation.beds
&& rooms.roomRank == pendingReservation.rank)
select rooms.roomId;
var unfinishedTasksInPool = from tasks in database.GetTable<HotelTask>()
where (availableRoomsFromPool.Contains(tasks.roomId)
&& tasks.taskStatus < 2)
select tasks.roomId;
It's a LINQ-to-SQL restriction. You can use local sequences in queries (as long as you use them in Contains), but you can't use a local sequence that itself is the result of a query using another local sequence.
So it's alright to do...
var availableRoomsFromPool = (from ....).ToArray();
...because the query contains one local sequence (reservationsInSameGroup).
But...
var unfinishedTasksInPool = (from ...).ToArray();
...throws the exception.
The solution is to use the result of var availableRoomsFromPool = (from ....).ToArray(); in the third query, because that reduces availableRoomsFromPool to one local sequence.
Related
I've written some complex LINQ query which I'm trying to run against NHibernate, unfortunately this causes an exception when trying to evaluate the query (call .ToList()).
Here is the code, which is supposed to retrieve Issue objects with some extra data:
var list = from i in sess.Query<Issue>()
let readFlag = (from f in i.ReadFlags
where (f.User != null && f.User.Username == request.UserName)
||
(f.Device.Name == request.MachineName)
select f).FirstOrDefault()
let isUnread = readFlag == null
let unreadCommentsCount = isUnread ? 0 : (from c in i.Comments
where c.DateCreated > readFlag.LastSeenCommentDate
select c).Count()
let statusChanged = isUnread && i.Status != readFlag.LastSeenStatus
where isUnread || unreadCommentsCount > 0 || statusChanged
select new
{
Issue = i,
ReadFlag = readFlag,
IsUnread = isUnread,
UnreadCommentsCount = unreadCommentsCount
};
i.e. - for each Issue object look for related IssueReadFlag which matches current username or machine name. if the Flag exists, it also contains the "last seen comment date", so the code calculates the number of new comments for this Issue.
Unfortunately NHibernate is not able to handle this query (Exception details).
I'm looking for the most optimal solution for this problem.
Obtaining all the Issue objects and applying the query criteria on the client-side is unacceptable for me.
trying to find out what causes the issue: It started working as I've commented out evaluation of unreadCommentsCount and statusChanged both in "select" and "where" statements. Following this lead, It seems that referencing readFlag in any of these subqueries causes the issue (after removing reference to readFlag in "let unreadCommentsCount .." and "let statusChanged.." conditions, the query doesn't throw exceptions).
Now I need a tip on how to make it functional (working as expected) again ...
Further investigating the issue I've found out that NHibernate can't handle the uncertain state of readFlag existence.
I've ended up splitting the query into two parts, first of them takes all the Issues where readFlag does not exists, the second one queries the IssueReadFlag directly, calculating the Unread Comments Count and Changed Status.
This seems to be the only solution as for now.
I get the following error when trying to run a specific query against RavenDB:
Can't extract value from expression of type: ArrayIndex
Here is the query that is generating the error:
people = from p in RavenSession.Query<DBObjects.Person, People_ByNameAndTrashedSortByFirstNameAndLastName>()
orderby p.FirstName, p.LastName
select p;
...
//building LINQ query
...
people = from p in people
where ((p.FirstName.StartsWith(SearchWords[0])) && (p.LastName.StartsWith(SearchWords[1])))
select p;
...
//later
foreach(DBObject.Person person in people) //triggers error listed above
{
}
I'm wondering if this is a limitation of RavenDB. I noticed that if I switch && with ||, then I get no error. Of course, I don't get the results I want either. I've also tried rewriting the query as:
people = from p in people
where p.FirstName.StartsWith(SearchWords[0])
where p.LastName.StartsWith(SearchWords[1])
select p;
I get the same error.
I've also tried using a dynamic index instead of a static index. I get the same error.
I suppose maybe RavenDB LINQ driver cannot cope with extracting value from array inside the query. Try to put already extracted values in the place of SearchWords[0] and SearchWords[1] instead:
var pref1 = SearchWords[0];
var pref2 = SearchWords[1];
... where ( p.FirstName.StartsWith(pref1) && p.LastName.StartsWith(pref2) )
I suspect I'm missing something rather basic, yet I can't figure this one out.
I'm running a simple linq query -
var result = from UserLine u in context.Users
where u.PartitionKey == provider.Value && u.RowKey == id.Value
select u;
UserLine user = null;
try
{
user = result.FirstOrDefault();
}
For some reason this produces a TargetInvocationException with an inner exception of NullReferenceException.
This happens when the linq query produces no results, but I was under the impression that FirstOrDefault would return Default<T> rather than throw an exception?
I don't know if it matters, but the UserLine class inherits from Microsoft.WindowsAzure.StorageClient.TableServiceEntity
there are two possible reasons:
provider.Value
id.Value
Are you sure that theese nullables have value. You might want to check HasValue before
var result = from UserLine u in context.Users
where (provider.HasValue && u.PartitionKey == provider.Value)
&& (id.HasValue && u.RowKey == id.Value)
select u;
UserLine user = null;
try
{
user = result.FirstOrDefault();
}
I thought it produced a different error, but based on the situation in which the problem is occurring you might want to look to check if context.IgnoreResourceNotFoundException is set to false? If it is try setting it to true.
This property is a flag to indicate whether you want the storage library to throw and error when you use both PartitionKey and RowKey in a query and no result is found (it makes sense when you think about what the underlying REST API is doing, but it's a little confusing when you're using LINQ)
I figured it out - the problem occured when either id or provider had '/' in the value, which the id did. when I removed it the code ran fine
Understanding the Table Service Data Model has a section on 'Characters Disallowed in Key Fields' -
The following characters are not allowed in values for the
PartitionKey and RowKey properties:
The forward slash (/) character
The backslash () character
The number sign (#) character
The question mark (?) character
Here's some fun try putting the where query the other way around like this to see if it works (I heard a while ago it does!):
where (id.HasValue && u.RowKey == id.Value) && (provider.HasValue && u.PartitionKey == provider.Value)
Other than this you can now set IgnoreResourceNotFoundException = true in the TableServiceContext to receive null when an entity is not found instead of the error.
It's a crazy Azure storage thing.
My app consolidates data from other DBs for reporting purposes. We can't link the databases, so all the data processing has to be done in code - this is fine as we want to allow manual validation during the imports.
Certain users will be able to start an update through the Silverlight 4 front end.
I have 3 tables in database x that are fed from one EF4 Model (ModelX). I want to join those tables together, select specific columns and return the result as a new entity that exists in a different EF4 Model (ModelY). I'm using this query:
var myQuery = from i in DBx.table1 from it in DBx.table2 from h in DBx.table3 where (i.id==it.id && h.otherid == i.otherid) select new ModelYServer {Name = i.name,Thing = it.thing, Stuff = h.stuff};
The bit i'm stuck on, is how to execute that query, and wait until the Asynchronous call has completed. Normally, i'd use:
DomainContext.Load<T>(myQuery).Completed += (sender,args) =>
{List<T> myList = ((LoadOperation<T>)sender.Entities.ToList();};
but I can't pass myQuery (an IEnumerable) into the DomainContext.Load() as that expects an EntityQuery. The dataset is very large, and is taking up to 30 seconds to return, so I definitely need to wait before continuing.
So can anyone tell me how I can wait for the IEnumerable query to complete, or suggest a better way of doing this (there very likely is one).
Thanks
Mick
One simple way is just to force it to evaluate by calling ToList:
var query = from i in DBx.table1
join it in DBx.table2 on i.id equals it.id
join h in DBx.table3 on i.otherid equals h.otherid
select new ModelYServer {
Name = i.name,
Thing = it.thing,
Stuff = h.stuff
};
// This will block until the results have been fetched
var results = query.ToList();
// Now use results...
(I've changed your where clause into joins on the earlier tables, as that's what you were effectively doing and this is more idiomatic, IMO.)
I ran into an interesting error with the following LiNQ query using LiNQPad and when using Subsonic 3.0.x w/ActiveRecord within my project and wanted to share the error and resolution for anyone else who runs into it.
The linq statement below is meant to group entries in the tblSystemsValues collection into their appropriate system and then extract the system with the highest ID.
from ksf in KeySafetyFunction where ksf.Unit == 2 && ksf.Condition_ID == 1
join sys in tblSystems on ksf.ID equals sys.KeySafetyFunction
join xval in (from t in tblSystemsValues
group t by t.tblSystems_ID into groupedT
select new
{
sysId = groupedT.Key,
MaxID = groupedT.Max(g=>g.ID),
MaxText = groupedT.First(gt2 => gt2.ID ==
groupedT.Max(g=>g.ID)).TextValue,
MaxChecked = groupedT.First(gt2 => gt2.ID ==
groupedT.Max(g=>g.ID)).Checked
}) on sys.ID equals xval.sysId
select new {KSFDesc=ksf.Description, sys.Description, xval.MaxText, xval.MaxChecked}
On its own, the subquery for grouping into groupedT works perfectly and the query to match up KeySafetyFunctions with their System in tblSystems also works perfectly on its own.
However, when trying to run the completed query in linqpad or within my project I kept running into a SQLiteException SQLite Error Near "("
First I tried splitting the queries up within my project because I knew that I could just run a foreach loop over the results if necessary. However, I continued to receive the same exception!
I eventually separated the query into three separate parts before I realized that it was the lazy execution of the queries that was killing me. It then became clear that adding the .ToList() specifier after the myProtectedSystem query below was the key to avoiding the lazy execution after combining and optimizing the query and being able to get my results despite the problems I encountered with the SQLite driver.
// determine the max Text/Checked values for each system in tblSystemsValue
var myProtectedValue = from t in tblSystemsValue.All()
group t by t.tblSystems_ID into groupedT
select new {
sysId = groupedT.Key,
MaxID = groupedT.Max(g => g.ID),
MaxText = groupedT.First(gt2 => gt2.ID ==groupedT.Max(g => g.ID)).TextValue,
MaxChecked = groupedT.First(gt2 => gt2.ID ==groupedT.Max(g => g.ID)).Checked};
// get the system description information and filter by Unit/Condition ID
var myProtectedSystem = (from ksf in KeySafetyFunction.All()
where ksf.Unit == 2 && ksf.Condition_ID == 1
join sys in tblSystem.All() on ksf.ID equals sys.KeySafetyFunction
select new {KSFDesc = ksf.Description, sys.Description, sys.ID}).ToList();
// finally join everything together AFTER forcing execution with .ToList()
var joined = from protectedSys in myProtectedSystem
join protectedVal in myProtectedValue on protectedSys.ID equals protectedVal.sysId
select new {protectedSys.KSFDesc, protectedSys.Description, protectedVal.MaxChecked, protectedVal.MaxText};
// print the gratifying debug results
foreach(var protectedItem in joined)
{
System.Diagnostics.Debug.WriteLine(protectedItem.Description + ", " + protectedItem.KSFDesc + ", " + protectedItem.MaxText + ", " + protectedItem.MaxChecked);
}
Avoid lazy evaluation by forcing an early execution with .ToList() on one of the components of the final query. The results will go into memory so try to make sure you are choosing a small set of data and don't force an unbounded query or gigantic query into a list.