Activities of "Sturla"

Add One-to-Many functionality to Suite (its not there today) and add something about it in the documentation please!

I even created a question on the topic to get an answer, Please make creating One-to-many relationship in Suite work!

Is there a good reason why its not possible to setup one-to-many relationship with Suite?

The current "one-to-many" only creates one-to-one relationship!

This here below gets created when I use the "add one-to-many navigational property" (1-n) from the Suite UI (example is where ScrapingConfiguration that should have many different ScrapingUrlId).

public class ScrapingConfiguration : FullAuditedAggregateRoot<Guid>
{
    [NotNull]
    public virtual string Name { get; set; }
    
    // Navigation property created by Suite that is one-to-ONE and not one-to-many relationship
    public virtual Guid? ScrapingUrlId{ get; set; }
}

But take a look at this question for details (why is it even called one-to-many in the UI?)

@alper answers with

ABP Suite helps to create basic CRUD pages with limited relationship options. if you need further steps, you should manually edit the generated code.

But I know that I can manually do this either by adding code like this

// Navigation property to represent the one-to-many relationship that needs to be manually added
// and one that Suite will remove when Save and create is pressed!
public virtual ICollection< ScrapingUrlId > ScrapingUrlIds{ get; set; }

or by updating the DbContext builder code like suggested here

BUT if I use Suite again it will remove that code every time I update it!

This just must be something that you can add?

p.s

There are lots of questions about this issue but nothing in the docs... I would suggest adding a One-to-many (like you have Many-to-many) part under the Generating a CRUD page

I tried to replicate the issue from a new 7.3.2 project but that didn´t work (there is no error) so it must be related to something being missed from the migration (I only used the update button)

Steps:

  1. Create a 7.2.2 project
    1. Application template
    2. Blazor Server
    3. Lepton-X
    4. Maui
    5. PostgreSQL
    6. Separate tenant schema
    7. Add entities (see below)
    8. Run update with update button in Suite

ScrapingContent.json

{
  "Id": "4ad61650-48d0-4212-80e1-a18b8762397a",
  "Name": "ScrapingContent",
  "OriginalName": "ScrapingContent",
  "NamePlural": "ScrapingContents",
  "DatabaseTableName": "ScrapingContents",
  "Namespace": "ScrapingContents",
  "BaseClass": "AuditedEntity",
  "MenuIcon": "file-alt",
  "PrimaryKeyType": "Guid",
  "IsMultiTenant": false,
  "CheckConcurrency": true,
  "ShouldCreateUserInterface": true,
  "ShouldCreateBackend": true,
  "ShouldExportExcel": true,
  "ShouldAddMigration": true,
  "ShouldUpdateDatabase": false,
  "CreateTests": true,
  "Properties": [
    {
      "Id": "d8fdc266-5d2f-4a81-8da5-e361cf427a8f",
      "Name": "Html",
      "Type": "string",
      "EnumType": "",
      "EnumNamespace": "",
      "EnumAngularImport": "shared/enums",
      "EnumFilePath": null,
      "DefaultValue": null,
      "IsNullable": false,
      "IsRequired": false,
      "IsTextArea": false,
      "MinLength": null,
      "MaxLength": null,
      "SortOrder": 0,
      "SortType": 0,
      "Regex": "",
      "EmailValidation": false,
      "ShowOnList": true,
      "ShowOnCreateModal": true,
      "ShowOnEditModal": true,
      "ReadonlyOnEditModal": false,
      "EnumValues": null,
      "IsSelected": true,
      "OrdinalIndex": 0
    },
    {
      "Id": "ffda4627-bf56-4e0d-8bb4-37ece256656d",
      "Name": "DateScraped",
      "Type": "DateTime",
      "EnumType": "",
      "EnumNamespace": "",
      "EnumAngularImport": "shared/enums",
      "EnumFilePath": null,
      "DefaultValue": null,
      "IsNullable": false,
      "IsRequired": false,
      "IsTextArea": false,
      "MinLength": null,
      "MaxLength": null,
      "SortOrder": 0,
      "SortType": 0,
      "Regex": "",
      "EmailValidation": false,
      "ShowOnList": true,
      "ShowOnCreateModal": true,
      "ShowOnEditModal": true,
      "ReadonlyOnEditModal": true,
      "EnumValues": null,
      "IsSelected": true,
      "OrdinalIndex": 0
    }
  ],
  "NavigationProperties": [
    {
      "EntityNameWithDuplicationNumber": "ScrapingUrl",
      "EntitySetNameWithDuplicationNumber": "ScrapingUrls",
      "ReferencePropertyName": "ScrapingUrl",
      "UiPickType": "Dropdown",
      "IsRequired": true,
      "Name": "ScrapingUrlId",
      "DisplayProperty": "Name",
      "Namespace": "TestNotWorking.ScrapingUrls",
      "EntityName": "ScrapingUrl",
      "EntitySetName": "ScrapingUrls",
      "DtoNamespace": "TestNotWorking.ScrapingUrls",
      "DtoEntityName": "ScrapingUrlDto",
      "Type": "Guid"
    }
  ],
  "NavigationConnections": [],
  "PhysicalFileName": "ScrapingContent.json"
}

ScrapingUrl.json

{
  "Id": "7b77295e-508a-4b0e-9d7e-e7caf2088cce",
  "Name": "ScrapingUrl",
  "OriginalName": "ScrapingUrl",
  "NamePlural": "ScrapingUrls",
  "DatabaseTableName": "ScrapingUrls",
  "Namespace": "ScrapingUrls",
  "BaseClass": "AuditedEntity",
  "MenuIcon": "file-alt",
  "PrimaryKeyType": "Guid",
  "IsMultiTenant": false,
  "CheckConcurrency": true,
  "ShouldCreateUserInterface": true,
  "ShouldCreateBackend": true,
  "ShouldExportExcel": false,
  "ShouldAddMigration": true,
  "ShouldUpdateDatabase": false,
  "CreateTests": true,
  "Properties": [
    {
      "Id": "b459187f-9946-4c43-b804-21f6637b16b4",
      "Name": "Name",
      "Type": "string",
      "EnumType": "",
      "EnumNamespace": "",
      "EnumAngularImport": "shared/enums",
      "EnumFilePath": null,
      "DefaultValue": null,
      "IsNullable": false,
      "IsRequired": false,
      "IsTextArea": false,
      "MinLength": null,
      "MaxLength": 52,
      "SortOrder": 0,
      "SortType": 0,
      "Regex": "",
      "EmailValidation": false,
      "ShowOnList": true,
      "ShowOnCreateModal": true,
      "ShowOnEditModal": true,
      "ReadonlyOnEditModal": false,
      "EnumValues": null,
      "IsSelected": true,
      "OrdinalIndex": 0
    },
    {
      "Id": "0f10d82b-e7b3-4b64-aba6-af46b2df5f03",
      "Name": "Url",
      "Type": "string",
      "EnumType": "",
      "EnumNamespace": "",
      "EnumAngularImport": "shared/enums",
      "EnumFilePath": null,
      "DefaultValue": null,
      "IsNullable": false,
      "IsRequired": false,
      "IsTextArea": false,
      "MinLength": null,
      "MaxLength": 1024,
      "SortOrder": 0,
      "SortType": 0,
      "Regex": "",
      "EmailValidation": false,
      "ShowOnList": true,
      "ShowOnCreateModal": true,
      "ShowOnEditModal": true,
      "ReadonlyOnEditModal": false,
      "EnumValues": null,
      "IsSelected": true,
      "OrdinalIndex": 0
    },
    {
      "Id": "d1752e3a-2d18-45a2-91ac-5b1d0f5505f5",
      "Name": "IsActive",
      "Type": "bool",
      "EnumType": "",
      "EnumNamespace": "",
      "EnumAngularImport": "shared/enums",
      "EnumFilePath": null,
      "DefaultValue": "true",
      "IsNullable": false,
      "IsRequired": false,
      "IsTextArea": false,
      "MinLength": null,
      "MaxLength": null,
      "SortOrder": 0,
      "SortType": 0,
      "Regex": "",
      "EmailValidation": false,
      "ShowOnList": true,
      "ShowOnCreateModal": true,
      "ShowOnEditModal": true,
      "ReadonlyOnEditModal": false,
      "EnumValues": null,
      "IsSelected": true,
      "OrdinalIndex": 0
    },
    {
      "Id": "38718158-9a68-4251-acda-898e4e4eb3ca",
      "Name": "LastError",
      "Type": "string",
      "EnumType": "",
      "EnumNamespace": "",
      "EnumAngularImport": "shared/enums",
      "EnumFilePath": null,
      "DefaultValue": null,
      "IsNullable": false,
      "IsRequired": false,
      "IsTextArea": true,
      "MinLength": null,
      "MaxLength": 1024,
      "SortOrder": 0,
      "SortType": 0,
      "Regex": "",
      "EmailValidation": false,
      "ShowOnList": true,
      "ShowOnCreateModal": true,
      "ShowOnEditModal": true,
      "ReadonlyOnEditModal": false,
      "EnumValues": null,
      "IsSelected": true,
      "OrdinalIndex": 0
    }
  ],
  "NavigationProperties": [],
  "NavigationConnections": [],
  "PhysicalFileName": "ScrapingUrl.json"
}

There is btw another error in regarding "required" and that is that if you mark a property as required the tests will also fail!

After updating (from 7.2.2) I´m getting the error below when running my tests. I´m getting this for all my tests. After having searched I found this 2 year old issue and that led me to unchecking the required tick for the navigation property and the tests started working!

Volo.Abp.AbpInitializationException : An error occurred during the initialize Volo.Abp.Modularity.OnApplicationInitializationModuleLifecycleContributor phase of the module LF.SearchPortal.SearchPortalTestBaseModule, LF.SearchPortal.TestBase, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null: An error occurred while saving the entity changes. See the inner exception for details.. See the inner exception for details. ---- Microsoft.EntityFrameworkCore.DbUpdateException : An error occurred while saving the entity changes. See the inner exception for details. -------- Microsoft.Data.Sqlite.SqliteException : SQLite Error 19: 'FOREIGN KEY constraint failed'.

    Stack Trace: 
ModuleManager.InitializeModules(ApplicationInitializationContext context)
AbpApplicationBase.InitializeModules()
AbpApplicationWithExternalServiceProvider.Initialize(IServiceProvider serviceProvider)
AbpIntegratedTest`1.ctor()
SearchPortalTestBase`1.ctor()
SearchPortalDomainTestBase.ctor()
SampleDomainTests.ctor() line 18
RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions)
----- Inner Stack Trace -----
ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
<30 more frames...>
ModuleManager.InitializeModules(ApplicationInitializationContext context)
----- Inner Stack Trace -----
SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
SqliteDataReader.NextResult()
SqliteCommand.ExecuteReader(CommandBehavior behavior)
SqliteCommand.ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)

Btw I expect to get this question refunded since this feature is not working and has caused me half a day of nothing...

  • ABP Framework version: v7.3.2
  • UI Type: Blazor Server
  • Database System: EF Core PostgreSQL
  • Tiered (for MVC) or Auth Server Separated (for Angular): no

I did this with suite and Blazor Server and it updates the package references in my Blazor project to a strange preview version of these two packages below. Try updating these to this

  <ItemGroup>
    <PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX" Version="2.3.*-*" />
    <PackageReference Include="Volo.Abp.AspNetCore.Components.Server.LeptonXTheme" Version="2.3.*-*" />
  </ItemGroup>

Please add to Suite creation information about each project in the UI. Is the project "tired, Blazor Server, PostgreSQL etc. This will make it easier to create a the same type of project to compare and update the code. And its just smart to have this information in the Suite to begin with for many other reasons.

And add a button in the dropdown, "create new version" that creates the same type of project using the same entities but with the newest version, this makes it easier to get a new version of the code to compare when updating between versions.

Add .editorconfig to all project/solution templates and update the code accordingly to have more consistency of code.

Like if I add this .editorconfig file, from David McCarter, to a brand new project I get over 70 errors, 400 warnings and 2200 suggestions...

There are probably lot in there that could be suppressed and not be used in this codebase but wouldn´t it be great to have some standard and help users from the start?

Update It's even much worse than that... because try to create a new vanilla solution and add some domain item and let it create code and there are default warnings in every single project.

So if I wanted to add <TreatWarningsAsErrors>true</TreatWarningsAsErrors> to the projects I would have to do lots of extra work cleaning up these warnings (that are now error) every time I add something with Suite.

Don´t you agree that for a framework this should not be like that?

Yes that´s correct. I chose probably the only symbol that didn´t work.

But it would be great to know how to enable the env´s and I would even go so far to say that they should be enabled by default...

I managed to make this work but only by using Environment.GetEnvironmentVariable("ConnectionStrings:Default")

I tried to add AddEnvironmentVariables() to CreateHostBuilder but that didn´t take.

So here is what I had to do.

docker run --rm \
-e ConnectionStrings:Default="$connection_string" \
${{ env.DEV_AZURE_CONTAINER_REGISTRY }}/dbmigrator:${{ github.sha }}

and the StartAsync()

public async Task StartAsync(CancellationToken cancellationToken)
{
        var envConnectionString = Environment.GetEnvironmentVariable("ConnectionStrings:Default");    
        if (!string.IsNullOrEmpty(envConnectionString))
        {
            _configuration["ConnectionStrings:Default"] = envConnectionString;
            Log.Logger.Information("Using ConnectionStrings:Default from environmental variable");
        }
        
        .... rest of the code..
    }
}

There was also one other issue and that is I was using a $ in my password and that doesn´t work because the docker run command is running in Linux using bash and then the $ is handled as a variable and it (and following letters) are skipped!

Showing 51 to 60 of 210 entries
Made with ❤️ on ABP v9.0.0-preview Updated on September 20, 2024, 08:30