c# - 如何使用 EF Core Fluent API 设计动态表数据结构?
问题描述
我想将数据存储在 SQL 表中。我的结构看起来像一个 Excel 表(或任何类型的表)。交叉点中有包含列、行和单元格的表格。我的域模型是:
public class Table {
public int Id { get; set; }
public List<Column> Columns { get; set; }
public List<Row> Rows { get; set; }
}
public class Column {
public string Name { get; set; }
public int TableId { get; set; }
public Table Table { get; set; }
}
public class Row {
public int Id { get; set; }
public List<Cell> Cells { get; set; }
public int TableId { get; set; }
public Table Table { get; set; }
}
public class Cell {
public int RowId { get; set; }
public string ColumnName { get; set; }
public int TableId { get; set; }
public string CellValue { get; set; }
public Column Column { get; set; }
public Row Row { get; set; }
}
棘手的部分是在单元格中,我在其中使用带有RowId
,ColumnName
和的复合键TableId
。
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Table>()
.HasMany(x => x.Columns)
.WithOne(x => x.Table)
.HasForeignKey(x => new { x.TableId, x.Name });
builder.Entity<Column>()
.HasKey(x => new { x.TableId, x.Name });
builder.Entity<Row>()
.HasOne(x => x.Table)
.WithMany(x => x.Rows);
builder.Entity<Row>()
.HasMany(x => x.Cells)
.WithOne(x => x.Row)
.HasForeignKey(x => new { x.RowId, x.ColumnName, x.TableId });
builder.Entity<Cell>()
.HasKey(x => new { x.RowId, x.ColumnName, x.TableId });
}
不幸的是,在尝试将表添加到数据库时出现异常。
InvalidOperationException:从 'Cell.Row' 到 'Row.Cells' 的关系具有外键属性 {'RowId' : int, 'ColumnName' : string, 'TableId' : int} 不能定位主键 {'Id' : int } 因为它不兼容。为此关系配置一个主键或一组兼容的外键属性。
我将我的示例 repo 发布到了 GitHub,也许它有助于理解和测试。 https://github.com/kodaniel/TableDbContextSample
当我使用简单的 Id PK 字段而不是复合键时,此示例工作正常,但我认为 Cell.Id 属性完全没有必要,因为 Table.Id、Column.Name 和 Row.Id 显然可以识别特定的 Cell . 所以我想这种方法应该可行,唯一的问题是我不知道我在哪里弄乱了模型构建。
解决方案
推荐阅读
- java - LDAP AD,获取密码
- php - 无法在我的 php 脚本中同时调用三个函数?
- arrays - 无法匹配R中数组中的确切数字
- ios - 如何转换uilabel保持其x位置相同并缩放以减小字体大小
- sql - 如何在sql中获取列值比较?
- node.js - Node js Google App Engine 中的 child_process
- cassandra - 尝试清理 Cassandra 节点时出错
- javascript - javascript & html - 每次用户在文本框中输入项目时创建新的复选框选项
- r - 提取句子中的第一个字符串
- java - 来电弹出错误:无法添加窗口 android.view.ViewRootImpl$W@e5b2272 -- 窗口类型 2003 的权限被拒绝