C# IQueryable<T> does my code make sense? - c#

I use this to get a list of materials from my database....
public IQueryable<MaterialsObj> FindAllMaterials()
{
var materials = from m in db.Materials
join Mt in db.MeasurementTypes on m.MeasurementTypeId equals Mt.Id
select new MaterialsObj()
{
Id = Convert.ToInt64(m.Mat_id),
Mat_Name = m.Mat_Name,
Mes_Name = Mt.Name,
};
return materials;
}
But i have seen in an example that has this,
public IQueryable<MaterialsObj> FindAllMaterials()
{
return from m in db.Materials
join Mt in db.MeasurementTypes on m.MeasurementTypeId equals Mt.Id
select new MaterialsObj()
{
Id = Convert.ToInt64(m.Mat_id),
Mat_Name = m.Mat_Name,
Mes_Name = Mt.Name,
};
}
Is there a real big difference between the two methods... Assigning my linq query to a variable and returning it... Is it a good/bad practise? Any suggestion which should i use?

No real difference. In a release / optimized build I would expect the compiler to remove the extra local, anyway. Having the variable is useful if you want to put a breakpoint in and inspect the value prior to return, or if you want to apply additional conditional filtering, for example:
if(applySort) { materials = materials.OrderBy(x => x.Name); }
In your example it doesn't add anything, but it also doesn't cost anything either. Feel free to keep it there; especially if you think it makes the code easier to read.

There's no difference, but usually I use the 1st version which makes it easier to set a watch or breakpoint in visual studio if I want to look at the data before it's returned.

Related

LINQ query help please, for each works?

I have a problem with some code that simply can’t work in LINQ, but it does work as a simple for..each. Any explanation and solution would be appreciated.
I have 3 classes, Users, User , UserPermissions composed as follows:
Class Users
ObservableCollection<User> GetList
Class User
Public int id {get;set;}
Public string UserName {get;set;}
Public UserPermissions Permissions {get;set;}
Class UserPermissions
Public Int ID {get;set;}
Public int ApplicationID {get;set;}
This works and returns the correct user:
Users users = new Users();
foreach (User u in users.GetList() )
{
if (u.UserName==username && u.Permissions.ApplicationID == applicationId)
{
usr = u;
break;
}
}
The linq below 'should' do the same thing, but it doesn’t. There are no errors returned or raised in the output window, and the musers variable simply doesn't exist after stepping over it. I have tried being more specific in my casts and using AsQueryable. I even tried let p=u.Permissions, using two from commands, but nothing seems to fix it.
My worry is that my other classes will suffer from this and cause issues later on as more complex queries are used.
var musers = from Users.User u in UsersList
where (u.UserName==userName)
&& (u.Permissions.ApplicationID == ApplicationId)
select u.ID;
One more bit of information the following errors too?
var t1 = UsersList.SelectMany( u => u.Permissions);
Error 1 The type arguments for method 'System.Linq.Enumerable.SelectMany(System.Collections.Generic.IEnumerable, System.Func>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
var usr = users.GetList()
.FirstOrDefault(
p => p.UserName == username
&& p.Permissions.ApplicationID == applicationId);
Should actually do it for you. FirstOrDefault can return null, if no user has been found...
Adam was spot on thank you Adam.
I have seen in the debugger that 'var found=from...' showed that found is created and contains a value at the point where the linq statement is run. However, as Adam correctly states that linq enumeration is deferred until the point you enumerate the query. The reason it all looked fine to me was that directly under the code that worked was a for loop which triggers the enumeration for THAT linq query. The others above it had no such enumeration so just looked as if they had failed silently!
I think the compiler was optimizing the function so that I could debug the linq query at the point it is in the code rather than where the enumeration occurs, nice trick but it completely wrong footed me! lol. It made me think that the query itself is evaluated to some degree even if the results aren't available until you use ToList(), Count() or other enumeration function.
for example in the code below only f3 will contain anything at all, the others are just, well, nothing because they are never enumerated!
var f1 = from .....;
var f2 = from ....;
var f3 = from ....;
do lots of other stuff, even call a function
int count = f3.Count();
What is interesting is that f1, f2 are nothing even after the line runs but f3 has a value immediately after and before the enumeration (Count) takes place, so i think compiler optimization/debug is playing a part here.
Hope this helps someone else :)

What's wrong with this LINQ, converting one object to another?

I'm trying to have a one-liner LINQ statement to project my one object to my ViewModel object - it seems it won't work with select?? The compiler says cannot resolve symbol select. This works with a collection, why doesn't it here? If not select, what keyword am I missing?
return from p in SettingRepository.Get(id)
select new EditSetting
{
};
Edit - Scratch that, doesn't work for a list. How can I accomplish this?
Although I'm not sure why you would want to use select to do this, but if you're really adamant about it:
return from p in new List<EntityObject>{SettingRepository.Get(id)}
select new EditSetting
{
};
If not, why not just use good old initializers?
var editSetting= new EditSetting { Id = setting.Id };
Typically I prefer to create methods with the following pattern. It discourages tight looping of Database calls, which can severely limit performance. Still Bryan Hong's answer is the actual ANSWER to your question.
public IQueryable<EditSetting> GetEditSettings()
{
return from p in SettingRepository
select new EditSetting{
Foo = p.Foo,
Bar = p.Bar,
//etc...
};
}
or
public IEnumerable<EditSetting> GetEditSettingsById(IList<string> ids)
{
var ret = from p in SettingRepository
where ids.Contains(p.Id)
select new EditSetting{
Foo = p.Foo,
Bar = p.Bar,
//etc...
};
return ret.ToList();
}

Linq deferred execution with local values

I've been experimenting with Linq to see what it can do - and I'm really loving it so far :)
I wrote some queries for an algorithm, but I didn't get the results I expected... the Enumeration always returned empty:
case #1
List<some_object> next = new List<some_object>();
some_object current = null;
var valid_next_links =
from candidate in next
where (current.toTime + TimeSpan.FromMinutes(5) <= candidate.fromTime)
orderby candidate.fromTime
select candidate;
current = something;
next = some_list_of_things;
foreach (some_object l in valid_next_links)
{
//do stuff with l
}
I changed the query declaration to be inline like this, and it worked fine:
case #2
foreach (some_object l in
(from candidate in next
where (current.toTime + TimeSpan.FromMinutes(5) <= candidate.fromTime)
orderby candidate.fromTime
select candidate))
{
//do stuff with l
}
Does anybody know why it doesn't work in case #1 ?
The way I understood it, the query wasn't evaluated when you declared it, so I don't see how there is a difference.
Changes to current will be captured, but the query already knows the value of next. Adding extra items to the existing list will make them show up in the query, but changing the value of the variable to refer to a different list entirely won't have any effect. Basically, if you mentally expand the query from a query expression into a "normal" form, any variable present in a lambda expression will be captured as a variable, but any variable present directly as an argument will be evaluated immediately. That will only capture the reference value of the variable, not the items present in the list, but it still means changing the variable value itself won't be seen. Your first query expands to:
var valid_next_links = next
.Where(candidate => (current.toTime + TimeSpan.FromMinutes(5) <= candidate.fromTime))
.OrderBy(candidate => candidate.fromTime);

Running identical code on 2 objects

I have a test script that does something to one object then the same thing to a second object. This continues for quite a while. With so much predictable repetition that it seems ripe for automation but I can't figure out how. I wouldn't care so much except with so much repetition, it's easy to overlook using the wrong variable (ie: stagingXyz when prodXyz was intended.)
The details below are irrelevant. What's important is the pattern.
var stagingDbs = cleanupDbs(stagingServer.Databases);
var prodDbs = cleanupDbs(prodServer.Databases);
printDiff(stagingDbs, prodDbs, "Databases mis-matched");
foreach (var db in stagingDbs.Intersect(prodDbs)) {
var stagingDb = stagingServer.Databases[db];
var prodDb = prodServer.Databases[db];
var stagingTables = cleanupTables(stagingDb.Tables);
var prodTables = cleanupTables(prodDb.Tables);
printDiff(stagingTables, prodTables, "Tables mis-matched on " + db);
foreach (var table in stagingTables.Intersect(prodTables)) {
var stagingTable = stagingDb.Tables[table];
var prodTable = prodDb.Tables[table];
var matchedColumns = stagingColumns.Intersect(prodColumns);
var stagingTableColumns = stagingTable.Columns
.Cast<Column>()
.Where(c => matchedColumns.Contains(c.Name))
.Select(c => formatColumn(c));
var prodTableColumns = prodTable.Columns
.Cast<Column>()
.Where(c => matchedColumns.Contains(c.Name))
.Select(c => formatColumn(c));
printDiff(stagingTableColumns, prodTableColumns,
"Columns mis-matched");
}
}
I don't want to go through, for instance, replacing this
var stagingTableColumns = stagingTable.Columns
.Cast<Column>()
.Where(c => matchedColumns.Contains(c.Name))
.Select(c => formatColumn(c));
var prodTableColumns = prodTable.Columns
.Cast<Column>()
.Where(c => matchedColumns.Contains(c.Name))
.Select(c => formatColumn(c));
with this
var stagingTableColumns = doStuff(stagingTable, matchedColumns);
var prodTableColumns = doStuff(prodTable, matchedColumns);
because I have to make sure everything in the 1st line is stagingXyz and the 2nd line is prodXyz. Not so bad for 1 line but the test script is huge and only ever does one of these 2 things:
foo(stagingXyz); foo(prodXyz);
bar(stagingXyz, prodXyz);
Similarly, wrapping with these items in an array and having doStuff[0]; doStuff[1]; is subject to the same easy typo error only a typo with 0 vs. 1 will be even harder to spot at a glance.
I thought about making 2 container objects (one for staging, one for prod) and putting these 2 objects in a collection but I fear this will lead to a bazillion tiny loops that will be very hard to maintain.
Is there anyway to simplify this and still have it be readable and maintainable?
Could you generate your test script? The input might read something like
var %%AB%%Dbs = cleanupDbs(%%AB%%Server.Databases);
printDiff(%%A%%Dbs, %%B%%Dbs, "Databases mis-matched");
foreach (var db in %%A%%Dbs.Intersect(%%B%%Dbs)) {
var %%AB%%Db = %%AB%%Server.Databases[db];
var %%AB%%Tables = cleanupTables(%%AB%%Db.Tables);
printDiff(%%A%%Tables, %%B%%Tables, "Tables mis-matched on " + db);
...
}
A line containing %%AB%% might expand to two copies of the same line, one with the "A" replacement and one with the "B" replacement, where %%A%% or %%B%% by itself might just get replaced.
Edit - After reading your comments I see the problem a bit clearer now. I think the problem is more the clarity of the one big function vs. coming up with a funky way to solve the readability problem. I think the more you broke it up into smaller functions, the clearer it would get.
If the main function was broken up into something like this:
public void mainMethod(DB prodDB, DB stagingDB)
{
doPart1(prodDB, stagingDB);
doPart2(prodDB, stagingDB);
}
...and each part had well named inputs like so:
public void doPart1(DB prodDB, DB stagingDB)
{
// Code...
}
Things would clear themselves up as you made things work at a more and more granular level. Anyone working in the doPart1 method only has to be concerned with it's small amount of code, and anyone working in the main section shouldn't have a million things to look over. I understand if this may sound like an oversimplified response, but it sounds like you're trying to solve a problem that shouldn't exist if the code is properly broken up.
If there is a method that is so huge and unreadable that another developer couldn't figure out what's going on with only TWO variables, then there is a different problem.

When to use an extension method with lambda over LINQtoObjects to filter a collection?

I am prototyping some C# 3 collection filters and came across this.
I have a collection of products:
public class MyProduct
{
public string Name { get; set; }
public Double Price { get; set; }
public string Description { get; set; }
}
var MyProducts = new List<MyProduct>
{
new MyProduct
{
Name = "Surfboard",
Price = 144.99,
Description = "Most important thing you will ever own."
},
new MyProduct
{
Name = "Leash",
Price = 29.28,
Description = "Keep important things close to you."
}
,
new MyProduct
{
Name = "Sun Screen",
Price = 15.88,
Description = "1000 SPF! Who Could ask for more?"
}
};
Now if I use LINQ to filter it works as expected:
var d = (from mp in MyProducts
where mp.Price < 50d
select mp);
And if I use the Where extension method combined with a Lambda the filter works as well:
var f = MyProducts.Where(mp => mp.Price < 50d).ToList();
Question: What is the difference, and why use one over the other?
LINQ turns into method calls like the code you have.
In other words, there should be no difference.
However, in your two pieces of code you are not calling .ToList in the first, so the first piece of code will produce an enumerable data source, but if you call .ToList on it, the two should be the same.
As mentioned d will be IEnumerable<MyProduct> while f is List<MyProduct>
The conversion is done by the C# compiler
var d =
from mp in MyProducts
where mp.Price < 50d
select mp;
Is converted to (before compilation to IL and with generics expanded):
var d =
MyProducts.
Where<MyProduct>( mp => mp.Price < 50d ).
Select<MyProduct>( mp => mp );
//note that this last select is optimised out if it makes no change
Note that in this simple case it makes little difference. Where Linq becomes really valuable is in much more complicated loops.
For instance this statement could include group-bys, orders and a few let statements and still be readable in Linq format when the equivalent .Method().Method.Method() would get complicated.
Other than the ToList difference, #2 is a lot more readable and natural IMO
The syntax you are using for d will get transformed by the compiler into the same IL as the extension methods. The "SQL-like" syntax is supposed to be a more natural way to represent a LINQ expression (although I personally prefer the extension methods). As has already been pointed out, the first example will return an IEnumerable result while the second example will return a List result due to the call to ToList(). If you remove the ToList() call in the second example, they will both return the same result as Where returns an IEnumerable result.

Categories

Resources