Jukka Snellman

16 Followers
15 Following
58 Posts
Software developer (.NET/React/TypeScript). Chaotic / Neutral. Don't take my opinions too seriously, except maybe software related. I mostly post in English.
Websitehttps://jukka.snellman.online
Most of my time programming #csharp I've been switching between two main IDEs: Microsoft Visual Studio (2026) and Jetbrains Rider. Rider is good for decompiling and debugging framework code, but very slow. My Core i9 13900H / 32GB RAM laptop wasn't powerful enough for Rider, I had to switch to desktop. Visual Studio is fast, but debugging framework code doesn't always work. So even in 2026, both are needed.

As an update, I made sample project for those "generic strong IDs": https://github.com/jukkahyv/dotnet-entity-id

That includes Roslyn code generator for global usings (global using OrderId = Id<Order>). I've been using those for a while now, and it works.

GitHub - jukkahyv/dotnet-entity-id: Sample for strongly typed entity ID value types for .NET

Sample for strongly typed entity ID value types for .NET - jukkahyv/dotnet-entity-id

GitHub
I had a rather heated debate whether or not #OData is a good idea for REST API. I'm comparing it to LINQ/IQueryable for ORM. As I understand it, IQueryable for ORM is a controversial topic. It's very powerful, but also fragile and unreliable, because LINQ doesn't always translate well to SQL. OData is basically IQueryable for REST, and to use it efficiently, it needs to go all the way to SQL. So now you have tight dependency between REST API and SQL. Powerful, but very very scary.
So #GitHub actions has environments and environment variables. It took me too long to figure out that variables configured for an environment are not environment variables - they are configuration variables.
@agehrke I'm a bit surprised there are no libraries for this generic approach, though. The way I see it, it scales better. The downside is less customization per ID type. So I guess the difference is, do you have a large number of homogenous ID types, or smaller number with some differences.

@agehrke

Thanks for the suggestion though. I think, maybe I can use their source generator as an inspiration. Really, everything else is easy, just adding the type aliases is a pain, and it has to be done for every project.

I should mention that the system has hundreds of entity types, that's why the code per type has to be minimized, and it's also making heavy use of generics.

@agehrke

Also, the good thing about the generic approach is that I actually don't need to repeat equality or JsonConverters. They all work with Id<T>. It seems StronglyTypedId solves a different use case, where you somehow want Ids to be different (some are string, some are int, some are convertible to JSON), but I don't need that: all IDs have the same features and same backing type.

@t4rzsan

Yeah I know. I tried that too. Problem is, when you start having lots of generic code, then you definitely want at least interface UserId: Id<T>. But even then, I found I end up in trouble when type is sometimes UserId, sometimes Id<User>, but I'd want those to be the same! For example, I have method Add<T>(T param) which puts "param" into some generic list. Is it List<UserId> or List<Id<User>>?

@agehrke

In my use case, it's important that the types are alises to generic type, so UserId = Id<User>. I don't want type like UserId, which is what this library seems to be doing? Also, I would like to generate that alias automatically based on User type. I don't want to define UserId anywhere. Based on that blog post, I couldn't see how I can do those. Is it possible?

With the new #dotnet project I've gone all in with value types, even using custom type for entity IDs.

record struct Id<T>(long Value)

It's better for type safety (can't mix IDs of different entities) and also for type inference.

If only #csharp had proper type aliases, so I could define UserId = Id<User>! global using helps, but it's still only project-specific. I want to write code generator that generates those global usings.