Umbraco 13 Unable to create custom table in custom...
# help-with-umbraco
p
I have an Umbraco 13 Migration which inhertis from
MigrationBase
and is silently failing with the following exception:
Copy code
Umbraco.Cms.Infrastructure.Migrations.IncompleteMigrationExpressionException: Cannot create a new expression: the previous expression has not run.
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.BeginBuild[T](T builder)
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Create()
It's occuring here where I try and create the table:
Copy code
protected override void Migrate()
{
    if (!TableExists("MyCustomTable"))
    {
        Create.Table<MyCustomTable>().Do();
    }
}
From what I can gather the error occurs because migrations need to execute each expression before starting a new one but there are no other expressions and I'm struggling to try and find what/where this might be coming from. Any ideas?
j
Looks like you are missing the migration plan that triggers this method. Have a look at the first file in this guide: https://docs.umbraco.com/umbraco-cms/extending/database#using-a-notification-handler
p
@Jemayn Sorry, I was trying to keep my post short because of the limits on here but I have a migration plan for this, that is how the migration is being triggered.
Copy code
public class PreLaunchMigrationPlan : MigrationPlan
{
    public PreLaunchMigrationPlan() : base("PreLaunchMigrationPlan")
    {
        From(string.Empty)
            .To<CreateCustomTable>("ciwf-0");
    }
}
Copy code
public class PreLaunchMigrationComponent: INotificationHandler<UmbracoApplicationStartedNotification>
{
    private readonly IMigrationPlanExecutor _migrationPlanExecutor;
    private readonly ICoreScopeProvider _coreScopeProvider;
    private readonly IKeyValueService _keyValueService;
    private readonly IRuntimeState _runtimeState;

    public PreLaunchMigrationComponent(
        ICoreScopeProvider coreScopeProvider,
        IMigrationPlanExecutor migrationPlanExecutor,
        IKeyValueService keyValueService,
        IRuntimeState runtimeState)
        
    {
        _migrationPlanExecutor = migrationPlanExecutor;
        _coreScopeProvider = coreScopeProvider;
        _keyValueService = keyValueService;
        _runtimeState = runtimeState;
    }
        
    public void Handle(UmbracoApplicationStartedNotification notification)
    {
        if (_runtimeState.Level < RuntimeLevel.Run)
        {
            return;
        }

        var migrationPlan = new PreLaunchMigrationPlan();
        var upgrader = new Upgrader(migrationPlan);
        upgrader.Execute(_migrationPlanExecutor, _coreScopeProvider, _keyValueService);
    }
}
j
Hmm that looks right to me.. The docs mention using the
UmbracoApplicationStartingNotification
and you are using the
UmbracoApplicationStartedNotification
but dont know if that matters
p
I've tried both with the same result
j
Did you check the KeyValueTable to see if you have a value assigned already? If you've been testing and changing things you may have a start point which is not string.Empty and is not in your code so it doesn't know how to move on? It should have a key called Umbraco.Core.Upgrader.State+PreLaunchMigrationPlan if the migration has ever run
p
Yes, checked that also @Jemayn There is no entry in the table. It's incredibly frustrating. If it was a one off task I'd just go ahead and manually create the table but I really need this working as a migration.
j
Sorry am out of ideas, next step for me would probably be to check the issue tracker and then start setting breakpoints in core code where the error comes from
p
As far as I can tell there is no uncaught exception either and I read that adding breakpoints is one potential trigger of this issue https://github.com/umbraco/Umbraco-CMS/issues/5759#issuecomment-1462911782
s
In the packages section do you have the option to run the migration manually?
p
Let me take a look as I wasn't aware that was an option
@Sebastiaan I'm not seeing anything in there that would allow me to do that?
s
Ah wait, it's not an actual package so I don't think that applies, I'm getting confused!
Let me run a test, one secc
p
Correct it's not a package
In MIgrationBase - this appears to be the source of the problem public ICreateBuilder Create => BeginBuild(new CreateBuilder(Context));
Which ties in with the observations I read in the above issue
When
Migrate()
executes and before I even attempt to create the table I can see that
Context.BuildingExpression
is true - the question is why as that is what is causing this to fail.
s
Hmm, not sure what you're doing exacctly but this code worked immediately for me : https://gist.github.com/nul800sebastiaan/99c4d683ccdeb71e2f4416464b394073
p
In the latest v13?
The main difference i am seeing is that my Migration Plan is a separate class inheriting from
MigrationPlan
I will try doing that differently and see if it makes a difference
Added updated code to the gist as a comment
p
Oh joy, there must be something else somewhere in the project causing this then as there is no punctuation in my table name.
s
There's a dash here though in your code?
Copy code
csharp
From(string.Empty)
            .To<CreateCustomTable>("ciwf-0");
p
Oh, I see you meant the migration state
s
So the error above came from the line
Create.Table<BlogCommentSchema>().Do();
- this didn't work as dashes are not allowed in SQLite table names, not sure if full-fat SQL allows those though.
p
I am using "Full fat SQL", just tried amending the state to remove the hyphen but the error still persists.
The error is apparent in the Create property and all I've read and observed points towards another incomplete expression being executed somewhere. https://cdn.discordapp.com/attachments/1336259761464803328/1336292705004818454/image.png?ex=67a3470f&is=67a1f58f&hm=4eea60b06a71fa534796313fe97671594ded18896615a478f5dd69e1b962630f&
s
I assume something is wrong with your table definition then.. Happy to test it if you can post the
Manado..
code
p
Copy code
[TableName("ciwfMandatoryProperties")]
[PrimaryKey("Id", AutoIncrement = false)]
[ExplicitColumns]
public class MandatoryPropertyRecord
{
    [PrimaryKeyColumn(AutoIncrement = false)]
    public Guid Id { get; set; } = Guid.NewGuid(); // Unique identifier

    [ForeignKey(typeof(Umbraco.Cms.Core.Models.ContentType))]
    public Guid ContentTypeKey { get; set; } // ContentType key
    
    [Column("contentTypeAlias")]
    [Length(255)]
    public string ContentTypeAlias { get; set; } // ContentType alias

    [Column("propertyAlias")]
    [Length(255)]
    public string PropertyAlias { get; set; } // Alias of the property

    [Column("mandatorySetting")]
    public bool MandatorySetting { get; set; } // Stores the original mandatory setting

    [Column("recordedAt")]
    public DateTime RecordedAt { get; set; } = DateTime.UtcNow; // Timestamp of when the setting was backed up
}
However, I'm not convinced it is that
s
the table name is not the same, are you consistently using the same table name everywhere in your code?
p
Do you mean it's not called
CreateCustomTable
?
ciwfMandatoryProperties
is not
ciwf-0
I mean, your previous code examples were for
ciwf-0
as a table name
p
ciwf-0
is not the table name it's the state that s inserted in the
umbracoKeyValue
table
s
ah okay! makes sense anyway, if I update the table name everywhere to
ciwfMandatoryProperties
and remove
[ForeignKey(typeof(Umbraco.Cms.Core.Models.ContentType))]
it works - guess in your example it's trying to instantiate that class which it can't at this point of the boot process
p
I will try removing that constraint as I can do without it I think
Still no joy for me and odd that I wasn't getting the exception you were seeing relating to the foreign key constraint
Copy code
at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.BeginBuild[T](T builder)
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Create()
   at CIWF.Migrations.Migrations.CreateMandatoryPropertiesTable.Migrate() in D:\Repositories\ciwf\src\CIWF.Migrations\Migrations\CreateMandatoryPropertiesTable.cs:line 37
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.Run()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationPlanExecutor.RunMigration(Type migrationType, MigrationContext context)
   at Umbraco.Cms.Infrastructure.Migrations.MigrationPlanExecutor.RunScopedMigration(Type migrationType, MigrationPlan plan)
   at Umbraco.Cms.Infrastructure.Migrations.MigrationPlanExecutor.RunMigrationPlan(MigrationPlan plan, String fromState)
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Alter()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Create()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Delete()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Execute()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Insert()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Rename()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Update()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Alter()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Create()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Delete()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Execute()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Insert()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Rename()
   at Umbraco.Cms.Infrastructure.Migrations.MigrationBase.get_Update()
There is still an incomplete expression preventing the Create table method from executing
Not sure I can afford to spend much longer on this and may have to do it the old fashioned way for a moment and come back to it.
I'm not sure if there is a way to see what expression might be that has not completed
s
I'm out of ideas as well - but do note I am using
UmbracoApplicationStartingNotification
and you might still be relying on
Started
.
p
I am also using
UmbracoApplicationStartingNotification
- I tried both
Thanks for trying
l
Maybe a different approach? I'm using entity framework migrations for adding and changing database tables: https://docs.umbraco.com/umbraco-cms/tutorials/getting-started-with-entity-framework-core In that case I just need to run the migrations in the Umbraco started notification:
Copy code
csharp
public class DatabaseCreateMigration : INotificationAsyncHandler<UmbracoApplicationStartedNotification>
{
  ...

  public async Task HandleAsync(UmbracoApplicationStartedNotification notification, CancellationToken cancellationToken)
  {
    var pendingMigrations = await _dbContext.Database.GetPendingMigrationsAsync(cancellationToken);

    if (pendingMigrations.Any())
      await _dbContext.Database.MigrateAsync(cancellationToken);
  }
}
p
Thanks for the suggestion. I see that as more of a workaround than directly addressing/understanding the issue but will keep it in mind as a last resort.
8 Views