Linq to SQL: .FirstOrDefault() not applicable to select new { ... } - linq

I just asked this question. Which lead me to a new question :)
Up until this point, I have used the following pattern of selecting stuff with Linq to SQL, with the purpose of being able to handle 0 "rows" returned by the query:
var person = (from p in [DataContextObject].Persons
where p.PersonsID == 1
select new p).FirstOrDefault();
if (person == null)
{
// handle 0 "rows" returned.
}
But I can't use FirstOrDefault() when I do:
var person = from p in [DataContextObject].Persons
where p.PersonsID == 1
select new { p.PersonsID, p.PersonsAdress, p.PersonsZipcode };
// Under the hood, this pattern generates a query which selects specific
// columns which will be faster than selecting all columns as the above
// snippet of code does. This results in a performance-boost on large tables.
How do I check for 0 "rows" returned by the query, using the second pattern?
UPDATE:
I think my build fails because I am trying to assign the result of the query to a variable (this._user) declared with the type of [DataContext].User.
this._user = (from u in [DataContextObject].Users
where u.UsersID == [Int32]
select new { u.UsersID }).FirstOrDefault();
Compilation error: Cannot implicitly convert type "AnonymousType#1" to "[DataContext].User".
Any thoughts on how I can get around this? Would I have to make my own object?

Why can you keep doing the samething? Is it giving you an error?
var person = (from p in [DataContextObject].Persons
where p.PersonsID == 1
select new { p.PersonsID, p.PersonsAdress, p.PersonsZipcode }).FirstOrDefault();
if (person == null) {
// handle 0 "rows" returned.
}
It is still a reference object just like you actual object, it is just anonymous so you don't know the actual type before the code is compiled.

Update:
I see now what you were actually asking! Sorry, my answer no longer applies. I thought you were not getting a null value when it was empty. The accepted response is correct, if you want to use the object out of scope, you need to create a new type and just use New MyType(...). I know DevEx's RefactorPro has a refactoring for this, and I think resharper does as well.
Call .FirstOrDefault(null) like this:
string[] names = { "jim", "jane", "joe", "john", "jeremy", "jebus" };
var person = (
from p in names where p.StartsWith("notpresent") select
new { Name=p, FirstLetter=p.Substring(0,1) }
)
.DefaultIfEmpty(null)
.FirstOrDefault();
MessageBox.Show(person==null?"person was null":person.Name + "/" + person.FirstLetter);
That does the trick for me.

Regarding your UPDATE: you have to either create your own type, change this._user to be int, or select the whole object, not only specific columns.

if (person.Any()) /* ... */;
OR
if (person.Count() == 0) /* ... */;

You can still use FirstOrDefault. Just have
var PersonFields = (...).FirstOrDefault()
PersonFields will be be null or an object with those properties you created.

Related

How do I know if my linq will return a useable object or a null

I am working on a web service. I am using linq to query a database. Seemingly simple, but I've run into an issue. Here is my code for reference:
List<Comment> res = new List<Comment>();
using (ApplicationHistoryEntities ahe = new ApplicationHistoryEntities())
{
res = (from columns in ahe.Comments
where columns.NetforumId == actionuniqueid
select columns).ToList();
}
If I have no entries in the database, will my .ToList() throw an error? I could deploy it, and just try it out but I want to know more about the mechanism that my linq is using. If ahe.Comments database has no rows... what will the (from...) section return?
I could just add a null reference check, use dynamics etc but I want to really understand it.
I found this Q: how to know if my linq query returns null but it seems like all of the answers are in conflict on how it really should be done...
example answers:
Either you can convert it to list and then check the count
Best approach is to check there is null(no items) in list use Any() instead of count()
LINQ queries should never return null and you should not get an exception if the result is empty. You probably have an error in your code.
You can realise the result as a list then check the items.
You can see why I question how it works.
Edit:
Final code looks like this:
List<Comment> res;
using (ApplicationHistoryEntities ahe = new ApplicationHistoryEntities())
{
res = ahe.Comments?.Where(rowItem => rowItem.NetforumId == actionuniqueid).ToList() ??
new List<Comment>().ToList();
}
Look at this example:
List<string> test = new List<string>();
var test1 = test.Where(x => x == "a").ToList();
If test exists but is empty the query returns an empty list. If test is null the query throws an error. So you can adapt the query as follows
List<string> test = new List<string>();
test = null;
var test1 = test?.Where(x => x == "a") ?? new List<string>().ToList();
The query is now 'safe'. Both of the above examples return an empty list i.e. test1.Count() will return zero but will be usable.
You can also look at the definitions of Where and ToList

Linq - How to query specific columns and return a lists

I am trying to write a linq query that will only return certain columns from my entity object into a list object.
Below is my code which produces an error(can't implicitly convert a generic list of anonymous types to a generic list of type TBLPROMOTION):
IQueryable<TBLPROMOTION> matches = webStoreContext.TBLPROMOTION.Include("TBLSTORE").Include("LKPROMOTIONTYPE");
List<TBLPROMOTION> promotionInfo = null;
promotionInfo = (from p in matches
orderby p.PROMOTION_NM descending
select new { p.EFFECTIVE_DT, p.EXPIRE_DT, p.IS_ACTIVE,
p.PROMOTION_DESC, p.PROMOTION_ID, p.PROMOTION_NM }).ToList();
What would be the best way to accomplish this. I do not want to do a "select p" in this case and return all the columns associated with the query.
thanks in advance,
Billy
Can't you do var promotionInfo = () and get a list of anonymous types?
Okay, basically you can not cast an Anonymous type to a known type like TBLPROMOTION.
ofcourse, you can say var promotionInfo = and then get an IEnumerable<{Anonymoustype}> and use that to do, what you were wanting to do with promotionInfo.
Also, personally I prefer the Fluent version of a linq query, easy on the eyes, good programming diet, at least for me :)
var promotionInfo = matches
.OrderByDescending( p => p.PROMOTION_NM)
.Select( p => new { p.EFFECTIVE_DT,
p.EXPIRE_DT,
p.IS_ACTIVE,
p.PROMOTION_DESC,
p.PROMOTION_ID,
p.PROMOTION_NM})
.ToList();
If you're moving from a L2E query to a Type already defined, you may need a step between. I haven't tried to compile this but something like:
List<TBLPROMOTION> promotions = new List<TBLPROMOTION>();
var results = from p in matches
orderby p.PROMOTION_NM descending
select new
{
p.EFFECTIVE_DT,
p.EXPIRE_DT,
p.IS_ACTIVE,
p.PROMOTION_DESC,
p.PROMOTION_ID,
p.PROMOTION_NM
};
foreach (var v in results)
{
promotions.Add(new TBLPROMOTION(v.EFFECTIVE_DT, v.EXPIRE_DT, v.IS_ACTIVE,
v.PROMOTION_DESC, v.PROMOTION_ID, v.PROMOTION_NM));
}
Based on the comment below, you might try something like:
foreach(var v in results)
{
TBLPROMOTION temp = new TBLPROMOTION();
temp.EFFECTIVE_DT = v.EFFECTIVE_DT;
temp.EXPIRE_DT = v.EXPIRE_DT;
temp.IS_ACTIVE = v.IS_ACTIVE
// Assign Other Properties
promotions.Add(temp);
}
.......
Sorry: Just read the addition to the top.
Are you sure that none of the fields you're leaving out (instead of saying "select p") are required for a TBLPROMOTION object? Also, sense your TBLPROMOTION object is going to have properties (and therefore memory allocated) for those skipped fields, why not just use an annonymous type or set up a helper class that contains only your needed properties?
#Billy, following code worked for me.
List<TBLPROMOTION> promotionInfo =
(from p in matches
orderby p.PROMOTION_NM descending
select new TBLPROMOTION(p.EFFECTIVE_DT, p.EXPIRE_DT, p.IS_ACTIVE,
p.PROMOTION_DESC, p.PROMOTION_ID, p.PROMOTION_NM)
).ToList();
did you try
select new TBLPROMOTION {.....
instead of
select new {.....
List<TBLPROMOTION> promotionInfo = null;
promotionInfo = (from p in matches
orderby p.PROMOTION_NM descending
select new TBLPROMOTION { COL1 = p.EFFECTIVE_DT, COL2 = p.EXPIRE_DT, COL3 = p.IS_ACTIVE... }).ToList();
Where COL1, COL2, ... are the names of the properties on TBLPROMOTION you wish you populate.
If you want a subset of the table you have 2 options:
#Fredou mentioned select new TBLPROMOTION{...}
other way is to create a custom DTO which has the exact properties & select them instead like:
List promotionInfo = ...
select new TBLPROMOTION_DTO{
Effective_dt = ...
}
HTH

LINQ to dataset: CopyToDataTable()

I want to query a datatable (dt) and load a 2nd dt with the resultant collection of datarows. Fine - we have the CopyToDataTable() extn mthd for exactly that purpose. However it is constrained to enumerate only over DataRows, which means that I cannot return anything else e.g. a collection of anonymous types. So - how can I modify the values in the datarows?
Eg I have a dt with 3 columns: MyPK, VARCHAR01, VARCHAR02.
Foreach row, if VARCHAR01 or VARCHAR02 has the value "" (i.e. String.Empty) I want to replace that with NULL (which the underlying type allows).
I would do this as follows:
var MyCleanedDatarows =
from o in ds.Tables["dt"].AsEnumerable()
select new {
MyPK = o.Field<string>("MyPK"),
VARCHAR01 = (o.Field<string?>("VARCHAR01") == "" ? NULL : o.Field<string?>("VARCHAR01") ),
VARCHAR02 = (o.Field<string?>("VARCHAR02") == "" ? NULL : o.Field<string?>("VARCHAR02") )
};
...but then I cant use CopyToDataTable() to get back to a dt. I'm thinking I need to modify the datarows before invoking select operator, but I dont know how to achieve that. Any help/thoughts would be v.greatfully recieved.
Thanks in advance,
Tamim.
Take a look at this approach, in MSDN documentation.
http://msdn.microsoft.com/en-us/library/bb669096.aspx

DataTable Query

I am new to LINQ. I am trying to find the rows that does not exists in the second data table.
report_list and benchmark both type are : DataTable. Both these datatables are being populated using OleDbCommand,OleDbDataAdapter. I am getting an error "Specified cast is not valid." in foreach ... loop. I would appreciate your help.
var result = from a in report_list.AsEnumerable()
where !(from b in benchmark.AsEnumerable()
select b.Field<int>("bench_id")
)
.Contains(a.Field<int>("BenchmarkID"))
select a;
foreach (var c in result)
{
Console.WriteLine(c.Field<string>("Name"));
}
I don't know if I understood your question. Are you trying to get the items that exists in the first table but not in the second?
var first = new string[] { "b", "c" };
var second = new string[] { "a", "c" };
//find the itens that exist in "first" but not in "second"
var q = from f in first
where !second.Contains(f)
select f;
foreach (var s in q) {
Console.WriteLine(s);
}
//Prints:
//b
I suggest you to make the inner query first, once it does not depend on the outer record.
From a in report_list
Group Join b in benchmark On a.bench_id Equals b.bench_id Into g = Group
Where g.Count = 0
Select a
Note that this is VB syntax.
My suspicion is that one of the fields you are comparing is not an integer in the database. I believe that the invalid cast exception is being thrown by one of the Field<int>() calls since that is one of the three different exceptions that this method can throw. See docs here.
Perhaps use the .Except() extension to get the set difference of the two sets?
(from b in benchmark.AsEnumerable()
select new { id = b.Field<int>("bench_id")}).Except(
from a in report_list.AsEnumerable()
select new {id = a.Field<int>("BenchmarkID")})
Not actually sure of the precise syntax, but that should work by taking the ids in benchmark, and then removing all equivalent ids in report_list, leaving only the ids that don't match. (I hope this is the order you were after...)
Note: This is also assuming that the above issue mentioned by tvanfosson isn't also a problem

LINQ to SQL bug (or very strange feature) when using IQueryable, foreach, and multiple Where

I ran into a scenario where LINQ to SQL acts very strangely. I would like to know if I'm doing something wrong. But I think there is a real possibility that it's a bug.
The code pasted below isn't my real code. It is a simplified version I created for this post, using the Northwind database.
A little background: I have a method that takes an IQueryable of Product and a "filter object" (which I will describe in a minute). It should run some "Where" extension methods on the IQueryable, based on the "filter object", and then return the IQueryable.
The so-called "filter object" is a System.Collections.Generic.List of an anonymous type of this structure: { column = fieldEnum, id = int }
The fieldEnum is an enum of the different columns of the Products table that I would possibly like to use for the filtering.
Instead of explaining further how my code works, it's easier if you just take a look at it. It's simple to follow.
enum filterType { supplier = 1, category }
public IQueryable<Product> getIQueryableProducts()
{
NorthwindDataClassesDataContext db = new NorthwindDataClassesDataContext();
IQueryable<Product> query = db.Products.AsQueryable();
//this section is just for the example. It creates a Generic List of an Anonymous Type
//with two objects. In real life I get the same kind of collection, but it isn't hard coded like here
var filter1 = new { column = filterType.supplier, id = 7 };
var filter2 = new { column = filterType.category, id = 3 };
var filterList = (new[] { filter1 }).ToList();
filterList.Add(filter2);
foreach(var oFilter in filterList)
{
switch (oFilter.column)
{
case filterType.supplier:
query = query.Where(p => p.SupplierID == oFilter.id);
break;
case filterType.category:
query = query.Where(p => p.CategoryID == oFilter.id);
break;
default:
break;
}
}
return query;
}
So here is an example. Let's say the List contains two items of this anonymous type, { column = fieldEnum.Supplier, id = 7 } and { column = fieldEnum.Category, id = 3}.
After running the code above, the underlying SQL query of the IQueryable object should contain:
WHERE SupplierID = 7 AND CategoryID = 3
But in reality, after the code runs the SQL that gets executed is
WHERE SupplierID = 3 AND CategoryID = 3
I tried defining query as a property and setting a breakpoint on the setter, thinking I could catch what's changing it when it shouldn't be. But everything was supposedly fine. So instead I just checked the underlying SQL after every command. I realized that the first Where runs fine, and query stays fine (meaning SupplierID = 7) until right after the foreach loop runs the second time. Right after oFilter becomes the second anonymous type item, and not the first, the 'query' SQL changes to Supplier = 3. So what must be happening here under-the-hood is that instead of just remembering that Supplier should equal 7, LINQ to SQL remembers that Supplier should equal oFilter.id. But oFilter is a name of a single item of a foreach loop, and it means something different after it iterates.
I have only glanced at your question, but I am 90% sure that you should read the first section of On lambdas, capture, and mutability (which includes links to 5 similar SO questions) and all will become clear.
The basic gist of it is that the variable oFilter in your example has been captured in the closure by reference and not by value. That means that once the loop finishes iterating, the variable's reference is to the last one, so the value as evaluated at lambda execution time is the final one as well.
The cure is to insert a new variable inside the foreach loop whose scope is only that iteration rather than the whole loop:
foreach(var oFilter in filterList)
{
var filter = oFilter; // add this
switch (oFilter.column) // this doesn't have to change, but can for consistency
{
case filterType.supplier:
query = query.Where(p => p.SupplierID == filter.id); // use `filter` here
break;
Now each closure is over a different filter variable that is declared anew inside of each loop, and your code will run as expected.
Working as designed. The issue you are confronting is the clash between lexical closure and mutable variables.
What you probably want to do is
foreach(var oFilter in filterList)
{
var o = oFilter;
switch (o.column)
{
case filterType.supplier:
query = query.Where(p => p.SupplierID == o.id);
break;
case filterType.category:
query = query.Where(p => p.CategoryID == o.id);
break;
default:
break;
}
}
When compiled to IL, the variable oFilter is declared once and used multiply. What you need is a variable declared separately for each use of that variable within a closure, which is what o is now there for.
While you're at it, get rid of that bastardized Hungarian notation :P.
I think this is the clearest explanation I've ever seen: http://blogs.msdn.com/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx:
Basically, the problem arises because we specify that the foreach loop is a syntactic sugar for
{
IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator();
try
{
int m; // OUTSIDE THE ACTUAL LOOP
while(e.MoveNext())
{
m = (int)(int)e.Current;
funcs.Add(()=>m);
}
}
finally
{
if (e != null) ((IDisposable)e).Dispose();
}
}
If we specified that the expansion was
try
{
while(e.MoveNext())
{
int m; // INSIDE
m = (int)(int)e.Current;
funcs.Add(()=>m);
}
then the code would behave as expected.
The problem is that you're not appending to the query, you're replacing it each time through the foreach statement.
You want something like the PredicateBuilder - http://www.albahari.com/nutshell/predicatebuilder.aspx

Resources