65.9K
CodeProject 正在变化。 阅读更多。
Home

如何将 DevExpress XAF SecuritySystemUser 迁移到 PermissionPolicyUser

starIconstarIconstarIconstarIconstarIcon

5.00/5 (7投票s)

2016 年 11 月 8 日

CPOL

5分钟阅读

viewsIcon

19599

关于如何将现有的 XAF 安全系统迁移到新的权限策略的说明。

引言

我花了一些时间将现有的 XAF 安全系统迁移到新的、改进了很多的策略权限系统,我想与大家分享我的经验和代码,以供其他可能决定进行此项艰巨任务的人参考。

我的应用程序仍在开发中,并且大量使用安全系统,这就是我决定转向改进的安全系统的原因。
由于这些脚本(希望如此)会把你的数据库搞得天翻地覆,我强烈建议你不要在生产环境运行它们,但如果你确实必须这样做 - 那么我说一句显而易见的 - 确保你有备份。多个备份。最好是在不同的介质上,在不同的地方,最好是在不同的洲。
另外,所有脚本都是 Microsoft SQL Server 特有的,所以如果你使用的是其他数据库,你需要修改所有元数据查询。

话不多说,我们开始吧。

使用代码

所有代码都可以使用现有的 XAF 更新机制来实现

  • UpdateDatabaseBeforeUpdateSchema - 这会在 XAF 尝试将类更改推送到数据库之前执行;以及
  • UpdateDatabaseAfterUpdateSchema - 这会在 XAF 完成类更改推送后执行,届时我们可以进行额外的后更新任务。

我需要处理两种不同的列,它们将提供一个很好的例子,供你参考类似的场景。

  1. 在我应用程序的初始版本中,我创建了一个通用的父类,该类具有连接到 SecuritySystemUserUserCreated UserModified uniqueidentifier 属性。我决定将这些属性更改为 nvarchar 类型,并保留用户名。
  2. 我想要保留并迁移到 PermissionPolicyUser 的用户属性(例如 - Employee.SystemUser 列)。

整个过程可分为以下几个步骤:

  1. UpdateDatabaseBeforeUpdateSchema 中,将所有 uniqueidentifier 列更改为 nvarchar 类型,并用用户名更新新列。
  2. 此外,重命名所有现有列(及其外键和索引),这将允许 XAF 正确创建与 PermissionPolicyUser 连接的新列。
  3. 允许 XAF 做它自己的事情。
  4. UpdateDatabaseAfterUpdateSchema 中 - 将用户、角色和权限从旧表复制到新表。
  5. 最后运行脚本,将新列更新为之前的数据,并删除旧列/关系/索引。

我将所有脚本封装在存储过程中,这样可以更轻松、更安全地从 XAF 调用(而不是多条 SQL 语句)。此外,每个存储过程都保存为一个单独的文件,并作为嵌入资源添加到我的非特定模块中,以便我在 XAF 更新过程中可以访问它们。

第一步 - 准备脚本并在 UpdateDatabaseBeforeUpdateSchema 中执行它们。

以下代码将加载嵌入的脚本。

if (CurrentDBVersion < new Version("3.5.3.105"))
{
    // This updates XAF splash screen
    UpdateStatus("InitSecurity", "Migrate users", "This action could take several minutes ...");

    batchSql = Func.GetSqlScript(this.GetType(), "Link.Module.DatabaseUpdate.Script.{0}.sql", "sp_sys_ConvertUsersToString", "");

    foreach (string sql in Func.GetNonQueryFromBatch(batchSql))
    {
        if (!string.IsNullOrWhiteSpace(sql)) ExecuteNonQueryCommand(sql, false);
    }

    using (var conn = DB.DBCommon.NewMSSqlConnection)
    {
        conn.Open();

        using (SqlCommand cmd = new SqlCommand(@"EXEC dbo.sp_sys_ConvertUsersToString", conn))
        {
            cmd.CommandTimeout = 0;
            cmd.ExecuteNonQuery();
        }

        conn.Close();
    }
}

我们使用了辅助函数 GetSqlScript (用于加载嵌入的资源脚本)和 GetNonQueryFromBatch (用于解析 GO 语句之间的各个块),因此它们如下所示:

public static string GetSqlScript(Type type, string ns, string scriptName, string version)
{
    Assembly _assembly = type.Assembly;
    StreamReader _textStreamReader;
    string text = "";
    try
    {
        string resourceName = "";
        if (version == "") resourceName = string.Format(ns, scriptName);
        else resourceName = string.Format(ns, version, scriptName);

        if (resourceName != "")
        {
            using (_textStreamReader = new StreamReader(_assembly.GetManifestResourceStream(resourceName)))
            {
                text = _textStreamReader.ReadToEnd();
                _textStreamReader.Close();
            }
        }
    }
    catch
    {
        throw new Exception("Error accessing resources!");
    }

    return text;
}

public static List<string> GetNonQueryFromBatch(string batchSql)
{
    List<string> result = new List<string>();

    string sql = string.Empty;
    batchSql += "\nGO";   // make sure last batch is executed.
    foreach (string line in batchSql.Split(new string[2] { "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries))
    {
        if (line.ToUpperInvariant().Trim() == "GO")
        {
            result.Add(sql);
            sql = string.Empty;
        }
        else
        {
            sql += line + "\n";
        }
    }

    return result;
}

这里是 sp_sys_ConvertUsersToString 存储过程的代码(更多详情请参阅注释)。

ALTER PROCEDURE [dbo].[sp_sys_ConvertUsersToString]
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    BEGIN TRAN T1;

    DECLARE @sql nvarchar(MAX)
    DECLARE @sch nvarchar(50)
    DECLARE @tbl nvarchar(200)
    DECLARE @col nvarchar(200)
    DECLARE @fk nvarchar(200)

    -- I had extra indices in all tables (seemed like a good idea in the time) but I do not need them any more, so I decided to use this chance
    -- and remove them.
    -- This query generates SQL that will drop all indexes with LinkID in it's name
    -- This is not directly related to subject, but if you have some extra work you have been waiting to do - this is a good chance to do it
    select @sql = (
    select 'DROP INDEX ' + o.name + '.' + i.name + char(10) as [text()]
      from sys.indexes i join sys.objects o on  i.object_id=o.object_id
      where i.name LIKE '%LinkID%'
      for xml path('')
    )

    -- PRINT @sql
    EXEC sp_executesql @sql

    -- Following query will locate all columns in all tables which reference SecuritySystemUser table - except columns in those tables which are actually
    -- part of Security System - we do not want to touch those or we might mess everything up
    DECLARE cur_tbl CURSOR FOR
    select
        tab1.name AS [table],
        sch.name AS [schema_name],
        col1.name AS [column],
        obj.name AS FK_NAME
    FROM sys.foreign_key_columns fkc
    INNER JOIN sys.objects obj
        ON obj.object_id = fkc.constraint_object_id
    INNER JOIN sys.tables tab1
        ON tab1.object_id = fkc.parent_object_id
    INNER JOIN sys.schemas sch
        ON tab1.schema_id = sch.schema_id
    INNER JOIN sys.columns col1
        ON col1.column_id = parent_column_id AND col1.object_id = tab1.object_id
    INNER JOIN sys.tables tab2
        ON tab2.object_id = fkc.referenced_object_id
    INNER JOIN sys.columns col2
    ON col2.column_id = referenced_column_id AND col2.object_id = tab2.object_id
    WHERE
        tab2.name = 'SecuritySystemUser'
        and not tab1.name like '%SecuritySystem%'

    -- This is a helper table variable which will hold all related indices
    DECLARE @idxtbl TABLE (
        index_name nvarchar(200),
        index_description nvarchar(200),
        index_keys nvarchar(200)
    )
    DECLARE @sql2 nvarchar(max)

    OPEN cur_tbl
    FETCH NEXT FROM cur_tbl INTO @tbl, @sch, @col, @fk

    WHILE @@FETCH_STATUS = 0
    BEGIN
        -- There are two kinds of columns in my database
        -- First, those that I wanted to turn into nvarchar (to store username) instead of uniqueidentifier (User Oid)
        -- I decided it is more convenient to store user name in the first place
        -- All those columns in my database are called UserCreated and UserModified

        IF @col in ('UserCreated', 'UserModified')
        BEGIN
            -- First I create SQL which will add new nvarchar column with Str sufix (which will temporarly hold username)
            SET @sql = 'ALTER TABLE ' + @sch + '.' + @tbl + ' ADD ' + @col + 'Str nvarchar(100) '
             EXEC sp_executesql @sql
            --PRINT @sql

            -- Next SQL will actually update this new Str column by making a join to SecuritySystemUser
            SET @sql = ' UPDATE q SET q.' + @col + 'Str = u.UserName FROM ' + @sch + '.' + @tbl + ' q INNER JOIN dbo.SecuritySystemUser u on u.Oid = q.' + @col
             EXEC sp_executesql @sql
            --PRINT @sql

            -- Then I drop constraint for uniqueidentifier column
            SET @sql = 'ALTER TABLE ' + @sch + '.' + @tbl + ' DROP CONSTRAINT ' + @fk
             EXEC sp_executesql @sql
            --PRINT @sql

            DELETE FROM @idxtbl

            -- This will load all indices for given table into table variable
            INSERT INTO @idxtbl
            EXEC sys.sp_helpindex @objname = @tbl

            -- After constraint is dropped, I also drop all indices that Oid column might have
            -- I use index_keys property to only filter indices defined for Oid column
            SELECT
                @sql = (
                    select                 
                        ' DROP INDEX ' + @sch + '.' + @tbl + '.' + index_name  + CHAR(10)
                    from @idxtbl
                    where index_keys = @col
                    for xml path('')
                    )

             EXEC sp_executesql @sql
            --PRINT @sql

            -- ThenI drop Oid column
            SET @sql = ' ALTER TABLE ' + @sch + '.' + @tbl + ' DROP COLUMN ' + @col
             EXEC sp_executesql @sql
            --PRINT @sql

            -- And finally I rename Str column to original name of the column
            SET @sql = ' EXEC sp_rename ''' + @sch + '.' + @tbl + '.' + @col + 'Str'', ''' + @col + ''', ''COLUMN'''  
             EXEC sp_executesql @sql
            --PRINT @sql
        END
        ELSE
        BEGIN
            -- Second type of columns are User Oids I actually want to keep and convert to PermissionPolicyUser
            -- But, in order to do that - I have to rename all existing columns, relationship or indicies
            -- I do that because I want XAF to re-create this columns with relationship to PermissionPolicyUser
            -- But I do not want to delete them, because I want to transfer data after XAF does it's job
            -- That is why I rename all columns I want to keep (renaming both relationship and indices are also
            -- required, otherwise XAF will fail to update with error that foreign key or index already exists)
            SET @sql =
                -- This SQL will add Old sufix to column I want to keep
                'EXEC sp_rename ''' + @sch + '.' + @tbl + '.' + @col + ''', ''' + @col + 'Old'', ''COLUMN''; '  + CHAR(10) +
                
                -- This SQL will rename foreign key related to column I want to keep
                ' EXEC sp_rename ''' + @fk + ''',''' + @fk + 'Old'', ''OBJECT'';' + CHAR(10)

            DELETE FROM @idxtbl

            -- Same as in previous case, I load indices for related table
            INSERT INTO @idxtbl
            EXEC sys.sp_helpindex @objname = @tbl

            -- And create SQL to rename all indices connected to column I want to keep
            SELECT
                @sql2 = (
                    select                 
                        ' EXEC sp_rename ''' + @sch + '.' + @tbl + '.' + index_name + ''', ''' + index_name + 'Old'', ''INDEX''; '  + CHAR(10)
                    from @idxtbl
                    where index_keys = @col
                    for xml path('')
                    )

            SET @sql = @sql + @sql2

             EXEC sp_executesql @sql
            --PRINT @sql
        END
        FETCH NEXT FROM cur_tbl INTO @tbl, @sch, @col, @fk
    END

    CLOSE cur_tbl
    DEALLOCATE cur_tbl

    COMMIT TRAN T1
    END
GO

因此,在 UpdateDatabaseBeforeUpdateSchema 中,我们同时更新存储过程并执行它。您可能会注意到我使用的是 ALTER PROCEDURE 而不是 CREATE PROCEDURE
这是因为我在 UpdateDatabaseBeforeUpdateSchema 的开头执行了一个脚本,该脚本会创建任何不存在的具有**空主体**的存储过程、函数和视图。
这使得“依赖地狱”不那么糟糕:-) 并确保每个过程/函数/视图都存在,从而允许我始终使用 ALTER 脚本,而不必太过担心。

这是该脚本的一个片段:

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_sys_ConvertUsersToString]') AND type = N'P')
    EXEC sp_executesql N'CREATE PROCEDURE [dbo].[sp_sys_ConvertUsersToString] AS BEGIN SET NOCOUNT ON END'
GO

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_sys_MigrateUsersToPermissionPolicy]') AND type = N'P')
    EXEC sp_executesql N'CREATE PROCEDURE [dbo].[sp_sys_MigrateUsersToPermissionPolicy] AS BEGIN SET NOCOUNT ON END'
GO

当然,还有其他方法可以做到这一点,但我发现这种方法最方便,并将需要担心的依赖性降到了最低。

第二步 - XAF 完成其魔法。

在上述代码执行完毕并处理完我想要转换为 nvarchar 并保留用户名的列后,我需要允许 XAF 推送所有类更改,并实际创建新的权限策略表,同时在我在其中使用了想要迁移的用户(如 Employee.SystemUser)的类中创建列和关系。

这由框架本身处理,并在 UpdateDatabaseBeforeUpdateSchema 完成执行后自动开始。

第三步 - 后更新迁移。

好的,我们现在在 UpdateDatabaseAfterUpdateSchema 中。

需要注意的是,你需要切换到新的安全系统。你可以通过应用程序(WinApplication.cs)上的模块设计器,将 PermissionPolicyUser 设置为 UserType,将 PermissionPolicyRole 设置为 RoleType (更多详情请参阅 XAF 文档),或者你可以像这样在代码中进行:

public static WindowsFormsApplication CreateApplication()

{

   WindowsFormsApplication winApplication = new WindowsFormsApplication();

   winApplication.Security =

      new SecurityStrategyComplex(

         typeof(DevExpress.Persistent.BaseImpl.PermissionPolicy.PermissionPolicyUser),

         typeof(DevExpress.Persistent.BaseImpl.PermissionPolicy.PermissionPolicyRole),

         new WinChangeDatabaseStandardAuthentication()); // This is my authentication type which allows database selection on login, so you will want to use standard XAF authentication here

}

新的表和列已经创建,我们现在需要从旧的已重命名的列迁移数据。
为了做到这一点,我使用了另一个名为 sp_sys_MigrateUsersToPermissionPolicy 的存储过程。我使用相同的系统 - 存储过程放在一个文件中,作为嵌入资源添加,然后加载并执行。
这是 UpdateDatabaseAfterUpdateSchema 代码。

if (CurrentDBVersion < new Version("3.5.3.107"))
{
    UpdateStatus("InitSecurity", "Migrate users", "This action might take several minutes ...");

    // We need to manually transfer users because C# scripts can not migrate passwords
    ExecuteNonQueryCommand(@"
INSERT INTO PermissionPolicyUser (Oid, UserName, StoredPassword, ChangePasswordOnFirstLogon, IsActive)
SELECT NEWID(), UserName, StoredPassword, ChangePasswordOnFirstLogon, IsActive
FROM SecuritySystemUser
WHERE GCRecord IS NULL", false);

    MySecurity.ConvertToNewSecurityModel(this, ObjectSpace);

    batchSql = Func.GetSqlScript(this.GetType(), "Link.Module.DatabaseUpdate.Script.{0}.sql", "sp_sys_MigrateUsersToPermissionPolicy", "");
    foreach (string sql in Func.GetNonQueryFromBatch(batchSql))
    {
        if (!string.IsNullOrWhiteSpace(sql)) ExecuteNonQueryCommand(sql, false);
    }

    using (var conn = DB.DBCommon.NewMSSqlConnection)
    {
        conn.Open();

        using (SqlCommand cmd = new SqlCommand(@"EXEC dbo.sp_sys_MigrateUsersToPermissionPolicy", conn))
        {
            cmd.CommandTimeout = 0;
            cmd.ExecuteNonQuery();
        }

        conn.Close();
    }
}

因此,我们再次更新存储过程代码,然后执行它,但首先我们使用 SQL 迁移用户,因为 C# 代码无法迁移密码。

这是 sp_sys_MigrateUsersToPermissionPolicy 存储过程(更多信息请参阅注释)。

ALTER PROCEDURE [dbo].[sp_sys_MigrateUsersToPermissionPolicy]
AS
BEGIN
    -- This procedure needs to be executed AFTER XAF updates database

    DECLARE @sql nvarchar(MAX)
    DECLARE @sch nvarchar(50)
    DECLARE @tbl nvarchar(200)
    DECLARE @fk nvarchar(200)
    DECLARE @col nvarchar(200)

    -- We fetch all columns that are referencing old SecuritySystemUser
    -- This are basically all columns we renamed in previous step
    -- Just to sleep tighter, we exclude any UserCreated and UserModified columns
    -- Technically, those references should not exists any more, but anything for better sleep, right?
    DECLARE cur_tbl2 CURSOR FOR
    select
        tab1.name AS [table],
        sch.name AS [schema_name],
        obj.name AS FK_NAME,
        col1.name AS [column]
    FROM sys.foreign_key_columns fkc
    INNER JOIN sys.objects obj
        ON obj.object_id = fkc.constraint_object_id
    INNER JOIN sys.tables tab1
        ON tab1.object_id = fkc.parent_object_id
    INNER JOIN sys.schemas sch
        ON tab1.schema_id = sch.schema_id
    INNER JOIN sys.columns col1
        ON col1.column_id = parent_column_id AND col1.object_id = tab1.object_id
    INNER JOIN sys.tables tab2
        ON tab2.object_id = fkc.referenced_object_id
    INNER JOIN sys.columns col2
    ON col2.column_id = referenced_column_id AND col2.object_id = tab2.object_id
    WHERE
        tab2.name = 'SecuritySystemUser'
        and not tab1.name like '%SecuritySystem%'
        and (
            col1.name not in ('UserCreated', 'UserModified')
        )

    -- Table variable to hold related indices
    DECLARE @idxtbl TABLE (
        index_name nvarchar(200),
        index_description nvarchar(200),
        index_keys nvarchar(200)
    )
    DECLARE @sql2 nvarchar(max)

    OPEN cur_tbl2
    FETCH NEXT FROM cur_tbl2 INTO @tbl, @sch, @fk, @col

    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @sql = ''

        -- Here we check if XAF actually created new columns properly
        -- If it did, we create SQL which will join to SecuritySystemUser using old column Oid and then using UserName join to new PermissionPolicyUser
        -- and update new column wich matching Oid - hence migrating old user to new one
        IF COL_LENGTH(@tbl, REPLACE(@col, 'Old', '')) IS NOT NULL    
            SET @sql =         
                'UPDATE q SET q.' + REPLACE(@col, 'Old', '') + ' = pu.Oid FROM ' + @sch + '.' + @tbl + ' q INNER JOIN dbo.SecuritySystemUser u on u.Oid = q.' + @col + ' INNER JOIN PermissionPolicyUser pu ON pu.UserName = u.UserName; ' + CHAR(10)

        -- After that we drop constraint from Old column
        SET @sql = @sql + ' ALTER TABLE ' + @sch + '.' + @tbl + ' DROP CONSTRAINT ' + @fk + '; ' + CHAR(10)

        DELETE FROM @idxtbl

        INSERT INTO @idxtbl
        EXEC sys.sp_helpindex @objname = @tbl

        -- And also all related indicies
        SELECT
            @sql2 = (
                select                 
                    ' DROP INDEX ' + @tbl + '.' + index_name + '; ' + CHAR(10)
                from @idxtbl
                where index_keys = @col
                for xml path('')
                )

        SET @sql = @sql + @sql2

        -- Finally - we drop Old column and migration is done
        SET @sql = @sql +
            ' ALTER TABLE ' + @sch + '.' + @tbl + ' DROP COLUMN ' + @col + '; ' + CHAR(10)
    
        EXEC sp_executesql @sql
        -- PRINT @sql
    
        FETCH NEXT FROM cur_tbl2 INTO @tbl, @sch, @fk, @col
    END

    CLOSE cur_tbl2
    DEALLOCATE cur_tbl2
END
GO

最后 - 这是 DevExpress 提供的代码(我稍微修改了一下,因为我实际上是在 SQL 中迁移用户,而原始代码不支持这一点),包装在 ConvertToNewSecurityModel: 中。

        public static void ConvertToNewSecurityModel(ModuleUpdater updater, IObjectSpace objectSpace)
        {
            using (MySecurity mySecurity = new MySecurity(updater, objectSpace, updateAll: false))
            {
                foreach (SecuritySystemUser securitySystemUser in objectSpace.GetObjects<SecuritySystemUser>())
                {
                    mySecurity.CopyUser(securitySystemUser);
                }
                foreach (SecuritySystemRole PermissionPolicyRole in objectSpace.GetObjects<SecuritySystemRole>())
                {
                    mySecurity.CopyRole(PermissionPolicyRole, null);
                }
                objectSpace.CommitChanges();
            }
        }

        private void CopyUser(SecuritySystemUser securitySystemUser)
        {
            PermissionPolicyUser permissionPolicyUser = ObjectSpace.FindObject<PermissionPolicyUser>(new BinaryOperator("UserName", securitySystemUser.UserName));
            if (permissionPolicyUser == null)
            {
                permissionPolicyUser = ObjectSpace.CreateObject<PermissionPolicyUser>();
                permissionPolicyUser.UserName = securitySystemUser.UserName;
                permissionPolicyUser.IsActive = securitySystemUser.IsActive;
                permissionPolicyUser.SetPassword("123");
                permissionPolicyUser.ChangePasswordOnFirstLogon = securitySystemUser.ChangePasswordOnFirstLogon;
            }

            foreach (SecuritySystemRole securitySystemRole in securitySystemUser.Roles)
            {
                CopyRole(securitySystemRole, permissionPolicyUser);
            }

        }
        private void CopyRole(SecuritySystemRole securitySystemRole, PermissionPolicyUser permissionPolicyUser)
        {
            PermissionPolicyRole permissionPolicyRole = ObjectSpace.FindObject<PermissionPolicyRole>(new BinaryOperator("Name", securitySystemRole.Name));
            if (permissionPolicyRole == null)
            {
                permissionPolicyRole = ObjectSpace.CreateObject<PermissionPolicyRole>();
                permissionPolicyRole.Name = securitySystemRole.Name;
                permissionPolicyRole.PermissionPolicy = SecurityPermissionPolicy.DenyAllByDefault;
                permissionPolicyRole.IsAdministrative = securitySystemRole.IsAdministrative;
                permissionPolicyRole.CanEditModel = securitySystemRole.CanEditModel;
                foreach (SecuritySystemTypePermissionObject securitySystemTypePermissionObject in securitySystemRole.TypePermissions)
                {
                    CopyTypePermissions(securitySystemTypePermissionObject, securitySystemRole, permissionPolicyRole);
                }
                foreach (SecuritySystemRole parentRole in securitySystemRole.ParentRoles)
                {
                    CopyParentRole(parentRole, permissionPolicyRole);
                }
            }

            if (permissionPolicyUser != null && !permissionPolicyUser.Roles.Any(x => x.Name == permissionPolicyRole.Name))
            {
                permissionPolicyUser.Roles.Add(permissionPolicyRole);
            }

        }
        private void CopyParentRole(SecuritySystemRole parentRole, PermissionPolicyRole permissionPolicyRole)
        {
            if (parentRole.IsAdministrative)
            {
                permissionPolicyRole.IsAdministrative = true;
            }

            if (parentRole.CanEditModel)
            {
                permissionPolicyRole.IsAdministrative = true;
            }
            foreach (SecuritySystemTypePermissionObject securitySystemTypePermissionObject in parentRole.TypePermissions)
            {
                CopyTypePermissions(securitySystemTypePermissionObject, parentRole, permissionPolicyRole);
            }
            foreach (SecuritySystemRole subParentRole in parentRole.ParentRoles)
            {
                CopyParentRole(subParentRole, permissionPolicyRole);
            }
        }
        private void CopyTypePermissions(SecuritySystemTypePermissionObject securitySystemTypePermissionObject, SecuritySystemRole securitySystemRole, PermissionPolicyRole permissionPolicyRole)
        {
            PermissionPolicyTypePermissionObject permissionPolicyTypePermissionObject = ObjectSpace.FindObject<PermissionPolicyTypePermissionObject>(new BinaryOperator("TargetType", securitySystemTypePermissionObject.TargetType));
            permissionPolicyTypePermissionObject = ObjectSpace.CreateObject<PermissionPolicyTypePermissionObject>();
            permissionPolicyTypePermissionObject.TargetType = GetTargetType(securitySystemTypePermissionObject.TargetType);
            permissionPolicyTypePermissionObject.Role = permissionPolicyRole;
            if (securitySystemTypePermissionObject.AllowRead)
            {
                permissionPolicyTypePermissionObject.ReadState = SecurityPermissionState.Allow;
            }
            if (securitySystemTypePermissionObject.AllowWrite)
            {
                permissionPolicyTypePermissionObject.WriteState = SecurityPermissionState.Allow;
            }
            if (securitySystemTypePermissionObject.AllowCreate)
            {
                permissionPolicyTypePermissionObject.CreateState = SecurityPermissionState.Allow;
            }
            if (securitySystemTypePermissionObject.AllowDelete)
            {
                permissionPolicyTypePermissionObject.DeleteState = SecurityPermissionState.Allow;
            }
            if (securitySystemTypePermissionObject.AllowNavigate)
            {
                permissionPolicyTypePermissionObject.NavigateState = SecurityPermissionState.Allow;
            }
            foreach (SecuritySystemObjectPermissionsObject securitySystemObjectPermissionsObject in securitySystemTypePermissionObject.ObjectPermissions)
            {
                CopyObjectPermissions(securitySystemObjectPermissionsObject, permissionPolicyTypePermissionObject);
            }
            foreach (SecuritySystemMemberPermissionsObject securitySystemMemberPermissionsObject in securitySystemTypePermissionObject.MemberPermissions)
            {
                CopyMemberPermission(securitySystemMemberPermissionsObject, permissionPolicyTypePermissionObject);
            }
            permissionPolicyRole.TypePermissions.Add(permissionPolicyTypePermissionObject);
        }
        private void CopyMemberPermission(SecuritySystemMemberPermissionsObject securitySystemMemberPermissionsObject, PermissionPolicyTypePermissionObject permissionPolicyTypePermissionObject)
        {
            PermissionPolicyMemberPermissionsObject permissionPolicyMemberPermissionsObject = ObjectSpace.CreateObject<PermissionPolicyMemberPermissionsObject>();
            permissionPolicyMemberPermissionsObject.TypePermissionObject = permissionPolicyTypePermissionObject;
            if (securitySystemMemberPermissionsObject.AllowRead)
            {
                permissionPolicyMemberPermissionsObject.ReadState = SecurityPermissionState.Allow;
            }
            if (securitySystemMemberPermissionsObject.AllowWrite)
            {
                permissionPolicyMemberPermissionsObject.WriteState = SecurityPermissionState.Allow;
            }
            permissionPolicyMemberPermissionsObject.Members = securitySystemMemberPermissionsObject.Members;
            permissionPolicyMemberPermissionsObject.Criteria = securitySystemMemberPermissionsObject.Criteria;
            permissionPolicyTypePermissionObject.MemberPermissions.Add(permissionPolicyMemberPermissionsObject);
        }
        private void CopyObjectPermissions(SecuritySystemObjectPermissionsObject securitySystemObjectPermissionsObject, PermissionPolicyTypePermissionObject permissionPolicyTypePermissionObject)
        {
            PermissionPolicyObjectPermissionsObject permissionPolicyObjectPermissionsObject = ObjectSpace.CreateObject<PermissionPolicyObjectPermissionsObject>();
            permissionPolicyObjectPermissionsObject.TypePermissionObject = permissionPolicyTypePermissionObject;
            if (securitySystemObjectPermissionsObject.AllowRead)
            {
                permissionPolicyObjectPermissionsObject.ReadState = SecurityPermissionState.Allow;
            }
            if (securitySystemObjectPermissionsObject.AllowWrite)
            {
                permissionPolicyObjectPermissionsObject.WriteState = SecurityPermissionState.Allow;
            }
            if (securitySystemObjectPermissionsObject.AllowDelete)
            {
                permissionPolicyObjectPermissionsObject.DeleteState = SecurityPermissionState.Allow;
            }
            if (securitySystemObjectPermissionsObject.AllowNavigate)
            {
                permissionPolicyObjectPermissionsObject.NavigateState = SecurityPermissionState.Allow;
            }
            permissionPolicyObjectPermissionsObject.Criteria = securitySystemObjectPermissionsObject.Criteria;
            permissionPolicyTypePermissionObject.ObjectPermissions.Add(permissionPolicyObjectPermissionsObject);
        }
        private Type GetTargetType(Type currentType)
        {
            if (currentType == null) return null;

            Type outType;
            if (!SecurityAssociationClassDictionary.TryGetValue(currentType, out outType))
            {
                outType = currentType;
            }
            return outType;
        }
        private static Dictionary<Type, Type> SecurityAssociationClassDictionary = new Dictionary<Type, Type>(){
            { typeof(SecuritySystemUser),typeof(PermissionPolicyUser) },
            { typeof(SecuritySystemRole),typeof(PermissionPolicyRole) },
            { typeof(SecuritySystemTypePermissionObject ),typeof(PermissionPolicyTypePermissionObject ) },
            { typeof(SecuritySystemObjectPermissionsObject ),typeof(PermissionPolicyObjectPermissionsObject ) },
            { typeof(SecuritySystemMemberPermissionsObject ),typeof(PermissionPolicyMemberPermissionsObject ) }
        };

技巧

我遇到了一个相当奇怪的情况,上述代码未能加载旧的 SecuritySystemUser 和 SecuritySystemRole,因为系统已切换到新的权限策略类,所以旧的似乎不再被 XAF 注册了。
通常,我会通过在非特定模块设计器中找到这些类,找到所需的类型,然后简单地选择“在应用程序中使用”来解决这个问题。
但出于某种原因,我在任何地方都找不到这些类,所以我将以下代码放在了 Module.cs 构造函数中:

        public LinkModule()

        {

            AdditionalExportedTypes.AddRange(

                        new Type[] { typeof(SecuritySystemUser), typeof(SecuritySystemRole) });

            InitializeComponent();

        }

这解决了问题,旧的类被正确填充了。

终点线

就这样 :-)

你的场景肯定会与我的不同,但过程是相同的 - 实际的 SQL 脚本需要根据你的具体情况进行调整。
如果还需要更多细节,请不要犹豫,给我写一两句话。

祝你迁移顺利!

© . All rights reserved.