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!
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);
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.
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.
Related
I'm new to working with nHibernate and have inherited a project which has implemented it for accessing its database. So far I've been able to write additional single-table query methods using QueryOvery<>, but I'm finding the logic behind table joins perplexing.
I want to implement the following T-SQL query:
SELECT DISTINCT f.FILE_ID, f.COMPANY_ID, f.FILE_META_ID, (etc...)
FROM AUDIT.FILE_INSTANCE f
INNER JOIN AUDIT.FILE_INSTANCE_REPORTING_PERIOD p ON p.FILE_ID = f.FILE_ID
WHERE p.REPORTING_PERIOD_ID BETWEEN 20150101 AND 20151304
AND FILE_STATUS != 'CANCELLED';
In this example, the reporting period ids would be parameters. Please note that they are integers, not dates, and the DISTINCT clause is important. How should I proceed?
I do not know your classes but if i would have written it, it would look like this:
var results = session.QueryOver<FileInstance>()
.Where(fi => fi.Status == FileStatus.Canceled)
.JoinQueryOver(fi => fi.ReportingPeriods)
.WhereRestrictionOn(period => period.Id).Between(20150101, 20151304)
.Transform(Transformers.DistinctRootEntity)
.List();
I have a system that uses tags to categorize content similar to the way Stack Overflow does. I am trying to generate a list of the most recently used tags using LINQ to SQL.
(from x in cm.ContentTags
join t in cm.Tags on x.TagID equals t.TagID
orderby x.ContentItem.Date descending select t)
.Distinct(p => p.TagID) // <-- Ideally I'd be able to do this
The Tags table has a many to many relationship with the ContentItems table. ContentTags joins them, each tuple having a reference to the Tag and ContentItem.
I can't just use distinct because it compares on Tablename.* rather than Tablename.PrimaryKey, and I can't implement an IEqualityComparer since that doesn't translate to SQL, and I don't want to pull potential millions of records from the DB with .ToList(). So, what should I do?
You could write your own query provider, that supports such an overloaded distinct operator. It's not cheap, but it would probably be worthwhile, particularly if you could make it's query generation composable. That would enable a lot of customizations.
Otherwise you could create a stored proc or a view.
Use a subselect:
var result = from t in cm.Tags
where(
from x in cm.ContentTags
where x.TagID == t.TagID
).Contains(t.TagID)
select t;
This will mean only distinct records are returned form cm.Tags, only problem is you will need to find some way to order result
Use:
.GroupBy(x => x.TagID)
And then extract the data in:
Select(x => x.First().Example)
I'm trying to create a LINQ provider. I'm using the guide LINQ: Building an IQueryable provider series, and I have added the code up to LINQ: Building an IQueryable Provider - Part IV.
I am getting a feel of how it is working and the idea behind it. Now I'm stuck on a problem, which isn't a code problem but more about the understanding.
I'm firing off this statement:
QueryProvider provider = new DbQueryProvider();
Query<Customer> customers = new Query<Customer>(provider);
int i = 3;
var newLinqCustomer = customers.Select(c => new { c.Id, c.Name}).Where(p => p.Id == 2 | p.Id == i).ToList();
Somehow the code, or expression, knows that the Where comes before the Select. But how and where?
There is no way in the code that sorts the expression, in fact the ToString() in debug mode, shows that the Select comes before the Where.
I was trying to make the code fail. Normal I did the Where first and then the Select.
So how does the expression sort this? I have not done any change to the code in the guide.
The expressions are "interpreted", "translated" or "executed" in the order you write them - so the Where does not come before the Select
If you execute:
var newLinqCustomer = customers.Select(c => new { c.Id, c.Name})
.Where(p => p.Id == 2 | p.Id == i).ToList();
Then the Where is executed on the IEnumerable or IQueryable of the anonymous type.
If you execute:
var newLinqCustomer = customers.Where(p => p.Id == 2 | p.Id == i)
.Select(c => new { c.Id, c.Name}).ToList();
Then the Where is executed on the IEnumerable or IQueryable of the customer type.
The only thing I can think of is that maybe you're seeing some generated SQL where the SELECT and WHERE have been reordered? In which case I'd guess that there's an optimisation step somewhere in the (e.g.) LINQ to SQL provider that takes SELECT Id, Name FROM (SELECT Id, Name FROM Customer WHERE Id=2 || Id=#i) and converts it to SELECT Id, Name FROM Customer WHERE Id=2 || Id=#i - but this must be a provider specific optimisation.
No, in the general case (such as LINQ to Objects) the select will be executed before the where statement. Think of it is a pipeline, your first step is a transformation, the second a filter. Not the other way round, as it would be the case if you wrote Where...Select.
Now, a LINQ Provider has the freedom to walk the expression tree and optimize it as it sees fit. Be aware that you may not change the semantics of the expression though. This means that a smart LINQ to SQL provider would try to pull as many where clauses it can into the SQL query to reduce the amount of data travelling over the network. However, keep the example from Stuart in mind: Not all query providers are clever, partly because ruling out side effects from query reordering is not as easy as it seems.
Given that I have three tables (Customer, Orders, and OrderLines) in a Linq To Sql model where
Customer -- One to Many -> Orders -- One to Many -> OrderLines
When I use
var customer = Customers.First();
var manyWay = from o in customer.CustomerOrders
from l in o.OrderLines
select l;
I see one query getting the customer, that makes sense. Then I see a query for the customer's orders and then a single query for each order getting the order lines, rather than joining the two. Total of n + 1 queries (not counting getting customer)
But if I use
var tableWay = from o in Orders
from l in OrderLines
where o.Customer == customer
&& l.Order == o
select l;
Then instead of seeing a single query for each order getting the order lines, I see a single query joining the two tables. Total of 1 query (not counting getting customer)
I would prefer to use the first Linq query as it seems more readable to me, but why isn't L2S joining the tables as I would expect in the first query? Using LINQPad I see that the second query is being compiled into a SelectMany, though I see no alteration to the first query, not sure if that's a indicator to some problem in my query.
I think the key here is
customer.CustomerOrders
Thats an EntitySet, not an IQueryable, so your first query doesn't translate directly into a SQL query. Instead, it is interpreted as many queries, one for each Order.
That's my guess, anyway.
How about this:
Customers.First().CustomerOrders.SelectMany(item => item.OrderLines)
I am not 100% sure. But my guess is because you are traversing down the relationship that is how the query is built up, compared to the second solution where you are actually joining two sets by a value.
So after Francisco's answer and experimenting with LINQPad I have come up with a decent workaround.
var lines = from c in Customers
where c == customer
from o in c.CustomerOrders
from l in o.OrderLines
select l;
This forces the EntitySet into an Expression which the provider then turns into the appropriate query. The first two lines are the key, by querying the IQueryable and then putting the EntitySet in the SelectMany it becomes an expression. This works for the other operators as well, Where, Select, etc.
Try this query:
IQueryable<OrderLine> query =
from c in myDataContext.customers.Take(1)
from o in c.CustomerOrders
from l in o.OrderLines
select l;
You can go to the CustomerOrders property definition and see how the property acts when it used with an actual instance. When the property is used in a query expression, the behavior is up to the query provider - the property code is usually not run in that case.
See also this answer, which demonstrates a method that behaves differently in a query expression, than if it is actually called.
I have a very simple set-up. Table "Node" has a nullable foreign key "ObjectId." This is represented in my database model with a one-to-many association. Now, I want to run a query that gives me all Node-Objects with a particular object id. In straight SQL, this is very easy:
SELECT Node.*, Object.*
FROM Node INNER JOIN Object
ON Node.ObjectId = Object.ObjectId
WHERE Node.ObjectId = #objectId
But now I want to do the same thing in LINQ to SQL:
private static Func<MyDataContext, string, IQueryable<DataNode>> _queryGet =
CompiledQuery.Compile(
(MyDataContext context, string objectId) =>
(from node in context.DataNodes
where node.ObjectId == objectId
select node));
var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<DataNode>(node => node.DataObject);
context.LoadOptions = loadOptions;
DataNode node = _queryGet.Invoke(context, objectId).FirstOrDefault();
...
The frustrating thing is that LINQ always generates a LEFT OUTER JOIN for this query and nothing I've tried makes difference.
On the face of it, this seems to make sense. The ObjectId foreign key is nullable, so some nodes won't have an associated object. But in my query, I'm supplying an object id. I'm not interested in nodes without an associated object.
In this case, an INNER JOIN is the right thing to do, but how do I convince LINQ?
I think you are just going to have to let it be a left outer join. I imagine when the expression tree is being transformed to SQL, the join and the equality predicate are considered seperate parts of the resultant query. In other words, the LEFT OUTER JOIN is just there because of the fact that you are joining on a nullable foreign key, and the equality part is written in afterwards (so to speak).
Does it really matter that it's not translating how you want it? The fact that you don't always get the most efficient query possible is kind of an accepted tradeoff when you use LINQ to SQL. Most of the time the queries are pretty efficient if you aren't doing anything crazy, and if you really think it's going to impact performance or something, you can always write a stored procedure LINQ to SQL can use.
loadOptions.LoadWith<DataNode>(node => node.DataObject);
You misunderstand the purpose of this statement. It does not filter the result in any way. It does not get translated into sql that can filter the result in any way. INNER JOIN will filter the result set, and LEFT JOIN won't, so LEFT JOIN is the correct choice.
If you want to filter the nodes, you should use a query that includes your filter criteria:
from node in context.DataNodes
where node.ObjectId == objectId
where node.DataObject != null
select node
Consider the difference between our queries when objectId is null (the query translator does not inspect objectId's value).
I did eventually find a good solution to this. The answer is to simply get LINQ to SQL out of the way. Like so:
using (MyDataContext context = CreateDataContext())
{
// Set the load options for the query (these tell LINQ that the
// DataNode object will have an associated DataObject object just
// as before).
context.LoadOptions = StaticLoadOptions;
// Run a plain old SQL query on our context. LINQ will use the
// results to populate the node object (including its DataObject
// property, thanks to the load options).
DataNode node = context.ExecuteQuery<DataNode>(
"SELECT * FROM Node INNER JOIN Object " +
"ON Node.ObjectId = Object.ObjectId " +
"WHERE ObjectId = #p0",
objectId).FirstOrDefault();
//...
}
Seems very complicated for what I think you want.
I would force the joins like this:
from n in context.Nodes join o in context.Objects on n.ObjectId
equals o.Object_id select n