diff --git a/docs/en/low-code/fluent-api.md b/docs/en/low-code/fluent-api.md index 5e93fa01da..ed91ea5a6d 100644 --- a/docs/en/low-code/fluent-api.md +++ b/docs/en/low-code/fluent-api.md @@ -16,7 +16,7 @@ C# Attributes and the Fluent API are the **recommended way** to define dynamic e ````csharp [DynamicEntity] [DynamicEntityUI(PageTitle = "Products")] -public class Product +public class Product : DynamicEntityBase { [DynamicPropertyUnique] public string Name { get; set; } @@ -30,18 +30,7 @@ public class Product } ```` -### Step 2: Register the Assembly - -````csharp -public override void ConfigureServices(ServiceConfigurationContext context) -{ - AbpDynamicEntityConfig.SourceAssemblies.Add( - new DynamicEntityAssemblyInfo(typeof(YourDomainModule).Assembly) - ); -} -```` - -### Step 3: Add Migration and Run +### Step 2: Add Migration and Run ```bash dotnet ef migrations add Added_Product @@ -50,12 +39,12 @@ dotnet ef database update You now have a complete Product management page with data grid, create/edit modals, search, sorting, and pagination. -### Step 4: Add Relationships +### Step 3: Add Relationships ````csharp [DynamicEntity] [DynamicEntityUI(PageTitle = "Orders")] -public class Order +public class Order : DynamicEntityBase { [DynamicForeignKey("MyApp.Customers.Customer", "Name", ForeignAccess.Edit)] public Guid CustomerId { get; set; } @@ -65,7 +54,7 @@ public class Order } [DynamicEntity(Parent = "MyApp.Orders.Order")] -public class OrderLine +public class OrderLine : DynamicEntityBase { [DynamicForeignKey("MyApp.Products.Product", "Name")] public Guid ProductId { get; set; } @@ -97,7 +86,7 @@ Marks a class as a dynamic entity. The entity name is derived from the class nam ````csharp [DynamicEntity] -public class Product +public class Product : DynamicEntityBase { public string Name { get; set; } public decimal Price { get; set; } @@ -108,7 +97,7 @@ Use the `Parent` property for parent-child (master-detail) relationships: ````csharp [DynamicEntity(Parent = "MyApp.Orders.Order")] -public class OrderLine +public class OrderLine : DynamicEntityBase { public Guid ProductId { get; set; } public int Quantity { get; set; } @@ -122,7 +111,7 @@ Configures entity-level UI. Entities with `PageTitle` get a menu item and a dedi ````csharp [DynamicEntity] [DynamicEntityUI(PageTitle = "Product Management")] -public class Product +public class Product : DynamicEntityBase { // ... } @@ -211,7 +200,7 @@ Defines JavaScript interceptors on a class for CRUD lifecycle hooks: InterceptorType.Post, "context.log('Deleted: ' + context.commandArgs.entityId);" )] -public class Organization +public class Organization : DynamicEntityBase { public string Name { get; set; } } @@ -241,7 +230,7 @@ Reference in an entity: ````csharp [DynamicEntity] [DynamicEntityUI(PageTitle = "Organizations")] -public class Organization +public class Organization : DynamicEntityBase { public string Name { get; set; } public OrganizationType OrganizationType { get; set; } @@ -272,28 +261,38 @@ The Fluent API has the **highest priority** in the configuration system. Use `Ab ### Basic Usage -Configure in your Domain module's `ConfigureServices`: +Configure in your Low-Code Initializer (e.g. `MyAppLowCodeInitializer`): ````csharp -public override void ConfigureServices(ServiceConfigurationContext context) +public static class MyAppLowCodeInitializer { - AbpDynamicEntityConfig.EntityConfigurations.Configure( - "MyApp.Products.Product", - entity => - { - entity.DefaultDisplayPropertyName = "Name"; + private static readonly AsyncOneTimeRunner Runner = new(); - var priceProperty = entity.AddOrGetProperty("Price"); - priceProperty.AsRequired(); - priceProperty.UI = new EntityPropertyUIDescriptor - { - DisplayName = "Unit Price", - CreationFormAvailability = EntityPropertyUIFormAvailability.Available - }; + public static async Task InitializeAsync() + { + await Runner.RunAsync(async () => + { + AbpDynamicEntityConfig.EntityConfigurations.Configure( + "MyApp.Products.Product", + entity => + { + entity.DefaultDisplayPropertyName = "Name"; + + var priceProperty = entity.AddOrGetProperty("Price"); + priceProperty.AsRequired(); + priceProperty.UI = new EntityPropertyUIDescriptor + { + DisplayName = "Unit Price", + CreationFormAvailability = EntityPropertyUIFormAvailability.Available + }; + + entity.AddOrGetProperty("InternalNotes").AsServerOnly(); + } + ); - entity.AddOrGetProperty("InternalNotes").AsServerOnly(); - } - ); + await DynamicModelManager.Instance.InitializeAsync(); + }); + } } ```` @@ -435,7 +434,7 @@ public enum OrderStatus // Customer entity [DynamicEntity] [DynamicEntityUI(PageTitle = "Customers")] -public class Customer +public class Customer : DynamicEntityBase { [DynamicPropertyUnique] public string Name { get; set; } @@ -453,7 +452,7 @@ public class Customer // Product entity [DynamicEntity] [DynamicEntityUI(PageTitle = "Products")] -public class Product +public class Product : DynamicEntityBase { [DynamicPropertyUnique] public string Name { get; set; } @@ -474,7 +473,7 @@ public class Product } }" )] -public class Order +public class Order : DynamicEntityBase { [DynamicForeignKey("MyApp.Customers.Customer", "Name", ForeignAccess.Edit)] public Guid CustomerId { get; set; } @@ -485,7 +484,7 @@ public class Order } [DynamicEntity(Parent = "MyApp.Orders.Order")] -public class OrderLine +public class OrderLine : DynamicEntityBase { [DynamicForeignKey("MyApp.Products.Product", "Name")] public Guid ProductId { get; set; } diff --git a/docs/en/low-code/index.md b/docs/en/low-code/index.md index f075e5ee0b..da55753ecd 100644 --- a/docs/en/low-code/index.md +++ b/docs/en/low-code/index.md @@ -34,7 +34,7 @@ Traditionally, adding a new entity with full CRUD functionality to an ABP applic ````csharp [DynamicEntity] [DynamicEntityUI(PageTitle = "Products")] -public class Product +public class Product : DynamicEntityBase { [DynamicPropertyUnique] public string Name { get; set; } @@ -158,7 +158,7 @@ protected override void OnModelCreating(ModelBuilder builder) ````csharp [DynamicEntity] [DynamicEntityUI(PageTitle = "Customers")] -public class Customer +public class Customer : DynamicEntityBase { public string Name { get; set; } @@ -188,7 +188,7 @@ Define entities as C# classes with attributes. You get compile-time checking, In ````csharp [DynamicEntity] [DynamicEntityUI(PageTitle = "Orders")] -public class Order +public class Order : DynamicEntityBase { [DynamicForeignKey("MyApp.Customers.Customer", "Name", ForeignAccess.Edit)] public Guid CustomerId { get; set; } @@ -198,7 +198,7 @@ public class Order } [DynamicEntity(Parent = "MyApp.Orders.Order")] -public class OrderLine +public class OrderLine : DynamicEntityBase { [DynamicForeignKey("MyApp.Products.Product", "Name")] public Guid ProductId { get; set; } @@ -276,9 +276,9 @@ Create a class that implements `ILcCommand` and decorate it with `[Cust ````csharp [CustomCommand("Create", "MyApp.Products.Product")] -public class CustomProductCreateCommand : LcCommandBase +public class CustomProductCreateCommand : CreateCommand { - public override async Task ExecuteWithResultAsync(DynamicCommandArgs commandArgs) + public override async Task ExecuteWithResultAsync(DynamicCommandArgs commandArgs) { // Your custom create logic here // ... @@ -307,6 +307,18 @@ public class CustomProductListQuery : ILcQuery } ```` +````csharp +[CustomQuery("Single", "MyApp.Products.Product")] +public class CustomProductListQuery : ILcQuery +{ + public async Task ExecuteAsync(DynamicQueryArgs queryArgs) + { + // Your custom single query logic here + // ... + } +} +```` + | Parameter | Description | |-----------|-------------| | `queryName` | The query to replace: `"List"` or `"Single"` |