我正在开发一个用户不知道内容是什么样的应用。所以我正在使用动态内容。我为我的控件创建了一个名为 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
)
答案 0 :(得分:0)
我一直在开发一个带有动态内容的 Blazor 项目,使管理员用户可以控制正在存储的内容。我的设置是基于 PHP API 和 MySQL 以节省成本,但我认为这个想法也适用于您。
你想避免让用户直接在数据库中创建表,而我所做的是让数据库存储动态内容的元数据。
所以在数据库中我做了这样的表格: TableMetaData - 用于存储动态表元数据的表 ColumnsMetaData - 用于存储不同列的元数据及其数据类型等的表 TableColumnsMap - 控制每个表使用哪些列的映射表,使不同的动态表可以共享列类型 DataRow - 将所有数据行存储在动态表中的表。
DataRow 表的表定义:
最后一个表是:
这是我在 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 中,但以我自己的方式使用它。这是显示数据的地方,另一个地方我做了一个列编辑器,用户可以在其中创建自己的列。一种列类型用于下拉菜单。