CrudGenerator - Code Generator

crud

💡 Pro Tip: Use AI to Generate Entity Classes

Before using the code generator, if you don't have an entity class yet, let AI write it for you:

I need a product table with Name, Price, Stock, and CategoryId (which links to a category table). CategoryId is a foreign key. Use FreeSql entity attributes. The entity class should inherit EntityFull. Add necessary attributes such as Table, Column, DisplayName, and Navigate.

AI will generate the complete entity class code — just copy and paste it into your project. For a detailed example, refer to the "Starting a New Module" document.

Overview

CrudGenerator is a visual code generation page that automatically produces CRUD page code based on the AdminTable component by selecting an entity type and configuring columns, relationships, and other options, reducing repetitive coding work.

Access URL: /Admin/CrudGenerator

Features

  • Automatically scans IEntity<> entities in the project – select and use
  • Visual column configuration (display, filter, search, edit column width)
  • Auto-detects ManyToOne navigation properties (foreign key → related entity), supports dropdown/dialog selection
  • Auto-detects OneToMany / ManyToMany collection navigation properties, supports IncludeMany loading or sub-table editing
  • Distinguishes [Flags] enums (MultiSelect) from regular enums (Select)
  • Automatically uses Switch/NullSwitch for bool / bool? types
  • Supports feature toggles like Draft Auto-Save (EnableDraft), Save Without Close (EnableSaveWithoutClose)
  • Supports generating a separate edit template component file
  • Supports menu generation with automatic add/edit/delete button creation
  • Code preview – WYSIWYG
  • Integrated AI assistant (OpenAI-compatible API) for natural language code customization
  • Configuration auto-saves to browser localStorage and restores on next use

Configuration

Basic Settings

Option Description
Entity Type Select the entity for CRUD generation. Auto-scans IEntity<> and [Table]-attributed classes
Page Size Number of records per page
Edit Dialog Size of the edit dialog (Large / ExtraLarge / Fullscreen, etc.)
Route Path Page route, e.g. /Admin/MyEntity
Search Show simple search box
Advanced Search Show advanced search button
Extend Buttons Show extension button area
Import Show import button
Export Show export button
Multi-Select Enable table multi-select
Draft Save Enable draft auto-save
Save Without Close Keep dialog open after saving
Allow Add/Edit/Delete Control CRUD button visibility
Generate Menu Auto-create menu entry (with add/edit/delete buttons) on save
Separate Edit Component Generate a standalone edit component file instead of inline template

Column Configuration

Option Description
Property Entity property name
Type C# type of the property
Display Name Text shown in the list and edit template
Display Whether to show this column in the table list
Filter Enable column header filtering
Search Enable text search (string type only)
Edit Column Width Field width in the edit dialog (Single/2-col/3-col/4-col)

ManyToOne Configuration:

  • Foreign key properties auto-detect the related entity
  • Option to show the related entity name in the list
  • Edit mode: Dropdown / Dialog Select

Relationship Configuration

Option Description
Navigation Property Collection navigation property name (e.g., Albums, Menus)
Type One-to-Many or Many-to-Many
Related Entity The related entity type
Display Name Tab title shown in the edit dialog
Edit Mode Disabled / IncludeMany Load / Sub-Table Edit

Sub-Table Edit: Adds a Tab in the edit dialog with an editable table for managing child collection data (add/remove rows). Column display text is customizable.

Generated Code

Inline Mode (Default)

All code is generated in a single Entity.razor file with an inline EditTemplate:

@page "/Admin/MyEntity"
<AdminTable TItem="MyEntity" TKey="long" ...>
    <TableColumns>
        ...
    </TableColumns>
    <EditTemplate>
        <!-- Inline edit template -->
    </EditTemplate>
</AdminTable>
@code { ... }

Separate Mode (Separate Edit Component checked)

Generates two files:

  • Entity.razor: Main page referencing the edit component
  • EntityEditTemplate.razor: Edit template component
@* Entity.razor *@
<AdminTable ...>
    ...
    <EditTemplate>
        <EntityEditTemplate Model="context" />
    </EditTemplate>
</AdminTable>

@* EntityEditTemplate.razor *@
@inject CommonLocalizer CommonLocalizer
...
@code {
    [Parameter]
    [NotNull]
    public MyEntity? Model { get; set; }
}

Sub-Table Generated Code

For collection navigation properties configured as "Sub-Table Edit":

<TabItem Text="ExternalLinks">
    <table class="table table-sm">
        <tr>
            <th><button @onclick="e => Model.ExternalLinks.Add(new())">+</button></th>
            <th>Text</th>
            <th>Link</th>
        </tr>
        @foreach (var item in Model.ExternalLinks)
        {
            <tr>
                <th><button @onclick="e => Model.ExternalLinks.Remove(item)">🗑</button></th>
                <td><input @bind="item.Text" /></td>
                <td><input @bind="item.Link" /></td>
            </tr>
        }
    </table>
</TabItem>

Type Mapping Rules

Entity Property Type Table Column Edit Template Component
string <TableColumn Filterable Searchable> <BootstrapInput>
int / long / decimal <TableColumn Filterable> <BootstrapInput type="number">
bool <TableColumn Filterable> <Switch>
bool? <TableColumn Filterable> <NullSwitch>
DateTime <TableColumn Filterable> <DateTimePicker>
[Flags] Enum <MultiSelect> column filter <MultiSelect>
Regular Enum <TableColumn Filterable Searchable> <Select>
ManyToOne FK Related entity name + filter <AdminSelectEntity>
OneToMany/ManyToMany Collection Sub-Table Edit / IncludeMany

Configuration Persistence

When switching entities, all column configurations, relationship settings, and basic options are automatically saved to the browser's localStorage (key: CrudGen_{EntityFullName}). When you select the same entity again, all settings are restored automatically.

Save Location

Generated files are saved to the currently running project's Components/ directory, with subdirectories determined by the route path.