简体   繁体   English

将 Nhibernate Castle.ActiveRecord 迁移到 EFCore HiLo

[英]Migrate Nhibernate Castle.ActiveRecord to EFCore HiLo

We're currently migrating our old OR Mapper to EF Core.我们目前正在将旧的 OR Mapper 迁移到 EF Core。 Till now we used the http://www.castleproject.org/projects/activerecord or mapper with the HiLo algorithm.到目前为止,我们使用的是http://www.castleproject.org/projects/activerecord或带有 HiLo 算法的映射器。 The explanations is: https://github.com/castleproject-deprecated/ActiveRecord/blob/master/docs/primary-key-mapping.md解释是: https://github.com/castleproject-deprecated/ActiveRecord/blob/master/docs/primary-key-mapping.md

Now we want to switch to EF Core and will try to use the same algorithm.现在我们要切换到 EF Core 并尝试使用相同的算法。 But there isn't much explanation how the HiLo algorithm exactly works in Nhibernate/ActiveRecord.但是没有太多解释 HiLo 算法在 Nhibernate/ActiveRecord 中是如何工作的。 And I try to avoid Id collision.我尽量避免 Id 冲突。

As far as I see, the Hi value is configured in a Database: select next_hi from hibernate_unique_key with the value: 746708 I think the maxLow Value is Int16.MaxValue据我所知,Hi 值是在数据库中配置的:来自 hibernate_unique_key 的 select next_hi 的值:746708 我认为 maxLow 值是 Int16.MaxValue

In that case the Sequence for EFCore should be:在这种情况下,EFCore 的序列应该是:

CREATE SEQUENCE [dbo].[DBSequenceHiLo] 
 AS [bigint]
 START WITH (select next_hi from hibernate_unique_key + Int16.MaxValue)
 INCREMENT BY Int16.MaxValue
 MINVALUE -9223372036854775808
 MAXVALUE 9223372036854775807
 CACHE 
GO

How does the ActiveRecord HiLo Algorithm exactly works? ActiveRecord HiLo 算法究竟是如何工作的? What is the Increment by value?什么是增量值? What is the start with value?价值的起点是什么? The migration will take some time, is it possible to run it parallel with the same HiLo algorithm?迁移需要一些时间,是否可以使用相同的 HiLo 算法并行运行它?

As far as I know.我所知道的。 It's not possible to use the exact same algorithm for ActiveRecord and EF Core.不可能对 ActiveRecord 和 EF Core 使用完全相同的算法。 One works with Sequence and the other works with a table.一个与 Sequence 一起工作,另一个与 table 一起工作。 So you can't use both OR Mapper parallel.所以你不能同时使用 OR Mapper。 But you can create a Sequence for EF Core without ID collision, you just can't use ActiveRecord afterwards.但是您可以在没有 ID 冲突的情况下为 EF Core 创建一个序列,之后您就不能使用 ActiveRecord 了。

To get the INCREMENT BY value just start the current app.要获取 INCREMENT BY 值,只需启动当前应用程序。 Create a DB Entry with the App.使用应用程序创建数据库条目。 Stop it.停下来。 Start it again and create a second entry.再次启动它并创建第二个条目。 Because you stopped the app, the Lo/cache is empty and it gets the next hi value.因为您停止了应用程序,所以 Lo/cache 是空的,它会获得下一个 hi 值。 The difference between those two ID's is the "INCREMENT BY" value of Active Record.这两个 ID 之间的差异是 Active Record 的“INCREMENT BY”值。 It was 2^17 in my case.在我的情况下是 2^17。 Default should be 2^15 I think, but I haven't seen any Infos about it.我认为默认应该是 2^15,但我还没有看到任何关于它的信息。

To get a start value I created a SQL script, to get the highest Id of the database.为了获得起始值,我创建了一个 SQL 脚本,以获取数据库的最高 ID。 Here is my script (It works only if your PK is named Id and it only works with sql.)这是我的脚本(仅当您的 PK 被命名为 Id 并且仅适用于 sql 时才有效。)

DECLARE @tables TABLE(tablename nvarchar(max) NOT NULL);
                DECLARE @name nvarchar(max)
                DECLARE @maxid bigint
                DECLARE @currentid bigint
                DECLARE @query nvarchar(max);
                        DECLARE @sSQL nvarchar(500);
                        DECLARE @ParmDefinition nvarchar(500);

                        set @maxid = 0

                insert into @tables
                SELECT TABLE_NAME
                FROM INFORMATION_SCHEMA.TABLES
                WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_CATALOG = 'BB_Vision'

                While(Select Count(*) From @tables) > 0
                Begin

                    Select Top 1 @name = tablename From @tables

                    IF EXISTS(SELECT 1 FROM sys.columns
                                WHERE Name = N'Id'

                                AND Object_ID = Object_ID(@name))

                    BEGIN
                        SELECT @sSQL = N'SELECT @retvalOUT = MAX(ID) FROM ' + @name;  
                        SET @ParmDefinition = N'@retvalOUT bigint OUTPUT';

                        EXEC sp_executesql @sSQL, @ParmDefinition, @retvalOUT=@currentid OUTPUT;

                        IF @currentid > @maxid
                        BEGIN

                            set @maxid = @currentid

                        END
                    END

                    Delete @tables Where @name = tablename
                End

                select @maxid+1

Now you can create your EF Core Sequence.现在您可以创建您的 EF Core 序列。 Here is an explanation how to use it: https://www.talkingdotnet.com/use-hilo-to-generate-keys-with-entity-framework-core/这是如何使用它的解释: https://www.talkingdotnet.com/use-hilo-to-generate-keys-with-entity-framework-core/

After that you shouldn't use ActiveRecord anymore or you have to create your sequence again with a higher start value.之后,您不应再使用 ActiveRecord ,否则您必须再次创建具有更高起始值的序列。

Because the migration takes some time and you will mostly still create some Features/Bugfix for the current OR mapper, it's a good idea to set your ActiveRecord Hi value to a larger value on your local Database.因为迁移需要一些时间,并且您仍然会为当前的 OR 映射器创建一些功能/错误修复,所以最好在本地数据库上将 ActiveRecord Hi 值设置为更大的值。 So you can work with both on the same Database.因此,您可以在同一个数据库上同时使用两者。 But I wouldn't use it in production但我不会在生产中使用它

update hibernate_unique_key set next_hi = next_hi + next_hi

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM