by to11mtm | 2025-09-02 20:31:33+00:00
> EF Core, while missing lots of features still (glad that left joins are actually coming as first-class lol) is still miles ahead of ORMs in just about any ecosystem (coming from someone who often prefers raw sql).

If you often prefer raw SQL, give linq2db a try. [0]

It's not a full blown ORM like EF Core, rather it's a LINQ->SQL DSL with a lot of nice features. Left joins have been first class for years (Heck there's also a -very- explicit .Join method that takes an enum for the join type!), same with Bulk Update (EF only got that in v7 or v8 IIRC) and it's bulk insert is stupidly fast.

Oh and it has CTE support (including recursive!) built in. Built in InsertOrUpdate support that lets you give different expressions for insert vs update (including passing the existing item into the update expression so you can do things like increment a counter or append to a string) [1]. Oh it's also got MERGE support if you know it's sane to use for your case... (I'm not a fan of MERGE)

Also I kinda like the extension syntax better, if you want to give a method call in LINQ a specific SQL translation, it's just 1 or more attributes on the method itself. [2] EF Core seems to need more ceremony for this last I checked.

Akka.NET is using it for their SQL persistence plugins now, since it's 'direct' enough and unlike dapper there is minimal need to maintain DB specific queries/code.

FWIW you can also use it 'on top of' EF Core via it's shim package, i.e. it can work alongside EF Core with your existing models/code but when you need to do something 'fancy' switch to it (And the ceremony is just one line per DbContext in your DI.) It's been really helpful at my current shop when we have nasty^nasty queries that EF Core just plain gives up on translating.

Apologies for gushing, it's my favorite library and it's been game changer at every shop I've been at.

> Quantity is not quality, but often times when I hit a path in dotnet that doesn't seem written about much (other than perhaps a outdated project on GitHub), I'll see "I wonder how folks are doing this in java or node" where I'll find much more modern and lively discussion on topics.

But hey if you need an EF Core ASP.NET WebAPI tutorial you are spoiled for choice!

Yeah it's a challenge to find prior examples of things in .NET and historically you'll often be told 'not to' without a luck or a 'good reason'. It's caused some stagnation (see prior tongue-in-cheek comment) as far as innovation however there's lots of interesting stuff out there. If you find the right circles you will be able to glean lots of good knowledge but it takes more sleuthing.

On the plus side, LLMs seem to be pretty good at 'translating' concepts from other languages into C#, I've been surprised at what Copilot can spit out even with obscure libraries so long as you have an even half-decent instruction prompt.

> Microsoft itself does an excellent job of communicating about the projects they're focused on (example: aspire), but they haven't built the same type of community that can support other amazing, but under recognized libraries that they don't have the time to shine the spotlight on (TPL dataflow, etc).

So much cool stuff! Like the Critter stack (Marten/Wolverine, AFAIK they actually use TPL as their base for things!), The aforementioned Akka.NET project (I may be biased but IMO Akka Streams has way more batteries included than Orleans Streams and even TPL), also, anything Cysharp puts out (They are a game development shop that does .NET, very slick purpose-specific libraries, also since they target Unity most of their stuff can target FW if you need it to.)

[0] - https://github.com/linq2db/linq2db

[1] - Will admit that I only really trust this in Postgres and SQLite, as those have specific syntax and don't reach for MERGE, but if those are your targets it is handy!

[2] - I say 1 or more because if you are targeting multiple DB languages and the SQL needed is different for each, you'll need to have attributes for each snowflake case. But if whatever you're doing works on all DBs or you only care about one DB language, you just need one.