Here's the code snip I'm trying to get to work.
using System; using System.Collections.Generic; using System.Text; using System.Query; using System.Xml.XLinq; using System.Data.DLinq; using nwind; namespace linq2 { public class Product { public int ProductID; public double UnitPrice; } class Program { static void Main(string[] args) { Northwind db = new Northwind("Data Source=(local);Initial Catalog=Northwind;Integrated Security=True"); List<Product> plist = new List<Product>(); IEnumerable<Product> query = from p in db.Products select new Product { ProductID = (int)p.ProductID, UnitPrice = (double)p.UnitPrice }; foreach(Product p in query) plist.Add((Product)p); Console.WriteLine("There are {0} items plist", plist.Count); } } } |
When run, this is the error returned:
Unhandled Exception: System.ArgumentException: GenericArguments[0], 'System.Int3 2', on 'System.Data.DLinq.SqlClient.MethodCallReader`1[T]' violates the constrai nt of type 'T'. at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, Type ty peContext, MethodInfo methodContext, Type[] genericArguments, Type[] genericPara mters) |

Adding query results to a List, can it be done?
lzeca
If you read the exception, you'll see it's saying that there's a problem with using System.Int32 in the reader. It hasn't even reached the IEnumerable bit. In fact, you got an exception, which means all this compiled, which means, at least, that query does in fact implement IEnumerable<Product>.
I can't verify whether it'll solve your problem, but a couple observations:
* ditch the explicit casts -- you almost certainly do not need them. Let the system do its job and avoid micromanaging the code until absolutely necessary. Without having run your code, I think it's the explicit casts which are throwing it off.
* bite the bullet and declare query using var. You won't lose strong typing. It'll adapt as your query changes. It'll also be correct.
* try plist.AddRange(query).
Overall -- and I'm generalizing here -- it looks like you need to sit down some more and have a long talk with the new APIs available in List (there are A LOT), as well as work through some misconceptions about where you need to make casts. I think you'll be happier for it.
James Hicks
Have you considered a type name conflict between elements contained in db.Products, and the Product class you have defined Try removing or renaming your Product class.
snatch
Gaspar Nagy
I renamed the Product class and used different named members and still I get the "argument type's do not match" message.
Back to the debugger I go go.
I found it easier to use the class defined by sqlmetal as a List type and extract the fields I needed from that like this, but I find I learn things easier when I do them my way.
List<Products> plist = new List<Products>();
var query = from p in db.Products orderby p.ProductID select p;
At first, through timings, I found that ..AddRange was taking twice as long to process than a .Add in a foreach loop until I reversed the two and found .Add take the same time as the inital Addrange. After the first .AddRange or .Add, even clearing the list and adding all of the values back in takes half the time the initial load did so /cheers local caching.
prof.gabi
Unhandled Exception: System.ArgumentException: Argument types do not match
at System.Expressions.Expression.Bind(MemberInfo member, Expression expr) in
c:\PdcBuild\query\System.Query\expression.cs:line 106
at System.Expressions.Expression.Bind(RuntimeFieldHandle fieldHandle, Express
ion expr) in c:\PdcBuild\query\System.Query\expression.cs:line 117
at linq2.Program.Main(String[] args) in d:\Vsp\C#\LINQ\linq2\linq2\Program.cs
:line 29
Line 29 being
select new Product { ProductID = p.ProductID, SupplierID = p.SupplierID };
Explicity casting them as both ints (as they are in the sql table) at least gets me past that part. SQL shows both of those fields to be int's. Even the generated nwind code declares "private int _ProductID;" yet without an explicit cast, this fails.
Using the .addrange worked quite well. The query works but, it will not work "on it's own" without the casts, go figure.
I dont know whats considered "correct" following the use of 'var' and using my own IEnumerable type as even at the PDC there were developers showing both methods and reading msdn blog posts I see MS's own programmers using both methods.
And given the time, I hope I get more free time to sit down and learn more about 2.0's features. It's why I'm posting here after all.
Shajed Zaman
Try just "select p"
Regarding "var": at compile-time, "var" is replaced with whatever the variable initializer comes out to, type-wise. Consider it a place-holder that says: "specifying the actual type isn't important, or it's pretty complex to type -- just make the type correct based on the assignment". This is different from using variant, or object, which says "it's impossible to say ahead of time what type this variable needs to contain".
This is perfect for Linq, since the query's type can change based on using Linq, DLinq, XLinq, or whatever sort of fooLinq people come up with in the future. All you, as a developer, need do is type "var foo = ...", and you're set.
Gallo_Teo
Remember: the variable "query" is just a description of the query you want to perform -- you're not actually going to the database until the data is *first* accessed in the enumerator.
This may appear to be the reverse of what you're used to, but you can consider (at least for DLinq) that the analogue from ADO.NET is to create the connection, create a command, instantiate a reader, then loop over the reader. In this case, you're creating a structure (stored in query) which describes the command, then DLinq does the actual command creation and reader instantiation for you when you ask for the Enumerator.
A similar thing goes on for Linq in general -- you're constructing an Enumerator in both cases -- but for Linq it's not interpreting some description (expression tree) of a description (sql) of a query operation (fetch the rows).
If you want to time Add, foreach, AddRange, etc, then pull all the data *first* to get the database call taken care of. Calling plist.GetEnumerator() should do it, I think.
beyonddc
Poking around more I found I can just as easily use
List<Products> plist = query.ToList();
I'll keep experimenting as to why I need to type those values even though they are equal to the types that sqlmetal created for the nwind database. I'm going to try some queries now against my own SQL databases to see what happens.
Thanks for taking the time to clarify the flow. I finally got the dlinq.doc printed so now I can read it.
KYChen