Привет Мне нужна идея, как вставить родительские / дочерние строки в EF6 с 2 внешними ключами, если строк не было раньше. Я работаю в c # MVC 5 с MSSQL DB, используя EF6 для связи DB.
У меня есть 4 таблицы с соответствующими классами.
Описание следующее: в таблице есть столбцы и строки. У строки есть ячейки, но поскольку одна ячейка принадлежит столбцу, столбец также имеет ячейки. Это означает, что одной ячейкой является определение по строке и столбцу (с использованием внешних ключей).
Модельные классы для этого:
[Table("TD_Tables")]
public class TD_Table
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int TD_TableId { get; set; }
public bool Active { get; set; }
public string Orientation { get; set; }
public int TenderDefinitionId { get; set; }
[ForeignKey("TenderDefinitionId")]
public TenderDefinition TenderDefinition { get; set; }
public virtual ICollection<TD_Column> Columns { get; set; }
public virtual ICollection<TD_Row> Rows { get; set; }
}
[Table("TD_Rows")]
public class TD_Row
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int TD_RowId { get; set; }
public bool Active { get; set; }
public int Sort { get; set; }
public int TD_TableId { get; set; }
[ForeignKey("TD_TableId")]
public TD_Table Table { get; set; }
public virtual ICollection<TD_Cell> Cells { get; set; }
}
[Table("TD_Columns")]
public class TD_Column
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int? TD_ColumnId { get; set; }
public bool Active { get; set; }
public string ColumnName { get; set; }
public int Sort { get; set; }
public int TD_TableId { get; set; }
[ForeignKey("TD_TableId")]
public TD_Table Table { get; set; }
public int TD_ColumnTypeId { get; set; }
[ForeignKey("TD_ColumnTypeId")]
public TD_ColumnType ColumnType { get; set; }
public virtual ICollection<TD_Cell> Cells { get; set; }
}
[Table("TD_Cells")]
public class TD_Cell
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int TD_CellId { get; set; }
public bool Active { get; set; }
public string CellValue { get; set; }
public int? TD_ColumnId { get; set; }
[ForeignKey("TD_ColumnId")]
public virtual TD_Column Column { get; set; }
public int? TD_RowId { get; set; }
[ForeignKey("TD_RowId")]
public virtual TD_Row Row { get; set; }
}
Для вставки в БД я создаю объект модели таблицы со всеми строками, столбцами
и клетки сначала и вставьте все в один вызов. Создание объекта модели таблицы:
{
var model = new TD_Table();
model.Active = true;
//number of columns to create
for(int i =0; i < columnsNum.AsInt(0); i++)
{
var column = new TD_Column()
{
Active = true,
ColumnName = "",
ColumnTypeId = (int)Core.Enums.TD_ColumnType.Text,
Sort = model.Columns.Count
};
model.Columns.Add(column);
}
//number of rows to create
for (int i = 0; i < rowsNum.AsInt(0); i++)
{
var row = new TD_Row()
{
Active = true,
Sort = i,
TD_TableId = model.TD_TableId
};
for(int c = 0; c < model.Columns.Count; c++)
{
var cell = new TD_Cell()
{
Active = true,
CellValue = "",
TD_ColumnId = model.Columns[c].TD_ColumnId,
Column = model.Columns[c]
};
model.Columns[c].Cells.Add(cell);
row.Cells.Add(cell);
}
model.Rows.Add(row);
}
// add table model in parent definition model
tender.TenderContent.TenderDefinition.Tables.Add(model);
}
В хранилище я обновляю существующее родительское определение и добавляю новую таблицу или обновляю существующую со всеми дочерними строками:
Tender Update(Tender tender)
{
using (var db = new TenderDbContext())
{
var t = db.Tenders.
Include(x => x.TenderContent).
Include(x => x.TenderContent.TenderDefinition).
//Include(x => x.TenderContent.TenderDefinition.Tables).
Include(x => x.TenderContent.TenderDefinition.Tables.Select(y => y.Columns.Select(z => z.Cells))).
Include(x => x.TenderContent.TenderDefinition.Tables.Select(y => y.Rows.Select(z => z.Cells))).
Include(x => x.TenderContent.Survey).
Include(x => x.TenderContent.Survey.Questions).
Where(x => x.TenderId == tender.TenderId).FirstOrDefault();
foreach (var table in tender.TenderContent.TenderDefinition.Tables.Where(x => x.Active))
{
var tableId = table.TD_TableId;
var existingTable = t.TenderContent.TenderDefinition.Tables
.Where(c => c.TD_TableId == tableId)
.FirstOrDefault();
if (existingTable != null)
{
db.Entry(existingTable).CurrentValues.SetValues(table);
if (table.Columns != null && table.Columns.Any())
{
foreach (var column in table.Columns.Where(x => x.Active))
{
var existingColumn = db.TD_Columns.Where(x => x.TD_ColumnId == column.TD_ColumnId).FirstOrDefault();
if (existingColumn != null)
db.Entry(existingColumn).CurrentValues.SetValues(column);
else
existingTable.Columns.Add(column);
}
}
if (table.Rows != null && table.Rows.Any())
{
foreach (var row in table.Rows.Where(x => x.Active))
{
var existingRow = db.TD_Rows.Where(x => x.TD_RowId == row.TD_RowId).FirstOrDefault();
if (existingRow != null)
{
db.Entry(existingRow).CurrentValues.SetValues(row);
foreach (var cell in row.Cells.Where(x => x.Active))
{
var cellExisting = db.TD_Cells.Where(q => q.TD_CellId == cell.TD_CellId).FirstOrDefault();
if (cellExisting != null)
db.Entry(cellExisting).CurrentValues.SetValues(cell);
else
row.Cells.Add(cell);
}
}
else
existingTable.Rows.Add(row);
}
}
}
else
t.TenderContent.TenderDefinition.Tables.Add(table); //insert table with all children
}
db.SaveChanges();
return t;
}
}
Моя главная проблема заключается в том, что после вставки новой таблицы, например. t.TenderContent.TenderDefinition.Tables.Add (таблица). Строки TD_Cells дублируются с заполненным значением RowId, и ColumnId равен нулю, а значение ColumnId заполнено, а RowId равен нулю. Так что, если я хочу вставить 10 ячеек с 2 внешними ключами строки и идентификатора столбца, у меня есть 20 ячеек с 1 ключом
Проблема в том, что когда я создал ячейку, я добавил эту ячейку в столбец и в строку, и EF не знает, как сопоставить эту ячейку с двумя внешними ключами. Если я добавил только один, будет заполнен только 1 ключ. Кто-нибудь может найти, что здесь не так и как лучше всего справиться с такой ситуацией?