views:

155

answers:

3

Hi all,

It seems Linq2sql doesn't know how to construct the TSQL while you transform linq2sql object into domain object with constructors. Such as:

from c in db.Companies
select new Company (c.ID, c.Name, c.Location).Where(x => x.Name =="Roy");

But when using settable attributes, it will be OK.

from c in db.Companies
select new Company { ID = c.ID, Name = c.Name, Location = c.Location }.Where(x => x.Name =="Roy");

I don't want to allow those attributes to be settable. How can I achieve this? And can anybody provide food for thought on how linq 2 sql is translated into TSQL? Thanks in advance!

A: 

The first query is incorrect because the from statement will return a collection of company entities. To get only 1 company you would need to change the first statement to:

Company c = (from c in db.Companies where c.ID = someId select c).First();

The second statement does the where statement implicitly.

I suggest you run SQL Profiler while executing the second query to see what is actually being used as TSQL statement.

Colin
But the first query works.
Roy
You stated Linq2Sql did't know how to translate to TSQL for the first query?
Colin
Colin, I don't see that Roy is asking for the query to return anything other than a collection. The two statements he posted, he's saying, should be equivalent (and I agree), but they are not. In general, new Company (someID, someName, someLocation) should work interchangeably with new Company { ID = someID, Name = someName, Location = someLoc }.
JoshJordan
That is to say, both of those queries return a collection of Company objects, as they should.
JoshJordan
Ok, see it now to, was looking at this during a sleepless long night, my bad...
Colin
+1  A: 

It's probably to do with the way L2S parses the expressions - it can parse the object initialiser expression, but not the constructor expression. Basically, the way L2S works is to parse the linq expressions the way any LINQ provider does and then convert the result into SQL.

You could achieve what you'd like by converting it into an IEnumerable first, as then you'll be free to use LINQ to Objects. In the example you gave this is trivial, but let's generalise to a case with a more complex where clause:

var companyData =
    from c in db.Companies
    where c.Name.StartsWith("Roy")
    select new { c.ID, c.Name, c.Location };

var companies =
    from c in companyData.AsEnumerable()
    select new Company(c.ID, c.Name, c.Location);
Michael Hart
Yeah, thanks. But I think there will be a performance hit when using linq2objects. Does ADO Entify Framework have such a problem?
Roy
Not sure why you think there'll be a performance hit? Objects take literally a few microseconds to instantiate. Be careful not to fall into the trap of premature optimisation here.
Michael Hart
In my application, I want to take the advantage of IQueryable. I mean, filter the result out after the call of GetAllProducts(). For example: GetAllProducts().SingleOrDefault(x => x.Name =="Microsoft"); If I use Linq2objects, each call will cause all the objects to be constructed. Doesn't this to be a performance hit while we have more than 10, 000 products?
Roy
IMO you can get all sorts of nasty surprises trying to pass L2S IQueryables around beyond your data layer boundary, because the SQL query is only executed when you start to enumerate, which may happen in another layer. This is probably a matter of personal preference, but I always prefer to return IEnumerables from the data layer (ie, from a Repository if you're using that pattern). You can still pass arbitrary criteria in to be executed. But after the query has been executed, you're free to do with it what you want.
Michael Hart
A: 

It cannot translate a query involving a constructor, because it doesn't know what said constructor is supposed to do. It has field mappings for properties, but your constructor could do absolutely anything - why should it try to second-guess that?

It's not clear what the purpose of making the properties read-only would be for L2S entity classes anyway - it is trivially circumvented by deleting the object and re-creating a new one with the same primary key but new property values.

Pavel Minaev
Thanks, I'm not forcing l2s entity's attribute to be read only. I'm forcing the Domain objects. I want to use constructor because, I want to encapsluate some logic, like validation logic, in the constructor. But it seems this make any linq technologies unable to translate the query.
Roy