I am having an issue with Linq at the moment. We are using the Telerik controls in a WPF application in C#. I have am "array" of clients. The type of array is a QueryableEntityCoreCollectionView, which is from Telerik. This is the source of a gridview.
I now need to make a property which will return a subset of these clients. No matter what conditions I put in my Where clause, the Where fails and gives me the classic Object is not set to an Instance blahblahblah. (the grid is able to get a IEnumerable, so I don't have to convert back into a QueryableEntityCoreCollectionView at the end.
Here is a bit of code I am trying to play around with:
public IEnumerable<Client> FilteredClients {
get {
IEnumerable<Client> res1 = clients.AsEnumerable<Client>();
IEnumerable<Client> res2 = res1.Where(T => 1 == 1);
return res2;
}
}
In the above example, res1 contains 11 elements. res2 does not work. It goes over it, I don't receive an actual exception, but if I put a breakpoint on the return, and check out both res1 and res2, I can see res1 is okay, res2 when I open it's result view, I get the message "Object reference not set to an instance of an object." with the stack trace:
at System.Linq.Enumerable.WhereEnumerableIterator`1.ToArray()
at System.Linq.SystemCore_EnumerableDebugView`1.get_Items()
Given the search criteria "1==1", I would expect everything to come out of it... But it fails. Even with a real search, like T => T.City == T.City, it also fails the same way. No matter what I give to Where(), it fails. If I simply return res1 here, my full list passes back to my datagrid as an IEnumerable, and everything works fine. As soon as I try to filter on anything, it fails.
Any ideas?
edit:
After Hazrelle comment, I tried calling .ToList() ... But everytime I try to do that, I get a Null Exception.
clients.ToList<Client>(); // fails
clients.AsEnumerable<Client>().ToList<Client>(); // fails
Everything I try fails, and I don't know why...
Edit 2: Still not able to filter or anything... However I got the following line of code to pass:
var query = clients.SourceCollection.ToEnumerable().First();
However, query is not a Client, but rather a Telerik.Windows.Data.QueryableProxy , and is still seen as a collection with 11 items. It is NOT just the first Client.
Seems like this QueryableEntityCoreCollectionView object is either bugged, or we are not supposed to play with it, and should only be handled internally by Telerik stuff, but I have resolved the problem by never creating this object, I create a good ol' List of Client directly and give this to the grid instead. Linq works like a charm then...
For some reason, no amount of AsEnumerable, ToList, AsWhatever I did to a QueryableEntityCoreCollectionView(of Client), it always became a QueryableEntityView(of Client) at best, never actually became a simple List(of Client).
Strange.
It is very possible I am loosing the ability to update the database by doing that, However, at this point, this is not data that is meant to be updateable, at least not from that window.
Related
I'm using a promise library that requires every promise chain to eventually be terminated by a .Done() call. The problem is that it's quite easy to forget it, and when that happens exceptions from within promises are swallowed which is quite bad.
i.e. these are all ok:
DoThingThatReturnsAPromise()
.Then(() => Log("Finished") // <-- returns IPromise
.Done(); // <-- void method. Everything ok, error handler attached
IPromise DoThing()
{
return DoOtherThing(); // Also ok, the calling method should make sure to use the return value though
}
Incorrect usage would be:
DoThingThatReturnsAPromise()
.Then(() => Log("Finished"); // <-- WRONG! We're leaving the IPromise as a statement, not attaching error handler
void DoThing()
{
DoThingThatReturnsPromise();
}
JetBrain's MustUseReturnValue attribute does almost what I want... It's just that I'd have to go through every method that returns a Promise (there are A LOT) and add it. Also, whenever somebody on my team writes a new function that returns an IPromise, they will probably forget to add it.
TL;DR:
I guess what I'm looking for is a way to tag a certain type (in this case IPromise) value, and detect if it's used as a statement. i.e. the last thing before a ; so I can add a linting rule for it.
This is exactly what Roslyn analyzers are for. In fact, there are a couple already written for "things that must use the return value of things" in the Microsoft.CodeAnalysis.NetAnalyzers package:
one that checks that IDisposable objects are eventually disposed.
one that checks that Linq statements that don't materialize the sequence are eventually materialized (this is very close to yours, it's things like arr.Select(x => x + 1);)
You can look at their source code for inspiration if you wish and write your own promise code analyzer that you can then reference from any project where you wish it to run.
In the controller of my .net core web application I have the following endpoint:
[HttpGet]
public IEnumerable<BusAppl> BusinessApplications()
{
var temp = _context.BusAppl
.Include(d=>d.BusApplDpndncyBusAppl)
.Include(d=>d.BusApplDpndncyDepBusAppl);
return temp;
}
If I have a breakpoint on line return temp;, the d.BusApplDpndncyDepBusApplproperty (the second Include) seems to be included correctly. If I have no breakpoint it's null. It seems unlikely to me that this is the real problem, but this is how I am able to reproduce it 100% of the time.
If I .ToList() the whole result that forces it to be evaluated and seems to fix the issue, but should that be necessary?
What can be the issue here?
Actually you have only a selection of data but no projection. You have to add e.g. ToList() or ToArray() to project (execute) the selection (query). It will cause the result's transformation into targeting type. If no result exists, it returns an empty list or array (targeting to examples above).
Well, in other words your LINQ-to-Entities query will be converted into SQL and executed against server and retrieves the result.
If you add a breakpoint the query will be executed by VS under the hood too. Therefore you have no exception.
I'm not sure, but it seems to be that Include will be executed only on projection.
Nevertheless, if you will not modify a query (IQueryable<T>) and you want the result, you should execute it. Otherwise it could result in a performance issue.
As queries in linq works on deferred execution concept .ToList() is helpful to get result of query immediatly i.e. it execute query and returns you result.
If you want to return full result than you must use
var temp = (_context.BusAppl
.Include(d=>d.BusApplDpndncyBusAppl)
.Include(d=>d.BusApplDpndncyDepBusAppl)).ToList();
I havent worked on entity framework much , so cannot comment on breakpoint issue. may be its doing async operation
public IQueryable<Application> GetAppById(Guid Id)
{
return Repository.Query().Where(c => c.Id == Id).Select(c => c.App)
}
I got this code above and it seems like it doesn't return right. If I call another repository in the DB such as Repository2.Query().Where(??code??). I got the error below.
ERROR:
{"There is already an open DataReader associated with this Command which must be closed first."}
However, when I change the return to ICollection<> it responses right.
public ICollection<Application> GetAppById(Guid Id)
{
return Repository.Query().Where(c => c.Id == Id).Select(c => c.App).ToList();
}
I debug IQueryable return, there is no error but I couldn't find find the data that it retrieves. The error takes place when you call another to the repo.
The message is correct; you have allowed two commands to execute simultaneously. The first method shown returns a "query" - it doesn't actually execute anything until you iterate it - and is open until you stop iterating it. Indeed, the entire purpose of IQueryable<T> is to allow additional composition prior to execution. So assuming you are using foreach, the query is active for the duration of the foreach, not the call to GetAppById itself. So if you do the classic "N+1":
foreach(var row in SomeOuterQuery(...)) { // N+1, not a great idea
SomeInnerQuery(row, ...);
}
then you are absolutely running multiple simultaneous commands.
There are three main fixes:
run the first query in full, and then iterate the results - that is what adding ToList does: it moves the foreach to inside GetAppById
enable "MARS" (Multiple Active Result Sets) - note: this is not advice, simply a "this will work" (but: not everything that works is a good idea)
restructure the work to never need the "N" in the "N+1", for example by fetching the additional data at the same time as the outer list (multiple result grids from a single query, for example)
I am using automapper. The code looks something like this:
var processedRecords = await queriedRecords.Project(x =>
Mapper.Map<BsonDocument, RecordViewModel>(x)).ToListAsync();
My problem is that I cannot put System.Diagnostics.Debug.WriteLine() inside the map definition. Is there any way to know which record automapper errors out on? The way I have been doing it is putting a break point in and clicking continue, but now I am working with a db with millions of records, so obviously that's not practical.
The exception is "Object reference not set to an instance of an object." Which I assume means that the object doesn't have the property I am trying to map, but it's irrelevant to the q. More interested in the theory here.
Well, you can actually put a Debug.WriteLine() in your lambda here. Simply make it a block instead of just an expression:
var processedRecords = await queriedRecords.Project(x =>
{
System.Diagnostics.Debug.WriteLine(x);
return Mapper.Map<BsonDocument, RecordViewModel>(x);
}).ToListAsync();
You can also put a try/catch around the Mapper.Map<,>() call if you want to now.
I was reading up on LINQ. I know that there are deferred and immediate queries. I know with deferred types running the query when it's enumerated allows any changes to the data set to be reflected in each enumeration. But I can't seem to find an answer if there's a mechanism in place to prevent the query from running if no changes occurred to the data set since the last enumeration.
I read on MSDN referring to LINQ queries:
Therefore, it follows that if a query is enumerated twice it will be executed twice.
Have I overlooked an obvious - but...?
Indeed, there is none. Actually, that's not quite true - some LINQ providers will spot trivial but common examples like:
int id = ...
var customer = ctx.Customers.SingleOrDefault(x => x.Id == id);
and will intercept that via the identity-manager, i.e. it will check whether it has a matching record already in the context; if it does: it doesn't execute anything.
You should note that the re-execution also has nothing to do with whether or not data has changed; it will re-execute (or not) regardless.
There are two take-away messages here:
don't iterate any enumerable more than once: not least, it isn't guaranteed to work at all
if you want to buffer data, put it into a list/array
So:
var list = someQuery.ToList();
will never re-execute the query, no matter how many times you iterate over list. Because list is not a query: it is a list.
A third take-away would be:
if you have a context that lives long enough that it is interesting to ask about data migration, then you are probably holding your data-context for far, far too long - they are intended to be short-lived