Orchard CMS 模块开发工作流程

3
我该如何强制Orchard重新运行Migrations.Create方法以重新创建我的模块数据呢?所有我看到的教程都使用Migrations.UpdateFrom方法使Orchard识别模块数据更改,但这意味着我每次在开发过程中进行更改时都必须创建一个新的方法。这些方法对于实际版本更新是有意义的,但对于初始开发来说则不然。
我尝试了禁用和重新启用模块,但没有成功。我也尝试卸载并重新安装模块,但运行卸载命令会永久删除模块,绕过回收站。
2个回答

3

我有点困惑你的问题,但我会尝试回答

迁移更新数据库和其中的数据。如果您想对仪表板中看到的视图进行更改,您不需要重新运行迁移。

但是,如果您要更改模型和数据,则需要运行更多的迁移或重置数据库并运行创建迁移。

当我重建我正在开发的模块时,它将运行任何未完成的迁移,而无需在本地版本上禁用/启用该模块

也就是说,如果当前迁移版本为1,并且在迁移中有UpdateFrom1方法,则在构建项目时将运行此方法。

您可以在以下表Orchard_Framework_DataMigrationRecord中检查当前版本号

如果您想强制重新运行迁移,则可以重置数据库中表的值。或者您可以在运行整个迁移套件之前备份数据库,并还原。

在开发过程中,我使用短小的迁移,在每次添加数据时创建一个方法,我尽量保持这些小,以便在开发过程中轻松识别任何问题。

然后在完成模块之前,将迁移合并为2或3个逻辑代码块

这是一个自定义类型的迁移示例

public int Create()
        {
            // Define the project type 
            ContentDefinitionManager.AlterTypeDefinition("Project", cfg => cfg
                .WithSetting("Stereotype", "Content")
                .CommomPart()
                .AutoroutePart("our-work")
                .BodyPart()
                .WithPart("TitlePart")
                .WithPart("PublishLaterPart")
                .WithPart("MenuPart", builder => builder
                    .WithSetting("MenuPart.OnMenu", "true")
                    .WithSetting("MenuPart.CurrentMenu", "Project Menu"))
                .WithPart("Project")
                .Creatable()
                .Draftable());

            return 1;

        }

        public int UpdateFrom1()
        {
            // Define project part - having a part with the same name will create fields in the project type
            ContentDefinitionManager.AlterPartDefinition("Project", builder => builder
               .MediaPickerField("MainImage")
               .MediaPickerField("MediumImage")
               .MediaPickerField("SmallImage")
               .MediaPickerField("Logo")
               .TextField("ShortDescription", Flavour.TextArea)
               .TextField("Features", Flavour.Markdown)
               .TextField("ClientTitle", Flavour.DefaultFlavour)
               .TextField("ClientName", Flavour.DefaultFlavour)
               .TextField("ClientQuote", Flavour.Textarea)
               .BooleanField("MainProjectOnHomePage", false)
               .Attachable());

            return 2;
        }

我添加了一些扩展方法,使其更简洁。

下面是它们:

 public static class MigrationExtentionHelpers
    {
        // part definitions 

        public static ContentPartDefinitionBuilder MediaPickerField(this ContentPartDefinitionBuilder builder, 
                                                                    string name, bool required = true, string hint = "")
        {
            var displayName = SplitCamel(name);

            // default implementation of Media picker field - create overloads for more options
            return  builder.WithField(name, fieldBuilder => fieldBuilder
                        .OfType("MediaPickerField")
                        .WithDisplayName(displayName)
                        .WithSetting("MediaPickerFieldSettings.Required", required.ToString(CultureInfo.InvariantCulture))
                        .WithSetting("MediaPickerFieldSettings.AllowedExtensions", "jpg png gif")
                        .WithSetting("MediaPickerFieldSettings.Hint", hint));

        }

        public static ContentPartDefinitionBuilder TextField(this ContentPartDefinitionBuilder builder, 
                                                             string name, Flavour flavor, bool required = true, string hint = "")
        {
            var strFlavor = SplitCamel(flavor.ToString());

            // default implementation of Media picker field - create overloads for more options
            return builder.WithField(name, fieldBuilder => fieldBuilder
                        .OfType("TextField")
                        .WithSetting("TextFieldSettings.Required", required.ToString(CultureInfo.InvariantCulture))
                        .WithSetting("TextFieldSettings.Flavor", strFlavor)
                        .WithSetting("TextFieldSettings.Hint", hint));

        }

        public static ContentPartDefinitionBuilder BooleanField(this ContentPartDefinitionBuilder builder,
                                                                string name, bool defalut, string hint = "")
        {
            // default implementation of Media picker field - create overloads for more options
            return builder.WithField(name, fieldBuilder => fieldBuilder
                        .OfType("BooleanField")
                        .WithSetting("BooleanFieldSettings.Hint", hint)
                        .WithSetting("BooleanFieldSettings.DefaultValue", defalut.ToString(CultureInfo.InvariantCulture)));

        }

        // type definitions 

        public static ContentTypeDefinitionBuilder AutoroutePart(this ContentTypeDefinitionBuilder builder, string pathPrefix = "")
        {
            var pattern = string.Format("[{{Name:'{0}/Title', Pattern: '{0}/{{Content.Slug}}', Description: 'my-page'}}]", pathPrefix);

            return builder.WithPart("AutoroutePart", partBuilder => partBuilder
                        .WithSetting("AutorouteSettings.PatternDefinitions", pattern)); 
        }


        public static ContentTypeDefinitionBuilder BodyPart(this ContentTypeDefinitionBuilder builder, 
            Flavour defaultFlavour = Flavour.Markdown)
        {
            return builder.WithPart("BodyPart", partBuilder => partBuilder
                        .WithSetting("BodyTypePartSettings.Flavor", defaultFlavour.ToString()));            
        }

        public static ContentTypeDefinitionBuilder CommomPart(this ContentTypeDefinitionBuilder builder)
        {
            return builder.WithPart("CommonPart")
                        .WithSetting("OwnerEditorSettings.ShowOwnerEditor", false.ToString(CultureInfo.InvariantCulture).ToLower());

        }

        private static string SplitCamel(string enumString)
        {

            StringBuilder sb = new StringBuilder();

            char last = char.MinValue;
            foreach (char c in enumString)
            {
                if (char.IsLower(last) && char.IsUpper(c))
                {
                    sb.Append(' ');
                    sb.Append(c.ToString(CultureInfo.InvariantCulture).ToLower());
                }
                else
                {
                    sb.Append(c);
                }
                last = c;
            }
            return sb.ToString();

        }
    }

1
谢谢,非常有帮助的答案!我想处理这个问题最简单的方法就是像你提到的那样重置数据库。很遗憾Orchard没有内置更好地处理这个问题的功能。在我看来,在初始开发期间进行“迁移”并没有意义。迁移应该用于允许用户从您产品的旧版本迁移。 - Josh Noe
1
是的,我很惊讶迁移中没有下滚/回滚方法。目前正在处理一个更大的项目。我想尽可能将东西拆分成较小的模块,但出于性能考虑,模块越少越好...这是我听说的。 - Axe

0

基本上,我所知道的除非从以前创建的备份还原数据库或直接调整它,否则没有办法运行两次迁移。

对于我来说,这不是问题,因为在我的团队开发过程中,我们使用本地数据库实例,并将所有迁移合并为初始迁移,然后部署到测试/暂存环境。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接