Coming from NodeJS, the amount of stuff that could be added with a single line from an official package was great. No more worrying about hundreds of unvetted dependencies.
Coming from NodeJS, the amount of stuff that could be added with a single line from an official package was great. No more worrying about hundreds of unvetted dependencies.
It allows you to just build things rapidly without worrying much about patterns/naming because once your vague ideas solidify and you realize where you went wrong, it's really easy to just Ctrl+Shift+R and make any codebase-wide adjustments instantly.
It's also great about picking up sub-optimal implementations or patterns with helpful warnings, and you just Ctrl+. to have it auto-fix for you. Using these Rider features combined with Github Copilot, I was able to pretty easily learn intermediate level C# because it's like having a mentor working along side you.
edit: been using Rider on Linux since a few years now
No, it uses Resharper as the backend.
But I use a .editorconfig tuned stylecop and roslynator on all projects so maybe that overrides some defaults.
Mind sharing which Java style rules are you seeing ?
Most of that disk size is supposedly in the toolchain (requiring 2-60GB of disk space alone[1]). Why is this so big? Modern toolchains from other vendors are not this large.
[1] https://learn.microsoft.com/en-us/visualstudio/releases/2022...
It turns out native code for all kinds of OS workloads take some space.
Go see how much GB, Apple or Android development stacks require.
$ pacman -Qi emacs | grep Size
Installed Size : 111,46 MiBSo what exactly does VS save you? Hell, I can’t even imagine what’s inside that.
[0] https://learn.microsoft.com/en-us/windows-server/administrat...
https://learn.microsoft.com/en-us/dotnet/core/install/linux
Also VS Code, an open source IDE with first class support for .NET languages:
It turned me right off C# outside of work. There are plenty of other languages that are better suited for hobby development.
The cynic in me suspects all the drama was directly related to Scott Hanselman suddenly losing interest in bloggin.
I'm not sure why they do not open source the debugger. I suppose it is obvious to some extent that some companies (JetBrains) are able to charge for high quality tooling. Microsoft makes a trickle of money from Visual Studio professional.
Though the objective function and decision variables are somewhat opaque, this is clearly an optimization problem.
We're moving to .Net, and I was surprised by how poor the built-in DB stuff is. It's like either assembly or Python, but nothing in the middle.
That said I've also been impressed about how nice it is to get stuff going. I used C# back in the .Net 1.1 days and yeah massive difference in ergonomics.
Dapper seems to be in the middle and it is pretty popular
Important concepts: .NoTracking and setting the EntityState correctly ( mark as deleted, updated, ... )
Additionally, sometimes it's easier to update things granularly, instead of all at once.
I suppose the annoyance comes from updating in bulk on a POST and trying to map everything?
[1]: https://linq2db.github.io/#update
[2]: https://linq2db.github.io/articles/sql/Join-Operators.htmlRight now EF Core is probably the best ORM that has ever existed. What exactly is missing?
Although for performance you would probably reach for something like Dapper but that is not an ORM.
We're not used to something like EF, perhaps it would work for us. But debugging generated queries due to performance issues is something we'd like to avoid. For now the decision was made to not use EF.
To be honest you should keep all ORM queries fairly simple if you can. Where clauses fine. Inserts, updates, deletes, ORMs save so much code, and so much pain when you add new properties/remove them.
But if a query is more than a few includes or joins you should be handcrafting it with FromSQL() or loading it piecemeal using Load().
And don't even think about using it to make complicated reports, that is not a good idea. Make a stored procedure or view.
And that's especially true if you are using anything other than SQL Server. I've seen abysmal performance myself on MySQL/Maria on moderately complex EF queries. I've not really looked since EF 6, but it used to love making nested selects instead of JOINs, which were fine in SQL Server but terrible performance-wise in MySQL. Postgre I've never used with EF in anger so can't comment.
You can use EF with Hot chocolate to make a GraphQL endpoint really easily, but I'd imagine that's an easy way to saddle yourself with serious performance problems unless you limit the levels it can go. I'd be interested to hear if anyone's using it and how they find it?
Also the lazy-loading and the in-memory provider for tests are both kind of misfeatures.
If you don't want to debug difficult queries, then extend it to use Dapper and use the best of both worlds.
There is one gigantic footgun in EF Core, that is the decision between single query and split query. If you choose single query in the wrong situation you can end up with truly pathological queries. I might blame EF Core here a bit for a dangerous default, but to be honest the other choice would be dangerous in a different way, so there is no obvious good default choice here. This is a part that you need to understand to use this ORM, and fortunately it generates warnings now and kind of forces you to choose the strategy.
The one other aspect that helps to generate good queries with EF Core is to use "Select()" for any case where you want to request fewer columns than available in your tables. I find it quite natural to write queries this way in any case.
The Interpolated family of methods take nice, clean string interpolation like $"Select * from Table where Id = {Id}" and make sure that is properly parametric SQL queries (ie, avoiding things like SQL injection attacks).
It's a killer feature and I have some idea why it lives in the EF side of the house rather than being generally applied across all of ADO.NET, but it should still probably be a more reusable library of its own beyond just EF.
I usually call .SaveChanges() when i % 20 == 0
Works faster than with .Tracking. The SQL script runs in your transaction, so rollback runs as usual.
The i%20==0 condition with .SaveChanges() is used with .Tracking(), yes.
Wish I could agree but they would have to fix the very slow time to first query when using big models (+500 tables in our case). Compiled models is not a solution for us since our model changes a lot and the compilation is just as slow. It's disappointing because it used to work fine under the ancient Linq2SQL library.
Also maybe you might find a benefit from splitting your context into multiples. I am considering this option for one of my code bases
I can't split the model without massive refactorings, and even then, some tables are common across all modules and would need to be duplicated. Your advice is unfortunately the standard answer in my case, I guess EF Core is just not for me, really disappointing but "c'est la vie".
edit: ha you probably mean commit it in source control so other devs can also use it? I guess it's a compromise, would still slow down our DbContext refresh command a lot.
Are you relying on model conventions or spelling out everything in modelBuilder calls?
* Support for "FOR UPDATE" and "SKIP LOCKED"; it's easy enough to tag the queries and modify the SQL in an interceptor though.. Yuck.
* Transaction attributes ala Spring; Though I can make do without them it's nice being able to specify what sorta transaction party a method is interested in.
* Better support for "bulk updates". SQL Alchemy, as rough an onboarding experience as it is, has really good support for executing db-side update logic.
That said, I largely agree with you and nobody should overlook LinqPad. Anyone interested in babysitting the generated SQL should be using it; too bad it's not on Linux :| :( ;(
The optimizations they cover in the docs should all be done by default IMHO; optimizing models, polling db contexts, and etc. I also open and close a db connection at app start which further reduced the first request latency after putting a process in rotation.
Having used it on an actual product and dealing with some of the pain points, it's my go-to since the typescript version (v5) came out.
The ORM uses Knex.js internally, which is very simple to drop into if you just want a query builder. Having Knex be accessible also makes it simple to just write your query in plain sql as well, or as the Lucid ORM has available, just fragments of your query (say the join statement) as raw sql: https://docs.adonisjs.com/reference/database/query-builder#w...
Along with debugging, printing out the sql, and support via the Adonisjs REPL "Ace", it makes for a very nice experience.
Which features would you say are the key ones that make Lucid seem more like a query mapper (Dapper, Knex) than an ORM (ActiveRecord, EF)?
Specifically, in my Adonis projects, I'm mostly working with the Model objects through the ORM methods, and only dropping to Knex/SQL when necessary (complex CTE, etc). Since it's such a Model-centric seeming way of development, it naturally seems like an Object-Relational Mapping to me.
Selecting complex dtos, this isn’t query building. A lot of magic turns this into sql.
TopPaidMayors = Cities
.where(c => c.state.govoner.party ==‘dem’)
.select(c =>
c.name,
highestPaid = c.mayors
.orderByDesc(m => salary)
.take(10))
.orderBy(c => highestPaid.First().salary)It's not all magic as well. Looking into the internals of EF, ActiveRecord, Hibernate, or other ORMs reveal patterns that once familiarized can help reason about the behavior of complex queries. I only state this to try to work against the commonly found wisdom of "big frameworks are magic" that tends to scare away learning developers from hoping to understand them.
There are intersections and disjunctions of feature sets between the various ORMs, with some features for EF still only available via extensions (or nonexistent). I don't think this makes the Lucid ORM any less of an ORM.
Again, I like EF Core. I simply think that as far as node-based ORMs go, that Lucid is the one I've had the best experience with, so wanted to highlight it.
There are a ton of joins and sub-selects in that query. 8 very succinct lines. Can you do anything close in Lucid? I don't think so.
However, you seem set on making this a combative conversation rather than a collaborative discussion, so I'll end my participation here.
Ideally I'd like to supply some selects, fill up some DataTables with master-detail data, manipulate it and commit changes.
But yeah, maybe I gotta check out the latest EF stuff and see if I can't convince the others...
Will def look at it more carefully.
Definitely check it out if you haven't recently!
I prefer next.js for the frontends.
System.Environment.GetEnvironmentVariable("NAME") ?? ...1. appsettings.json
2. appsettings.{env}.json
3. user secrets (only in Development environment)
4. environment variables
5. command line args
You can full customize the setup if you desire, there are packages to support things like external secret stores. If you Google ‘Asp.Net core configuration” there’s a MS page that goes into great detail on all of this.
Anyway, your env vars must match the name as you’d structure it in a json object, but with the periods replace with double underscores. So ConnectionStrings.MyConnection becomes CONNECTIONSTRINGS__MYCONNECTION, FeatureFlags.Product.EnableNewIdFormat becomes FEATUREFLAGS__PRODUCT__ENABLENEWIDFORMAT, etc.
One nitpick: environment vars don't have to be capitalized. You can do ConnectionStrings__MyConnection so the casing matches what you see in appsettings.json.
And a word of warning: make sure to understand how the configuration overrides work. If you have appsettings.json define an array of auth servers with 5 elements, then in appsettings.Production.json (or env variables) define an array of auth servers with only 1, auth servers 2-5 from the default appsettings.json will still be there! (something similar to this may or may not have caused a scare in the past)
I tend to avoid using arrays in config because of the unexpected behavior, and the risk of overriding something you didn't mean to. Anywhere you'd use an array you can usually use an object and bind it to a Dictionary<string, Whatever>, then ignore the keys.
builder.Configuration.AddEnvironmentVariables();
Then you can use an env variable like "Foo__Bar=X" to override Foo.Bar from your appsettings json.
A simple HTTP server? Maybe I'm missing something, but when I needed it I hadn't found one.
I believe, the closest it has is System.Net.HttpListener which is a very different thing from your typical Golang's net/http.Server or python's http.server.HTTPServer.
I believe at some point they had switched from HTTP.sys to Kestrel, so at least it doesn't need the admin privileges anymore. But this whole thing is so much related to ASP.NET it's pretty hard to figure out how to create a simplest HTTP server without anything else forced upon you (no services, no "web applications", no router, just plain and simple bare HTTP protocol handler). So my impression is that maybe .NET can make certain complex things easy, but it has some issues with keeping simple things simple.
Productive devs want the request/response wrapper objects and routing constructs to handler methods to get work done and can still drop down into fine-grained request/response crafting as and when required.
That's exactly what I don't do, and what I want to see available in a standard library.
But I quite frequently implement custom request handling before any routing happens (if there's even any routing). That's super easy to do in Go, Python or Rust, but when I needed something comparable in C# I haven't found any similar composable independent pieces that I can join together in a way I see fit.
https://learn.microsoft.com/en-us/aspnet/core/tutorials/min-...
It’s .NET 101 stuff.
And this stuff is ASP.NET Core, not a bare .NET [Core], isn't it? What I'm talking about is something comparable to just Kestrel, except that I failed to find any documentation on using it "raw" without the whole ASP.NET thing (maybe I misunderstood what it is and it's tightly coupled with the whole framework?).
(This partly reflects the classic HTTP.SYS role in IIS/Windows as well, because Window's HTTP.SYS is surprisingly high level for a "raw" kernel component for hosting web servers. From my understanding, most of "Kestrel" under-the-hood is just a cross-platform semi-recreation of the HTTP.SYS abstraction machine on top of things like but maybe not exactly libuv/ioring. So yes, everything is "naturally" higher level in .NET than Python's lowest level just because it assumes a higher-level "OS server" base.)
Also, yes, the boundary between "Kestrel" and ASP.NET is really hard to define at this point. Almost all of ASP.NET is just "Express-style" (though much of these middleware patterns in ASP.NET I believe predate Express) middleware that is cumulatively stacked on top of each other as you add more high-level ASP.NET features, and at this point all of them are just about optional depending on what you are looking to do.
Even many alternatives to ASP.NET at this point are built on top of the core basics like WebApplicationBuilder, they just diverge at which sets of middleware stack on top of that.
As others point out the recently expanded "Minimal APIs" experience is most tuned for "Flask-like" out-of-the-box behavior: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/m...
That's as low level as it gets in .NET, but not so much because of "strong coupling" but because "everything is middleware" in .NET.
[1] https://learn.microsoft.com/en-us/dotnet/core/extensions/gen...
I don't have any issues with the IHost and builder patterns. I actually like those - although I've only used the very basics, so I don't really know about the intricacies and possible drawbacks.
Thanks for clearing my misunderstanding about the coupling. I really thought Kestrel was something different, have not expected it to be this high level. It being a replacement of HTTP.sys totally makes sense, of course.
I've found and read https://learn.microsoft.com/en-us/aspnet/core/fundamentals/m... and it started to make more sense now.
There's a long issues thread on HttpListener should be more strongly marked deprecated [2] to avoid people accidentally using it despite today's recommendations to use Kestrel/the "Most Core" parts of ASP.NET. One fun part of the thread is an example repo of the absolute most "bare-bones" and "raw" Kestrel bootup possible [3], including a "TODO: implement TLS handshake here" bit.
[1] https://learn.microsoft.com/en-us/dotnet/api/system.net.http...
[2] https://github.com/dotnet/platform-compat/issues/88
[3] https://github.com/davidfowl/BasicKestrel/tree/master/BasicK...
Its not. Keep reading.
Disclaimer: looking from sysadmin's POV.
If for some reason you don’t want the framework to handle things like routing or request/response deserialization/serialization then you can go bare bones and implement everything via custom middleware: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/m...
The only bit of framework-specific / hidden magic debugging I really had to do was the realization of AsSplitQuery() when creating objects composed of independent datasets, AsNoTracking() for a decent perf bump, and single group-by's are fine but when you start nesting them it gets really hairy really quickly -- they usually ended up becoming views.
Otherwise change-tracking worked wonderfully for batch-updating (but everything I did was short-lived) and outside of group-bys, the LINQ -> SQL mapping (and vice-versa) was extremely predictable, in both EF Core generating the SQL I expected, and creating the correct LINQ from the SQL I knew I wanted.
9/10 would use again; inline sql is for nerds
I don’t know why one would have an issue with not using the features they’re not looking for anyways. Keeping everyone aligned on patterns/usage is half the point of code review, and it was managed there without much trouble (you can’t really do the truly magical incantations without quite a bit of setup)
So much better than spring and NodeJS.
Internal error handling was sometimes abysmal too, a misconfiguration of certain dependencies in `AppModule` could leave the application in a broken state on startup where it wouldn't bind to its port and no error messages were printed to console. On a few occasions I had to spend an hour or more reading and understanding NestJS source code to resolve those issues, which could have been avoided if they had better internal validation and error logging in place.
That's not to say it was all terrible, some aspects of it were genuinely good, but the overall experience and many hours of needless pain it caused left a really bad taste in my mouth. Back then, at least, it felt like a Lego set where the pieces didn't all quite fit together.
Depressingly enough, it seemed like NestJS was the best that Node.js world had to offer which made me quit the ecosystem altogether.