有没有办法从动态生成的字段(字段名称、字段类型)创建 SQL 表

时间:2021-07-08 09:26:39

标签: c# asp.net-core blazor blazor-server-side

我正在开发一个用户不知道内容是什么样的应用。所以我正在使用动态内容。我为我的控件创建了一个名为 control details 的模型

public class ControlDetails
{
    public string ControlName{ get; set; }
    public string Type { get; set; }
    public string Label { get; set; }
    public bool IsRequired { get; set; }

}

用户填充数据库,我将这些作为表单呈现给我的 Blazor/Razor UI。但是,我想将表单中填写的数据提交到表格中。

渲染模型中的一个示例记录是

   ControlName => Lastname;
   Type => Textbox;
   Label => Enter Firstname ;
   IsRequired => Yes;

这是由用户动态创建的

如何动态创建对应的SQL表,填写UI表单时将数据提交到哪里?例如

  create table [Table Name]
  (
      ControlName Type
      ControlName Type
      ControlName Type
  )

1 个答案:

答案 0 :(得分:0)

我一直在开发一个带有动态内容的 Blazor 项目,使管理员用户可以控制正在存储的内容。我的设置是基于 PHP API 和 MySQL 以节省成本,但我认为这个想法也适用于您。

你想避免让用户直接在数据库中创建表,而我所做的是让数据库存储动态内容的元数据。

所以在数据库中我做了这样的表格: TableMetaData - 用于存储动态表元数据的表 ColumnsMetaData - 用于存储不同列的元数据及其数据类型等的表 TableColumnsMap - 控制每个表使用哪些列的映射表,使不同的动态表可以共享列类型 DataRow - 将所有数据行存储在动态表中的表。

DataRow 表的表定义:

  • 表:DataRow
  • DatarowId - int(主键部分)
  • TableId - int(主键部分)
  • ReadOnly - bool(是否应该是 可在用户界面中编辑)
  • UpdatedBy - 用户 ID(如果出现问题 可能对
  • 有用
  • LastUpdate - 日期(主键部分)每次更新都会在此表中创建一个具有新“lastupdate”日期时间的新行。
  • 主动 - bool(这是为了改善数据流我只让最新的更新 保持活跃,这是为了避免必须检查“最大 最后更新")
  • IsDeleted - bool(允许删除和恢复列。如果 最新的活动行版本被删除,它被删除。)

最后一个表是:

  • DataCell - 用于在行的范围列中存储数据的表。 DataCell 表的列
  • DatarowId - int - 数据行的 ID,它是主键部分
  • TableId - int - 此数据行所属的表,它的第二个主键部分。它指的是表元数据表。
  • ColumnId - int - 此列所属的列,此 Id 指的是列元数据表
  • CellValue - 字符串 - 存储的数据。根据列元数据及其定义的数据类型,我将根据不同情况对其进行不同的转换。
  • UpdatedBy - userid - 对用户数据表的引用
  • LastUpdate - 日期 - 最后一个主键部分,用于存储此单元格发生的事情的完整历史
  • Active - bool - 与 datarow 表相同,只有最新版本设置为 active
  • IsDeleted - bool - 与数据行表相同,如果单元格已被删除,则为真。

这是我在 Blazor 中用于显示此数据的代码示例:

<table class="table" style="table-layout: auto; height: auto; padding:0px; border-collapse:collapse; border-spacing: 0px;">
        <thead style="padding: 0px;">
            <tr style="padding: 3px;">
                @foreach (DataColumn col in tableView.Table.Columns)
                {
                    <th @onclick="@(
                        () =>
                                     {
                                         Console.WriteLine(col.ColumnName + " ASC");
                                         if(tableView.Sort == col.ColumnName + " ASC")
                                            tableView.Sort = col.ColumnName + " DESC";
                                         else
                                            tableView.Sort = col.ColumnName + " ASC";
                                         EventManager.AddRenderAction(() => StateHasChanged());
                                     }
                        )" style="padding: 3px; cursor: s-resize;">@col.ColumnName</th>
                    }
            </tr>
        </thead>

        <tbody>
            @{
                isReadOnly = false; // ApiService.IsAdmin ? false : true;
                int rowindex = 0;
            }

            @foreach (DataRowView rowView in tableView) // for (int r = 0; r < tableView.Table.Rows.Count; r++)
            {
                if (OnlyShowChanges && !rowView.Row.GetChangedColumns().Where(c => c.ColumnName != "Vælg").Any())
                    continue;

                DataRow row = rowView.Row;
                int gid = groupId;

                if (pageSize * pageIndex > rowindex || (pageSize * (pageIndex + 1) - 1) < rowindex)
                {
                    rowindex++;
                    continue;
                }
                rowindex++;

                if (groupId != 1 && ApiService.mUserGroups.Where(g => groupName != ((TableDropDownColumn)row.ItemArray[2]).SelectedItem).Any())
                    continue;

                int r = tableData.Rows.IndexOf(row);

                <tr bgcolor="white">
                    @for (int c = 0; c < tableView.Table.Rows[r].ItemArray.Length; c++)
                    {
                        var cell = tableView.Table.Rows[r].ItemArray[c];
                        var col = tableView.Table.Columns[c];
                        string cellvalue = Convert.ToString(tableView.Table.Rows[r].ItemArray[c]);
                        Type cellType = tableView.Table.Columns[c].DataType;

                        isReadOnly = col.ReadOnly;

                        //cellType = BusDataProps.GetValueOrDefault(tableView.Table.Columns[c].ColumnName);

                        bool nullable = false;
                        if (cellType.IsGenericType && cellType.GetGenericTypeDefinition() == typeof(Nullable<>))
                        {
                            nullable = true;
                            cellType = Nullable.GetUnderlyingType(cellType);
                        }

                        if (cellType == typeof(TableDropDownColumn))
                        {
                            string selectedDropDownValue = "Tom";
                            int colno = c;
                            if (tableView.Table.Rows[r].ItemArray.Any())
                                selectedDropDownValue = ((TableDropDownColumn)tableView.Table.Rows[r].ItemArray[c]).SelectedItem;
                            <td style="padding: 0px; border-collapse:collapse;">
                                <select NAME='@col.ColumnName' readonly="@isReadOnly" @onchange="@((ChangeEventArgs __e) => UpdateDropDown(__e,r,colno))" style="background-color:transparent;" value=@selectedDropDownValue>

                                    @foreach (var item in ((TableDropDownColumn)tableView.Table.Rows[r].ItemArray[c]).DropDownItems)
                                    {
                                        if (@isReadOnly && item != selectedDropDownValue)
                                            continue;
                                        <option value=@item>@item</option>
                                        @*<option value="lightblue" style="background-color:lightblue;">Blå</option>
                                            <option value="yellow" style="background-color:yellow;">Gul</option>
                                            <option value="white" style="background-color:whitesmoke;">Hvid</option>*@
                                    }
                                    @if (!tableView.Table.Rows[r].ItemArray.Any())
                                    {
                                        <option value="Tom">Tom</option>
                                    }
                                </select>
                            </td>
                        }
                        else if (cellType == typeof(string))
                        {
                            p_rows = @cellvalue.Trim().Length > 30 ? @cellvalue.Trim().Length / 30 : p_rows = 1;
                            s_rows = @cellvalue.Trim().Length > 30 ? @cellvalue.Trim().Length / 30 : s_rows = 1;
                            <td style="padding: 0px; border-collapse:collapse;">
                                <textarea cols="10" rows="@p_rows" @onchange="@((ChangeEventArgs __e) => row.SetField<string>(col, __e.Value.ToString()))" value="@cellvalue"
                                          readonly="@isReadOnly" style="background-color:transparent; resize:both; min-height:22px; overflow: hidden; padding: 3px; border:none;" wrap="hard" />
                            </td>
                        }
                        else if (cellType == typeof(int))
                        {
                            <td style="background-color:transparent; padding:0px">
                                <input type="number" pattern="/^-?\d+\.?\d*$/" readonly="@isReadOnly" onKeyPress="if(this.value.length==4) return false;" style="background-color:transparent; border:none; padding: 3px; width: 4em" value="@cellvalue"
                                       @onchange="@((ChangeEventArgs __e) => row.SetField<int>(col, int.Parse(__e.Value.ToString())) )" size="4" max="9999" id="number" />
                            </td>
                        }
                        else if (cellType == typeof(DateTime))
                        {
                            <td style="background-color:transparent; padding:0px">
                                @if ((nullable && ((DateTime?)cell).HasValue && ((DateTime?)cell).Value.ToString("yyyy") != "0001"))
                                {
                                    <input type="date" readonly="@isReadOnly" style="background-color:transparent; border:none; padding: 3px; width:10em" value="@(((DateTime?)cell).Value.ToString("yyyy-MM-dd"))"
                                           @onchange="@((ChangeEventArgs __e) =>row.SetField<DateTime?>(col,(DateTime?)__e.Value))" />
                                }
                                else if (!nullable && !string.IsNullOrWhiteSpace(cellvalue))
                                {
                                    <input type="date" readonly="@isReadOnly" style="background-color:transparent; border:none; padding: 3px; width:10em" value="@(((DateTime)cell).ToString("yyyy-MM-dd"))"
                                           @onchange="@((ChangeEventArgs __e) =>row.SetField<DateTime>(col,(DateTime)__e.Value))" />
                                }
                                else
                                {
                                    <input type="date" readonly="@isReadOnly" style="background-color:lightyellow; border:none; padding: 3px; width:10em" value="@DateTime.Today.ToString("yyyy-MM-dd")"
                                           @onchange="@((ChangeEventArgs __e) =>ChangeDate(row, col, __e))" />//
                                }
                            </td>
                        }
                        else if (cellType == typeof(bool))
                        {
                            <td style="padding: 0px;">
                                @if (!string.IsNullOrWhiteSpace(cellvalue) && Convert.ToBoolean(tableView.Table.Rows[r].ItemArray[c]))
                                {
                                    <input type="checkbox" style="background-color:transparent; border:none; width:6em; padding: 3px" checked
                                           @onchange="@((ChangeEventArgs __e) =>row.SetField<bool>(col,(bool)__e.Value))" />
                                }
                                else
                                {
                                    <input type="checkbox" style="background-color:transparent; border:none; width:6em; padding: 3px"
                                           @onchange="@((ChangeEventArgs __e) =>row.SetField<bool>(col,(bool)__e.Value))" />
                                }
                            </td>
                        }
                        else
                        {
                            <td style="padding: 0px;">
                                <textarea cols="40" rows="@p_rows" value="No value found type is @cellType.ToString()"
                                          readonly="@isReadOnly" style="background-color:transparent; resize:both; min-height:22px; overflow: hidden; padding: 3px; border:none;" wrap="hard" />
                            </td>
                        }
                    }
                </tr>
            }
        </tbody>
    </table>

所以我将所有表数据存储在 C# DataTables 中,但以我自己的方式使用它。这是显示数据的地方,另一个地方我做了一个列编辑器,用户可以在其中创建自己的列。一种列类型用于下拉菜单。