Вставка MVC EF6 с несколькими внешними ключами - PullRequest
0 голосов
/ 27 апреля 2018

Привет Мне нужна идея, как вставить родительские / дочерние строки в EF6 с 2 внешними ключами, если строк не было раньше. Я работаю в c # MVC 5 с MSSQL DB, используя EF6 для связи DB. У меня есть 4 таблицы с соответствующими классами. enter image description here

Описание следующее: в таблице есть столбцы и строки. У строки есть ячейки, но поскольку одна ячейка принадлежит столбцу, столбец также имеет ячейки. Это означает, что одной ячейкой является определение по строке и столбцу (с использованием внешних ключей). Модельные классы для этого:

[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 ключ. Кто-нибудь может найти, что здесь не так и как лучше всего справиться с такой ситуацией?

...