LINQ select query with Anonymous type and user Defined type
Asked Answered
D

3

17

Anonymous class has read only properties in c#. Which is often used to to declare in linq select query to get particular values from database. In my code I have the following query.The thing that confused me selecting new object of anonymous class using new statement. I had a model class of StudentClerkshipsLogModel . When I Use model name the query result allow editing.

var query = (from entity in _tblStudentClerkshipsLog.GetQueryable()
             where entity.StudentID == intStudentID                             
             select new StudentClerkshipsLogModel
             {
                 StudentClerkshipID = entity.StudentClerkshipID,
                 StudentID = entity.StudentID,
                 ClerkshipID = entity.ClerkshipID,
             }).ToList();

When I did not mention type after new in select statement I am unable to exit. compiler raise an error . enonymous object is read only.

var query = (from entity in _tblStudentClerkshipsLog.GetQueryable()
             where entity.StudentID == intStudentID                             
             select new 
             {
                 StudentClerkshipID = entity.StudentClerkshipID,
                 StudentID = entity.StudentID,
                 ClerkshipID = entity.ClerkshipID,
             }).ToList()

my question is how linq bind the about two query differently . Both queries have dynamic binding or first one is is static.

Thanks

Dependable answered 8/9, 2015 at 6:22 Comment(7)
What do you mean by "I am unable to exit"? What code is the compiler complaining about? (I doubt that it's the code you've shown.) Are you trying to modify the objects later? If so, show the code.Tolley
i want to modify the code later .but i need to know the difference between the select queries so i can choice the better one .Dependable
@JonSkeet: it looks like a typo. "I am unable to edit".Cumming
They're just different. One projects to an anonymous type, the other projects to a named type. If you need to modify the objects later, you definitely can't use an anonymous type, as the properties on anonymous types are read-only. That has nothing to do with LINQ directly...Tolley
@MuhammadNasir: define a criteria for "better".Cumming
The error has nothing to do with the code posted. The error is generated from somewhere else in the code where query is being used. It looks like you are trying to write to the query object. StudentClerkShipsLogModel is a class and the amount of memory the object is using is clearly defined. So it can be edited. The 2nd case you are using an anonymous query where the size of the object are dynamically defined and can vary so they can not be edited.Matteo
@Dennis: Yes, after reading it again that makes sense - but it really doesn't help that the code trying to modify the objects isn't shown...Tolley
C
11

If I understand you correctly, you're wondering, how LINQ provider can set properties of anonymous object, since they are "true" read only properties (there's no any private set, but get only)?

When you call Select extension method for IQueryable<T>, it accepts an expression of type Expression<Func<T, TResult>. If you'll write some stub for Select you can look into the generated expression, using debugger:

public static class MyExtensions
{
    public static void MySelect<T, TResult>(this IQueryable<T> query, Expression<Func<T, TResult>> projection)
    {
        System.Diagnostics.Debug.WriteLine(projection);
    }
}

The difference is in how compiler generates lambda expressions for named types and anonymous types. When you call Select for named type, expression will look like this:

{_ => new Person() {Id = _.Id, Name = _.Name}}

That is, firstly new Person object will be constructed, and then members will be initialized (MemberInit expression).

But when you call Select for anonymous type, expression will be built as constructor call (New expression):

{_ => new <>f__AnonymousType0`2(a = _.Id, b = _.Name)}

LINQ provider compiles these lambdas into delegates, when materializing query results, and ultimately just calls constructor for anonymous type.

Cumming answered 8/9, 2015 at 7:12 Comment(0)
T
18

The error you're getting really doesn't have anything to do with LINQ. You can see the same thing without using LINQ at all:

var anonymous = new { Name = "Fred" };
anonymous.Name = "Joe"; // Error, as properties of anonymous types are read-only

So if you want to modify the objects fetched by your LINQ query, you shouldn't use anonymous types. But both LINQ queries are statically bound - anonymous types are still fully known at compile-time, and the compiler applies normal type restrictions to them. For example:

var anonymous = new { Name = "Fred" };
Console.WriteLine(anonymous.Foo); // Error: no property Foo
int bar = anonymous.Name; // Error: no conversion from string to int
Tolley answered 8/9, 2015 at 6:39 Comment(1)
i know this but the thing i want to know how linq treat then because the queries working are completely different. i had mention in question that anonymous object are read onlyDependable
C
11

If I understand you correctly, you're wondering, how LINQ provider can set properties of anonymous object, since they are "true" read only properties (there's no any private set, but get only)?

When you call Select extension method for IQueryable<T>, it accepts an expression of type Expression<Func<T, TResult>. If you'll write some stub for Select you can look into the generated expression, using debugger:

public static class MyExtensions
{
    public static void MySelect<T, TResult>(this IQueryable<T> query, Expression<Func<T, TResult>> projection)
    {
        System.Diagnostics.Debug.WriteLine(projection);
    }
}

The difference is in how compiler generates lambda expressions for named types and anonymous types. When you call Select for named type, expression will look like this:

{_ => new Person() {Id = _.Id, Name = _.Name}}

That is, firstly new Person object will be constructed, and then members will be initialized (MemberInit expression).

But when you call Select for anonymous type, expression will be built as constructor call (New expression):

{_ => new <>f__AnonymousType0`2(a = _.Id, b = _.Name)}

LINQ provider compiles these lambdas into delegates, when materializing query results, and ultimately just calls constructor for anonymous type.

Cumming answered 8/9, 2015 at 7:12 Comment(0)
D
2

I Found following difference in with anonymous type result of a LINQ result.

  1. Result is not edit able e.g. if we assign value to a gridview it will be read only.

  2. Problem with scope of an anonymous object.we can't pass the type to another method. define a parameter of type var; var must always be followed by an initialization expression.

If you need result only in current context for read only purpose use anonymous query . If you need result in other function the you have to define type of object. the object type after new will be created with properties you want to get from result define then in curly braces {} . It is not necessary to initialize all value of model class.

Dependable answered 8/9, 2015 at 7:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.