Why LINQ beats SQL
linqpad.net
linqpad.net
If you're stuck using a database version that first came out a decade ago, you've got bigger problems than legacy syntax for pagination.
> Not only is this complicated and messy, but it violates the DRY principle (Don't Repeat Yourself). Here's same query in LINQ. The gain in simplicity is clear: var thirdPage = query.Skip(20).Take(10);
If you're using OFFSET / LIMIT to do paging then you're doing it wrong. See here for the real way to handle paging for large result sets: http://use-the-index-luke.com/blog/2013-07/pagination-done-t...
DB2 LUW has also decent row-values support: http://use-the-index-luke.com/blog/2014-11/seven-surprising-...
Need to update the slides...
Even more controversial... I don't want to make it any easier for developers to interact with the database unless it is absolutely correct and transparent. I know.. I know... how could I say such I thing! But you see I want every interaction with the our data repository... our precious data repository... that is usually the bottleneck... I want you to know WTF you are doing when you touch it.
We (my company and probably others) are past the days of monolithic rapid prototype apps with ORMs. Now you pick a database and you learn the hell out of it because you can stick to it. Back in the day one of the reasons ORMs were so popular because companies would have to ship on premise ware that would have to work with multiple databases. With the cloud that is no longer the case. However I still think a lot of .NET shops come from the on premise mentality. Thus performance is less of concern (speed of release is more desired).
I do like the syntax also though.
The happy medium is a flexible ORM that automates the repetitive stuff but let's you call out to the higher level stuff...because if you don't have that your developers are going to end up building their own awful ORM-ish layer to automate the repetitive stuff anyway.
In Java there are host of libraries that do this. I have even used Hibernate to do the mapping at times as I do think it does a pretty good job of that.
What I mean by mapping is minimal code generation (either host language or SQL) of Class <-> Entity and Row result <-> Object.
I think jOOQ approaches that medium you talk about fairly well btw. JDBI and MyBatis are also fairly good as well (both mapping technologies).
I don't think it's conceptually right to regard LINQ as a "SQL generator". I think it's better to think of both LINQ and SQL as just different database control languages.
(It might be the case that behind the scenes LINQ is implemented by generating SQL, but that's an implementation detail. Just like Haskell is implemented by generating C behind the scenes but it's more reasonable to think of Haskell as its own separate programming language than as a "C generator")
I don't agree with this at all. SQL does not abstract a specific execution plan. The execution plan is calculated by the RDBMS to efficiently compile the results required by a given SQL statement. The plan depends on available indexes, table statistics, input parameters and so on. The execution plan might change from time to time as new indexes are built or as table statistics change. When you write an SQL statement, you are defining what you want and how the tables are related in your context. You are NOT telling the RDBMS what the actual execution plan should look like.
C is an abstraction over machine language, in the same way; but so is Prolog.
SQL does not map any specific execution plan. The execution plan will be very different depending on external factors such as the contents of the tables and so on. Have you looked at some actual execution plans?
Related rhetorical question for you: What is the difference between a 3rd generation and a 4th generation programming language? (SQL is a 4th GL and C is a 3rd GL)
This is totally not true unless you have optimizations turned off. Have you ever looked at what clang or gcc generates with -O2 or -O3 ?
Anyway, regardless of whether you agree with me on this point, I don't see how it relates to the general point I'm making. This seems like it's just disagreement over the definition of the word "abstraction". It doesn't change (and in fact, actually supports!) my main point, which was that SQL is not properly regarded as "native" to database engines in some special way that can't be true of LINQ or any other language.
This is just plain wrong and you are missing important details of how LINQ and SQL and RDBMSes work in the real world.
The LINQ interpreter on the client would have to retrieve the statistics from the server's tables and indexes of interest and perform the same operation as the optimizer (costing more network and some db cpu). Next it would have to send back the plan to the db executor in some way. This plan "marshalling" would cause more network traffic, requiring the executor to "unmarshall" the plan costing more CPU. This is less efficient than the current scheme.
Alternatively the LINQ language could be implemented on the database but with its own inherent difficulties, but in reverse.
Once a plan is cached and is reused, this inefficiency goes away to some degree. So there could be a possible mechanism for the server to send back to LINQ client a hash identifying the plan if it is cached and then have LINQ only send the hash with parameters to the DB on next execution. (You would have to see if this isn't covered by some patent of course!)
The constraint is the network connection. If the network connection between client and server were faster and bigger than the data bus on the computers, then it would change the equation significantly. But longer distances means slower communication all things being equal (lightspeed and all). So a network connection being better than the data bus would be inefficient and quickly remedied in a competitive marketplace.
In short - LINQ runs on the client machine, the execution plan happens on the database server.
Think of it this way: Lets say you have a database of clients and contacts. Lots of systems in your company connects to this database to access this data. Each of those systems will submit SQL in the form of 'select clientname from clients where id = 123' or whatever. Now lets say the client list grows and the old execution plan is not optimal any more. Our smart RDBMS can just dynamically fix the execution plan and performance goes up for every system accessing the database. If the RDBMS instead received a rigid execution plan, EVERY client system will need to recalculate the execution plan.
Also: lets say your client app connects to several different database servers. What's a good exection plan on one server it not going to be a good execution plan on another server, so LINQ would need to keep a list of database servers with table statistics, indexes, etc etc and continually monitor all of those for changes. It's massive duplication of work. It's much more efficient to have each database server look after its own execution plans.
On the topic of concept-rightness you quickly veer into a language game. gcc transforms c code into machine code (and may also output error messages, warnings and such). For some, this is not important, and may not be conceptually right. But if you are interested in say the ABI for instance, you do care.
On the point of "fundamentalness of abstraction", I interpret it as a measure of how many layers of abstraction (Ab) can be decomposed into the concrete thing of interest. LINQ generates another layer, that of SQL. If it generated an execution plan and sent that to the database optimizer, then I would say it does not generate another layer and would be equal in level of Ab to SQL.
But if LINQ can generate SQL that runs on the database, then it is also possible for the database to support LINQ natively. And maybe that was the original intent.
However, as it stands today LINQ to SQL costs CPU resources. So in adopting LINQ one of the tradeoffs you are adopting is CPU resources for developer use/benefit of LINQ.
Perhaps 20 years ago, perhaps more. Optimizing compilers have gone long way.
Compiling an execution plan is a significantly easier task than actually guessing how exactly an optimizing compiler would schedule the code, down to assembly. (and cheating w/ hints in SQL- [looking at Oracle]just reinforces that.)
Which is the exact same thing you do when you write a LINQ query against a database context...
Both are just languages that describe what you want to achieve, not how to achieve it.
> I don't think it's conceptually right to regard LINQ as a "SQL generator". I think it's better to think of both LINQ and SQL as just different database control languages.
Thats the thing. There is nothing theoretical about this. It is about what is actually closer to the real thing which in this case is the data.
I agree LINQ is far easier to understand and is more productive but those benefit just don't outweigh my performance, safety, and concurrency concerns. Understanding the database along with its native SQL gets you that.
For others the productivity is worth it.
> (It might be the case that behind the scenes LINQ is implemented by generating SQL, but that's an implementation detail. Just like Haskell is implemented by generating C behind the scenes but it's more reasonable to think of Haskell as its own separate programming language than as a "C generator")
Doesn't GHC backend compile directly to assembly?
Why is SQL closer to the data?
> Understanding the database along with its native SQL gets you that.
My whole point is that SQL is not any more "native" than LINQ. The database takes SQL and computes an execution plan in its own internal representation. This can look totally different from the SQL as the other commentator pointed out. SQL does not in any way correspond to the "native" way the data is stored or how query results are computed.
> Doesn't GHC backend compile directly to assembly?
Maybe now but at some point it generated C.
Yes please point a reference to me to a database that speaks LINQ or how LINQ directly generates to an execution plan (I admit I haven't touched MS SQL Server in some time).
In theory you are right but not in reality. To give another analog you still have to know Javascript to know TypeScript or Coffeescript (or whatever else in vogue) because WASM isn't a reality yet.
Any tool that can map to that query tree has the same level of abstraction as SQL.
Repeat after me, SQL is nothing special. Its semantics are extremely limited. Nothing it does can't really be done by LINQ or a similar DSL that maps to relational algebra operators.
This is completely wrong. SQL is a declarative language, it tells database what to do, not how to do it (aka query plan).
I didn't say SQL is a way of writing query execution plans but it seems some people are interpreting my post that way.
1. Compile time checking. I hate when I'm writing a straight SQL query in a string literal and misspell one of the column names, because everything will compile and unit tests will pass, and the mistake isn't caught until I run integration tests. I want a short edit-compile-debug cycle. jOOQ is a good example of something that helps here.
2. Arbitrary filters. Often I have to expose a REST API where the user can add an arbitrary number of filters to their query. You can't write SQL literals for these because there's a combinatorial explosion of possibilities. So you wind up dynamically generating SQL yourself by concatenating strings in the WHERE clause, hoping and praying you don't accidentally allow SQL injection. I want an ORM to deal with that shit for me.
List<Condition> conditions = new ArrayList<>();
if (notNull(lessThan)) {
conditions.add(MY_TABLE.MY_COLUMN.lt(lessThan));
}
if (notNull(greaterThan)) {
conditions.add(MY_TABLE.MY_COLUMN.gt(greaterThan));
}
if (notEmpty(name)) {
conditions.add(MY_TABLE.NAME.eq(name));
}
dslContext.selectFrom(MY_TABLE).where(conditions).fetch();
(This is obviously really contrived but I hope it illustrates the ideas)We use constructions like this with jOOQ relatively frequently, especially for cases where we offer all sorts of arbitrary filter knobs (useful for internal tools especially).
In general, you can do some pretty fancy manipulation with `Condition` in jOOQ, like you can build a list of conditions and then call `DSL.or(conditionList)` to OR them all together. Stuff like that.
Source: use jOOQ in production code -- been very pleased so far, other than sometimes poor documentation
var query = from c in db.MyTable
where lessThan == null ? true : c.MyColumn < lessThan
where greaterThan == null ? true : c.MyColumn > greaterThan
where name == null ? true : c.Name == name
select c;
Although IQueryable supports your approach also: var query = db.MyTable;
if (lessThan != null)
query = query.Where(c => c.MyColumn < lessThan);
if (greaterThan != null)
query = query.Where(c => c.MyColumn > greaterThan);
if (!String.IsNullOrEmpty(name))
query = query.Where(c => c.Name == name);
var results = query.ToList();Thanks for your feedback. We're currently collecting API that is not documented well enough yet. Your feedback would be very welcome: https://github.com/jOOQ/jOOQ/issues/5816
Lukas
Vlad Mihalcea, a Hibernate developer/evangelist, has been doing amazing work improving the project's documentation and providing educational material about how to use it properly without sacrificing performance[1]. I can't recommend his book High-Performance Java Persistence enough: https://leanpub.com/high-performance-java-persistence
For me, his key lesson is that ORMs can be incredibly useful if, and only if, your understanding of SQL and DB performance is good enough that you can use them in a DB-friendly way. It's really simple things like expressing relationships between your domain entities such that the resulting tables can be easily joined. You still get the productivity that comes from skipping loads of JDBC boilerplate, but you don't feel like there's a load of magic between you and the DB.
He also pushes the idea that you should use Hibernate in combination with other DB tools: Liquibase/Flyway for migrations, and JOOQ for optimised queries with lots of joins,or DB-specific work. By having a decent ORM, SQL builder, and migration tool, you can use be flexible depending on the situation. Complex, performance-insensitive business logic can use the domain model from the ORM, whereas API-backing queries can be expressed a single, tightly constrained JOOQ call, and the actual creation and maintenance of the schema can be done via pure SQL scripts that are managed by your migration tool.
Personally I like creating an API of stored procedures. Make users that can _only_ execute those sprocs with zero dynamic SQL in them. Users can only do what you tell them they can do via your sproc API.
Why don't you hire a DBA and have all major queries go through them if it's that important instead of asking developers to master yet another thing because you got burned in the past?
I'm all for learning database stuff, but you and everyone else are pulling developers in all different directions by simultaneously claiming "YOU NEED TO KNOW THIS SHIT" about <THING THAT HURT YOU PREVIOUSLY>.
If you can't afford a DBA when DB performance is critical to your application, you probably don't have good QA for all of those platforms either. But suddenly your developer is supposed to stretch over all three areas?
When people talk about hilariously long laundry lists of technical requirements, it's an aggregation of demands like these over time that has inflated those requirements.
The thing is that soft wall is wayyyy too vague for anyone to prepare themselves before actually joining a team. I may not want to join your team if you require everyone to be a database expert because I don't like databases. But because the communication around this is so damned vague, there's no way to know before joining.
If you somehow have a SQL-oblivious developer, he should be identified early on because it's not compatible with the level of competence you've established for your business.
Why is this guy suddenly writing performance-critical queries for your webapp and not working with his strengths?
Does he have any strengths? No? Why was he hired? Shouldn't someone be reviewing this guy's code?
The SQL-oblivious developer is a perfectly natural occurrence from a time past when front and back end job postings were not wrapped into a full stack developer position for less pay than those positions combined. It's just that it's so easy to pile on requirements that it just outpaces some people.
Can we identify those people reliably? Yes? Congrats, you've probably got a way to actually test developer competence without invoking another 300-post threadnought on HN and you will likely be very, very rich.
But see, you can't go off studying every single thing mentioned in the context of "Things important for developers to know" even if you wanted to try and keep up. There have been tons and tons of blog posts and articles and angry posts about terrible situations created due to a lack of knowledge and everyone just says "Hey, you should know this, get to it". Even if I wanted to filter through all of those posts, how do I know who to listen to?
Great DBA's are rare, but vastly more important than most people think.
So something like a DBA, i.e. an expert in your software's database, will emerge naturally over time on a product. In my current project, there are definitely some areas that I am the "go to" guy on, and likewise there are other people on my team that are the "go to" people for other areas. And yes, we even have two people who are especially knowledgeable about our backing datastore, and the library we use to interact with it.
Do the LINQ examples, especially the more complex ones, result in the same or better execution plans? Maybe they do, but the article doesn't tell, and without it it's kind of inappropriate to make judgments or even recommendations.
- Prototype and use Linq first ( faster to develop and good enough queries in production)
- Static Typed LINQ reduces mistakes ( a domain object changes, an error appears in your code), definatly later on the road when changing the domain.
- Iterate and improve when i goes slow. Try to keep LINQ, but off course, SQL is faster.
For example, if you want the top N items ordered by f(x), and LINQ doesn't know how to map f(x) to a SQL Server built-in, it has to pull the entire set over the wire, and find the top N client-side. Obviously, if your table is huge, performance won't be good.
That can even affect more than performance. For example, SQL Server orders GUIDs differently than .NET, and SQL Server's decimal isn't quite a IEEE float (https://msdn.microsoft.com/en-us/library/bb738633(v=vs.110)....)
If it actually only ends up creating some complex sql behind the scenes to get those ten rows, how horribly convoluted did it become and wouldn't it be better to write a straight SQL query to do the same thing, even if it's a little more complicated than the pseudo code? I guess I prefer more control. If my SQL query turns out to be slow, then I can learn from that and fix it. If the generated query from LINQ is slow, I have no recourse over it.
That would be a silly thing to do. LINQ is made to be lazy. At worst it would pull the first thirty rows, twenty in Skip and ten in Take.
(Apparently, while LIMIT n,k is MySQL-only, MySQL, PostgreSQL and sqlite all support LIMIT k OFFSET n. So I assume this blog post is only really relevant for people who live in a Microsoft ecosystem?)
It's a pretty bizarre situation.
SELECT * FROM items
ORDER BY key
OFFSET 100 ROWS
FETCH NEXT 10 ROWS ONLY
(https://technet.microsoft.com/en-us/library/gg699618(v=sql.1...) select * from data where data.indexed_column > last_seen order by data.indexed_column desc limit 100Not a good start. SQL is still in widespread use 43 years later because of how good it is. It's not a legacy weighing us down. Rather it has consistently proven its usefulness over and over again. Some of the constructs can feel awkward to be sure. But part of our impression of awkwardness is really just due to SQL's declarative nature, which makes the structure of queries look a lot different than the procedural languages we spend most of our time in.
But it's not clear to me from this article that LINQ is even anything different that what already exists in most every modern application platform. It provides a cleaner syntax for some subset of common query patterns. Okay. There's a ton of SQL generators out there. Is LINQ doing something _else_ for us? This article doesn't say. I don't know, and I didn't learn that from this article.
If you use C# or VB to write apps against relational databases, then by all means, use this to write your SQL. But don't pretend the SQL isn't there or isn't important. LINQ just places you one more potentially leaky abstraction away from your dataset.
I'm rather dubious of this claim. This is kind of like claiming the reason we use Javascript is because of how good it is. The awkwardness of SQL is not because it is declarative, otherwise LINQ would have the same awkwardness because it is also declarative. I think the real reason SQL is because database vendors have not made an effort to add support for other languages.
It's a language that can barely express subqueries and query aliases.
Every ORM has shorthand syntax for expressing filters and order by statements that's way better than the SQL equivalents.
It's barely composable. Do you want to build a query dynamically based on a set of conditions. Tough luck, use a query builder that's prettier anyway.
Its syntax is not amenable to autocompletion. Join syntax is ugly on the eyes and hard to indent.
Seriously, let's kill the love for SQL. I'd rather read queries written in EF Codd's original relational algebra syntax (https://en.wikipedia.org/wiki/Relational_algebra) rather than embedding the abortion that is SQL in my code.
SQL's a pretty grim language, but it's the only language the database understands as a first-class citizen. Until someone designs a new foundation (like WebASM is doing), the rest is just syntactic sugar.
SQL is an ugly COBOLesque veneer over an elegant relational calculus core.
But the "new foundation" you speak of already exists, and has for decades. Competing query languages based on relational calculus are less ugly – QUEL, D, etc.
Sadly, those better looking query languages have failed in the marketplace–ugly SQL won.
Perhaps these options exist and I've just never encountered them? It's surprising that what I most often seem to encounter in casual discussion is this sophie's choice dichotomy between using SQL directly versus an ORM.
It was clear then that QUEL was better in a number of ways.
Sadly, many IT professionals lack the intuition on this.
SQL is a highly sophisticated language since many years. Having done insane amounts of data prepping and validation for analytics, I will attest to this.
However, if I am writing software in .NET, I would trade away SQL for LINQ any day of the week. (Preferrably by means of some sort of intuitive DAL.)
map/filter/reduce are just basic functional programming elements.
This allows you to compose linq expressions without computing intermediate results.
Streams bear a pretty strong resemblance to translated LINQ.
I would like to see C#'s LINQ get an update. It seems to have been left to rot since Eric Meijer left the team. It doesn't even support the new values tuples where it's been fitted to every other part of the language:
from (x,y) in Some((1,2)) // (x,y) will error
select x + y;
The from x in y, let x = y, where x, select x, and, join x in y on a equals b, could and should be extended. Even better would be to allow custom operators like F#'s computation expressions. dogs
.Select(d => d.Id)
.Where(d => d.Age > 3)
.Skip(4)
.Take(2)
would be considered just as much "linq" by most c# devs even though this isn't the query language integrated - simply because it's the same exact thing as the regular linq code.I too find the "real" linq form mostly distracting.
Most of it boils down to plain old functional map/fold/filter/zip constructs under different names.
Honestly, if you've seen what LINQ compiles to, it looks an awful lot like a Java 8 Stream.
Using Wikipedia's example of LINQ translation (https://en.wikipedia.org/wiki/Language_Integrated_Query#Lang...):
Written LINQ is:
var results = from c in SomeCollection
where c.SomeProperty < 10
select new {c.SomeProperty, c.OtherProperty};
It compiles to: var results =
SomeCollection
.Where(c => c.SomeProperty < 10)
.Select(c => new {c.SomeProperty, c.OtherProperty});
And in Java 8: Stream<> results = someCollection.stream()
.filter(c -> c.getSomeProperty() < 10)
.map(c -> new AbstractMap.SimpleEntry<>(c.getSomeProperty(), c.getOtherProperty()));
(of course, iterating over them is different; you just use a for loop in C#, but in Java you have to either use .forEach() or .collect() to a collection and then for over that)I think Streams have more LINQ in them than most people think.
Disclaimer: it's been about a year since I've written Java 8, and this is off the top of my head (and the last time I used it, my employer's codebase had a class for pairs that was better than just SimpleEntry), so the code could be wrong.
Edit: and just for completeness... the same in Python generator expressions:
results = ((c.some_property, c.other_property)
for c in some_collection
if c.some_property < 10)
Not very LINQ-like, but it serves the same purpose.It's just more readable, and turns it into an object pipeline/functional programming style instead. The Java 8 streams were pretty much directly taken from LINQ and given their traditional functional names.
That was my point. I was disagreeing with olmo's suggestion that Java "systematically ignored" LINQ.
What's your source for this claim? Because anecdotally I don't see that at all.
Most uses of where/order/select in C# I'm pretty sure is linq to objects, not sql. I very rarely see the linq proper form in any C# code neither in OSS or in my dat job.
Closest thing we have to real data, but it's been my experience in OSS and in professional life.
I also don't use LINQ to SQL at all. It's all on in-memory stuff. I pretty much never write code like this:
var result = new List<string>();
foreach (var item in input)
{
result.Add(item.Value);
}
return result;
instead, using LINQ: return items.Select(x => x.Value);
The real power comes when you start mixing conditions: return items
.Where(x => IsValidKey(x.Key))
.Select(x => x.Value);
Or doing quick checks: if (items.Any(x => x == null || x.SomeValue == null))
throw new InvalidArgumentException(nameof(items));if(items.Any(x => x?.SomeValue == null))
var results = from a in x
from b in y
from c in z
select a * b * c;
Is very much more attractive than: var results = x.SelectMany(a => y.SelectMany(b => z.Select(c => a * b * c)));
If you use LINQ for more than just SQL queries (for monadic types like Option, Either, etc.) then these types of expression are commonplace. I'd certainly rather use C#'s LINQ grammar over its fluent API.The LINQ to SQL stuff annoys me, because while it works, it's a painful disaster to implement yourself against your own data stores. Believe me, I've tried.
The headlines may as well read: "Why [interpreted language] beats assembly".
Yet somehow, dirty, ugly, hard-to-write SQL is still here while ORMs keep coming and going. And I have yet to see one without an escape hatch allowing raw SQL.
I don't know where you've been looking, but from what I've seen it's an easy to find feature. To give two examples:
My point being that ORMs can't fully replace SQL, and the proof is they all provide an escape hatch.
I have 30k lines of business logic written for Django that does not use that hatch even once.
LINQ to SQL and Entity Framework are examples of ORMs that use the LINQ features
The article says to avoid using Linq for bulk inserts, but for years I've been using an extension method to translate Linq to a bulk insert and it works fine. I forget where I found it.
public static class DataContextExtension
{
public static void BulkInsertAll<T>(this DataContext dc, IEnumerable<T> entities)
{
using (var conn = new SqlConnection(dc.Connection.ConnectionString))
{
conn.Open();
Type t = typeof(T);
var tableAttribute = (TableAttribute)t.GetCustomAttributes(
typeof(TableAttribute), false).Single();
var bulkCopy = new SqlBulkCopy(conn)
{
BulkCopyTimeout = 1200,
DestinationTableName = tableAttribute.Name
};
var properties = t.GetProperties().Where(EventTypeFilter).ToArray();
var table = new DataTable();
foreach (var property in properties)
{
Type propertyType = property.PropertyType;
if (propertyType.IsGenericType &&
propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
propertyType = Nullable.GetUnderlyingType(propertyType);
}
table.Columns.Add(new DataColumn(property.Name, propertyType));
}
foreach (var entity in entities)
{
table.Rows.Add(
properties.Select(
property => property.GetValue(entity, null) ?? DBNull.Value
).ToArray());
}
bulkCopy.WriteToServer(table);
}
}
private static bool EventTypeFilter(System.Reflection.PropertyInfo p)
{
var attribute = Attribute.GetCustomAttribute(p,
typeof(AssociationAttribute)) as AssociationAttribute;
if (attribute == null) return true;
if (attribute.IsForeignKey == false) return true;
return false;
}
}I convert all objects that i import to a big SQL Query.
Something like
First query: UPDATE table SET active=0;
Second ( big ) query: UPDATE table SET properties=values IF ROWCOUNT =0 INSER INTO table(properties)VALUES(values)
I just design the IQueryable with if's, switches, ... and when i need to execute it. I use .ToList()
The IQueryable is then translated to SQL and executed it.
Now i design most of my pages through 1 service/method with a lot of if's and else and re-use that method all the time
For example, a ecommerce-site i made has one function for querying the products, paging, searching, sorting by X, ...). Although, it get's rather complex lately, i wouldn't have it any other way. ( with complex, i mean i now also grouping them by category and category code, a category order number, a product order number, by product title ( varying by the current language), ...
And yes, it' seperated in my service layer ;) and no, i won't change it because this is the fastest way untill now.
Alternatively, you could use Extensions on IQueryable and IOrderedQueryable. Then you do something like db.Products.FilterBySearchTerm(searchTerm).OrderAllBy(sortPropertyName);
But i like ProductHelper.GetProducts(filterWithSettings,SortOnSettings,GroupBySettings); more, mostly because it's easier when i need to customize all the methods because of some "sudden" Change Request that changes all the internal workings :(
Also, if you are new to Linq To Sql. Don't forget DbFunctions / SqlFunctions for built-in SQL Functionality ( depending the EF version you are using). Eg. The LIKE operator has been added in the new EF.
Also, you can always using DataContext.Database.Sql() for using standard SQL.
=====
Pro Tip: DbContext is already a Repository Pattern if you are using DDD !
=====
PS. If you don't know LINQ. It generates a long SQL query and it's a bit slow, BUT it's very productive in development . Here's an example with both Generated SQL (commented between /* */ ) and Linq in one of my subbmitted issues on EF : https://github.com/NicoJuicy/EF-ContainsAndStartsWith/blob/m...
I like LINQ: Develop fast and improve when something executes slow :)
As said before, change to pure SQL WHEN something goes too slow. You don't have to change everything. It will bite you in the * later ;)
Gotta love static typed :)
* In pretty much every project I've ever worked on, there's a small, un-standardised set of database functions I rely on. I need to parse strings and dates, round to the start or end of the month or week, group and categorise values in order to build a dimension table. I've never found a SQL generator that can provide this, although I believe SQLAlchemy Core folks are working on it.
* Planners are still not so good that you can ignore them altogether. I often rely on EXPLAIN to see why things are taking seconds instead of milliseconds, and I often end up looking for ways to trick the planner. If I'm using a SQL generator, I'm now trying to trick both the planner and the generator, neither of which I have direct control over.
* If you're building a lot of complicated queries, setting up indexes and views, and so on, it's hard to get past the advantages of an IDE. Currently, the best tools are pretty much all database specific. Even just being able to quickly see your data in a tabular format is huge.
I haven't used entity framework or any newer tech beyond LINQ to SQL but I'd have to believe such a trivial feature is present in them.
Otherwise we're potentially fetching the customer data N times per customer (depending on the average number of high value purchases)
I guess the TL;DR would be something like: "For constrained but not atypical data models (no N:M relationships, foreign keys explicit in the schema, etc), it's possible to have a more concise syntax than SQL, with less impedance mismatch."
But even that underwhelming statement is generous.
In the 1980s, the object database claim to fame was less impedance mismatch, and ODI's "coding by deletion", but at least ODBs coupled that with claims to superior performance for network data models.
Maybe it's just the grandiose title "LINQ beats SQL" that's so annoying. Simpler syntax would certainly be welcome for the relatively rare cases of humans generating SQL (I think most SQL is machine generated these days)... but only with a host of etceteris parabis conditions, prominently including performance.
Or maybe it was the look you have when you are SURE that someone is telling you an elaborate joke and suddenly realize that no punch line is coming.
LINQ: I'm looking at YOU :-/
That said, I tend to prefer to use the collection extension methods, over the LINQ syntax, which make more sense in my mind.
Same will be said of LINQ in a decade. Whereas SQL will still be there.
Of course, if you don't know what you're doing, you can write some monstrous Linq queries that will be dog slow and exhibit all the worst n+1 behavior, pretty easily.
For LINQ to other languages: Swift Java Kotlin Clojure Dart Elixir
And if that's the case, then of course it is easier and looks nicer than SQL -- that's kind of the point of an ORM.
But I could show you a whole bunch of articles about Python and Ruby and Go ORMs too.
Seems like an Apples to Oranges comparison.
https://msdn.microsoft.com/en-us/library/system.data.linq.da...
Doesn't that make it an ORM?
* LINQ is a set of language features and libraries that help enable better ORMs, among other things
* LINQ to SQL and Entity Framework are examples of ORMs that use the LINQ features
For example, that's Sequel querying DSL: http://sequel.jeremyevans.net/rdoc/files/doc/querying_rdoc.h...
And I think LINQ is "language integrated" because C#, like Java, has poor DSL building possibilities. So they're added ORM-specific syntax right into language.
It's gotten slightly better over the years but compared to an ORM with less abstraction like Hibernate it's still dog slow. Every MS project I've worked on was mostly LINQ...then a folder called "dirty SQL" for the heavy stuff.
I'm not sure if it's due to the highly abstracted nature or just not making performance a priority but in my experience sane Hibernate queries are about 1/2 the speed of native SQL and LINQ is closer to 1/50.
I hope and pray they can make the performance at least within an order of magnitude of raw SQL or even Hibernate so I can say goodbye to SQL forever.
You can always use DataContext.Database.SQL(query) ofc
that's pretty much our MO :) . Never used Dapper, how reliable is it? I ask because we use StackExchanges' Redis client for C# and it mysteriously crashes even after untold hours of debugging
Performance tuning LINQ is a science that I think escapes far too many people. Often it seemed to simply be mistakes that they wouldn't make in hand-written SQL, but they were writing LINQ too much like C# instead of enough like SQL.