4 ms·
One difference with LINQ is its ubiquity. It works with database, in memory data structures, on disk files. You can use your skills/code across all the system.
by blackoil 2y ago
One difference with LINQ is its ubiquity. It works with database, in memory data structures, on disk files. You can use your skills/code across all the system.
- John23832 2y agoIt's just built on top of anything that is Iterable. If a language has first class iterator support, they could do something similar.
- naasking 2y agoMainly first-class functions I think. If you have those, you can just use fold in the core combinators.
- mythz 2y agoTakes a lot more than that, LINQ providers work by accepting a LINQ Expression Syntax tree instead of an opaque function, which allows providers to inspect and traverse the Expression's AST and translate it into the data source it's implementing. This Expression AST is constructed by the compiler, not something that can be tacked on by a library later.
- megadal 2y agoYes, but I think the point is practically every high level language can already do this pretty trivially. If it's scripted you can typically just get a string representation of the function. If it's Java, JAR inspection/dynamics have been a thing for a long time. And in other languages, they usually directly support metaprogramming (like Rust) and plugging code into the compilation logic.
- mythz 2y agoIf it were trivial you'd see LINQ-like providers implemented in "practically every high level language". Source code of the function means you have to implement the parser/lexer to convert it into a usable AST which is bad for both runtime performance and library size. Very much doubt this is available in Java, which Java ORM lets you use native Java language expression syntax to query a database?
- pjmlp 2y agojOOQ would be one such example, https://www.jooq.org/ https://www.jooq.org/ Not that I use this, I am a myBatis person in what concerns database access in Java, and Dapper in .NET for that matter, not a big ORM fan. And case in point most people use LINQ for in-memory datastructures, not the database part.
- mythz 2y agoThis is a custom expression language to work within the expressive limitations of the language: create.select(BOOK.TITLE) .from(BOOK) .where(BOOK.PUBLISHED_IN.eq(2011)) .orderBy(BOOK.TITLE) If Java supported LINQ you'd be able to use a more intuitive and natural Java expression syntax instead: create.from<Book>() .where(x -> x.publishedIn == 2011) .orderBy(x -> x.title) .select(x -> x.title);
- pjmlp 2y agoJava streams are what you're looking for. If you insist in telling LINQ === EF, well that isn't what most folks in .NET use System.Linq for. And back to the ORM thing, jOOQ is one way, there are others, and even if it isn't 1:1 to "from x select whatever" the approach exists.
- mythz 2y ago> If you insist in telling LINQ === EF I don't use EF, nor have I ever mentioned it. You're replying to a thread about what it takes to implement a LINQ provider, which was dismissed as every high level language implements it with iterables, then proceed to give non-equivalent examples.
- recursive 2y agoIQueryable<> manipulation has other tools available to it than brute-force iteration, like streams do. Streams may be the closest thing java has, but it's still a fundamentally different thing.
- 2y ago
- eknkc 2y agoWait what? Am I gonna include a source code parser and AST analyser to my JavaScript library for example, to examine the provided expression source and do this? This reads like the infamous Dropbox comment from when it first got released.
- megadal 2y agoYou could also bundle your JS. Or pretend like any number of other solutions like caching parsed ASTs exist instead of being as obtuse as possible, or something idk
- jayd16 2y agoNot that I agree it's trivial but even if it was, so what? This just feels like sour grapes.
- deleted 2y ago[deleted]
- Pxtl 2y agoHaving used it since its inception, I've come to the conclusion that the SQL translator is kind of a misfeature. It creates so many weird bugs and edge-cases and tedium. I love LINQ, I love having a typesafe ORM as a standard feature of C#, but the convenience of being able to reuse my Pocos and some expressions for both in-memory and in-SQL don't outweigh the downsides. If I were designing SQL/LINQ today, I'd keep the in-memory record classes and in-database record classes distinct and use some kind of codegen/automapping framework for keeping them synched up. Maybe allow predicate operators to return things other than booleans so we could make `a == b` return some kind of expression tree node. For ad-hoc queries using anonymous classes? Support defining an interface inline in a generic so you can say public T MyQuery<interface {string Firstname{get;set;}; string Lastname{get;set:}} T>(); Like, to elaborate, if you were doing some kind of JSON-based codegen (alternately you could do something where you have a separate hand-written POCO Model assembly and use reflection against it to generate your DbModel classes so it's still Code First). Yes, I know MS tried and abandoned this approach, I used LinqToSQL and EF3.5 and whatnot and suffered all that pain. like, your master datatable file would be something like ```json "tables" : [ "persons" : { "dataRecordClass" : "DataRecordsNamespace.DbPerson", "objectClass" : "PocosNamespace.Person" }, "columns : { "PKID" : { "type" = "integer", "isPrimaryKey" = true, "isAutoGenerated" = true, } "firstName" : { "type" : "nvarchar(255)", "allowNull" : true, } "lastName" : { "type" : "nvarchar(255)" "allowNull" : false } } ] ``` which would generates something like ```cs public class DataRecordsNamespace.DbPerson : DbRecord { public DbPerson() { throw ThisIsAFakeClassException(); } public DbInt PKID{ get => throw ThisIsAFakeClassException(); set => throw ThisIsAFakeClassException(); } public DbNVarChar { get => throw ThisIsAFakeClassException(); set => throw ThisIsAFakeClassException(); } } public partial class PocosNamespace.Person { public AutoGenerated<int> PKID{ get; init; } public string FirstName { get; set; } public string LastName { get; set; } } public class MyDbModel : DbModel { public DbTable<DbPerson> Persons => DoSomeLazyStuff(); } public static class MyDbContextExtensions { public static List<Person> Resolve(this DbQuery<DbPerson> dbPersons) { //call code to execute the actual query. } } ``` Am I making sense? Then you wouldn't have the problem of "oops I used an untranslateable method or member of Person", because MyDbModel can't have any of those. You'd lose the ability to to switch from whether a query is in-memory or in-database just by removing the ToList(), but I'd argue that's a misfeature, and better-handled by having some kind of InMemory implementation. Like, having DbQuery have a simple `.ToLocalMemory()` function that is a hint that the next part should be done locally instead of in the database would be a better way to do that. Then you could still do ```cs List<Person> myPersons = connection.MyDbModel .Persons .DoSomeInDatabaseQueryStuff() .ToLocalMemory() .DoSomeLocalMemoryStuffToOffloadItFromDatabase() .Resolve() .DoSomeDotNetStuff() .ToList(); ``` edits: fix some of the HN pseudomarkdown