andrewlock / StronglyTypedId

A Rosyln-powered generator for strongly-typed IDs
MIT License
1.52k stars 80 forks source link

EF Value Generator for int and long backed Id's #78

Open kazeshini178 opened 2 years ago

kazeshini178 commented 2 years ago

This could be useful for identity columns in SQL databases. Not sure if this should potentially be treated as its own generator, currently just extended the templates for the EF Int and Long converters.

Sample usage when configuring EF Tables

 modelBuilder
        .Entity<Entity>(builder =>
        {
            builder
                .Property(x => x.Id)
                .HasConversion(new EntityId.EfCoreValueConverter())
                .HasValueGenerator<EntityId.EfCoreValueGenerator>()
                .ValueGeneratedOnAdd();
        });
andrewlock commented 2 years ago

I like the idea behind this, but the implementation is a bit problematic, I think. Currently, it has race conditions as it's not thread safe. It also won't work in a server farm scenario (one of the reasons I'm not a fan of sequential IDs!).🤔

However, I'm not sure exactly how this is supposed to work? I'm a bit torn how to proceed, this would be very useful for e.g. the Guid IDs, but I'm not sure if it really works for the int/long versions?

Rudde commented 2 years ago

Status on this? Or is it abandoned?

kazeshini178 commented 2 years ago

Hi @Rudde sorry no haven't abandon this from my end. Just had a few busy weekends :D

Currently, it has race conditions as it's not thread safe. It also won't work in a server farm scenario (one of the reasons I'm not a fan of sequential IDs!).🤔

Been doing a bit more research into EF, seems it should be thread safe as long as each thread uses it own DbContext though for the cases where a singleton context is used for multiple threads we could use:

 System.Threading.Interlocked.Increment(ref _id);

Implement would then be similar to the internal EF Value generator which might be better. Internal Long Generator

For the case of server farms, not sure if there would be an issue as the Generator only generates temporary values. The SQL Server is responsible for the final generated value, this value would be used by EF to know which entity it should assign the "real" ID back too.

However, I'm not sure exactly how this is supposed to work? I'm a bit torn how to proceed, this would be very useful for e.g. the Guid IDs, but I'm not sure if it really works for the int/long versions?

For int/long it helps prevent the an issue where inserting multiple entity all have an internal value of 0. From some the project been working on with StronglyTypedId as well as this issue #59 I came across.

Happy to add one for Guid as well, think the only difference would be that it wouldn't generate a temp value like the int/long ones.

Though for Guid I found public EntityId Id { get; set; } = EntityId.New(); works pretty well for Guid types, but this would give people options 😄

Hope this help @andrewlock

Rudde commented 2 years ago

Won't this still have a race condition if you run several API instances? Isn't it it best to let the database increment the value, like it does on regular ints, or isn't this possible to configure? I understand it probably will be slightly different for each underlying sql driver supported

kazeshini178 commented 2 years ago

This would still let SQL increment/generate the int/long ID's. This would just allow for EF to track which entity should get which ID in the case that multiple entities are added at once.