简体   繁体   English

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

[英]Is there a way to create an SQL Table from a dynamically generated fields (Field name, Field type)

I am developing an app where the user does not know what the content is like.我正在开发一个用户不知道内容是什么样的应用程序。 So i am using Dynamic Content.所以我正在使用动态内容。 I have created a model for my controls named control details我为名为 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; }

} }

The user populates the database and I render these to my Blazor/Razor UI as a form.用户填充数据库,我将它们作为表单呈现给我的 Blazor/Razor UI。 However, I want to submit the data filled in the form to a table.但是,我想将表单中填写的数据提交到表格中。

An example record in the model is rendered is渲染模型中的示例记录是

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

This is dynamically created by the user这是由用户动态创建的

How can I dynamically create a corresponding SQL table where the data will be submitted to when the UI form is filled?如何动态创建对应的 SQL 表,在填写 UI 表单时将数据提交到该表? for instance例如

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

I have been developing a Blazor project with Dynamic content making it possible for the admin users to control what content is being stored.我一直在开发一个带有动态内容的 Blazor 项目,使管理员用户可以控制正在存储的内容。 My setup is on a PHP API and MySQL to save cost, but I think the idea should work for you as well.我的设置是基于 PHP API 和 MySQL 以节省成本,但我认为这个想法也适用于您。

You want to avoid having users create tables in the database directly, instead what I have done is make the database store the metadata of the dynamic content.您希望避免让用户直接在数据库中创建表,而是让数据库存储动态内容的元数据。

So in the database I have made tables like this: TableMetaData - a table to store metadata for the dynamic tables ColumnsMetaData - a table to store the metadata for the different columns, their datatype and such TableColumnsMap - a mapping table that controls what columns each table use, making it possible for different dynamic tables to share types of columns DataRow - a table that stores all datarows in the dynamic tables.所以在数据库中我做了这样的表: TableMetaData - 一个用于存储动态表元数据的表 ColumnsMetaData - 一个用于存储不同列的元数据的表,它们的数据类型和这样的 TableColumnsMap - 一个映射表,控制每个表的列使用,使得不同的动态表可以共享列类型 DataRow - 一个将所有数据行存储在动态表中的表。

The table definition of the DataRow table: DataRow表的表定义:

  • Table: DataRow表:数据行
  • DatarowId - int (primary key part) DatarowId - int(主键部分)
  • TableId - int (primary key part) TableId - int(主键部分)
  • ReadOnly - bool (whether its supposed to be editable in the UI) ReadOnly - bool(是否应该在 UI 中可编辑)
  • UpdatedBy - userid (if something goes wrong it might be useful to UpdatedBy - 用户 ID(如果出现问题,它可能对
  • LastUpdate - date (primary key part) every update creates a new row in this table with a new "lastupdate" datetime. LastUpdate - 日期(主键部分)每次更新都会在此表中创建一个具有新“lastupdate”日期时间的新行。
  • Active - bool (This is to improve the data flow I only let the latest update be active and this is to avoid having to check for the "max lastupdate") Active - bool(这是为了改善数据流,我只让最新更新处于活动状态,这是为了避免检查“max lastupdate”)
  • IsDeleted - bool (To allow for deleting and restoring a column. If the latest active row version is deleted, its deleted.) IsDeleted - bool(允许删除和恢复列。如果删除了最新的活动行版本,则将其删除。)

The last table is:最后一张表是:

  • DataCell - A table for storing the data in reach column for the rows. DataCell - 用于在行的范围列中存储数据的表。 The columns of the DataCell table DataCell 表的列
  • DatarowId - int - The ID of the datarow, its a Primary Key part DatarowId - int - 数据行的 ID,它是主键部分
  • TableId - int - The table this datarow belongs to, its the second primary key part. TableId - int - 此数据行所属的表,它的第二个主键部分。 It refers to the tablemetadata table.它指的是表元数据表。
  • ColumnId - int - The column this belongs to, this Id refers to the columnmetadata table ColumnId - int - 这个所属的列,这个Id指的是columnmetadata表
  • CellValue - string - The stored data. CellValue - 字符串 - 存储的数据。 Depending on the columnmetadata and the type of data it defines this to be, I will cast this differently depending on that.根据列元数据和它定义的数据类型,我将根据不同情况对其进行不同的转换。
  • UpdatedBy - userid - A reference to a user datatable UpdatedBy - userid - 对用户数据表的引用
  • LastUpdate - date - The last primary key part, this is to store a full history of what has happened with this cell LastUpdate - 日期 - 最后一个主键部分,这是存储此单元格发生的事情的完整历史记录
  • Active - bool - Same as with the datarow table, only the newest version is set to active Active - bool - 与数据行表相同,仅将最新版本设置为活动
  • IsDeleted - bool - Same as the datarow table, its true if the cell has been deleted. IsDeleted - bool - 与数据行表相同,如果单元格已被删除,则为真。

This is an example of the code I use in Blazor to display this data:这是我在 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>

So I store all the table data in C# DataTables but use it a bit in my own way.所以我将所有表数据存储在 C# DataTables 中,但以我自己的方式使用它。 This is where the data is displayed and another place I have made a column editor where users can make their own columns.这是显示数据的地方,另一个地方我做了一个列编辑器,用户可以在其中创建自己的列。 One column type is for drop down menus.一种列类型用于下拉菜单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从数据库表中读取行时动态获取字段类型 - Dynamically get the field type while reading a row from a database table 如何从Webform上动态生成的字段向SQL服务器表动态添加数据? - How to Add Data Dynamically to sql server table from dynamically generated fields on Webform? 如何循环动态生成的按钮并相应地创建输入字段 - How to loop over dynamically generated buttons and create input field accordingly 有没有办法创建字典列表 <field_name, field_value> 从查询结果? - Is there the way to create list of Dictionary<field_name, field_value> from query results? sql-如何在SQL中为field_name元素中的列名和field_value元素中的列值的表创建XML路径? - How to create for XML path in sql for table with column name in field_name element and column value in field_value element? 动态创建具有多个筛选字段的新字段搜索组 - Dynamically create new field search group with multiple filter fields 从类型名称动态创建委托 - Create delegate dynamically from Type name 从 SQL 数据库的表中选择字段 - Selecting a field from a table in an SQL Database 无法访问动态生成的模板化字段控件 - Not able to access dynamically generated templated field controls 按名称从类动态导入postsharp方面字段 - Import postsharp aspect field from class by name dynamically
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM