paul_vin Ответов: 1

"Столбец с именем" идентификатор встречи клиента "уже принадлежит этому datatable." ошибка в ASP .Чистая бочках скачивания данных в формате Excel


"A column named 'Client Meeting ID' already belongs to this DataTable."}

ошибка, когда я пытаюсь загрузить данные из базы данных в формат Excel.

protected void btnmeeting_Click(object sender, EventArgs e)
        {
            ResultsData1.Clear();
            SqlConnection con211 = new SqlConnection(connstring);
            SqlCommand cmd21 = new SqlCommand("USP_Report", con211);
            cmd21.CommandType = CommandType.StoredProcedure;
            cmd21.Parameters.AddWithValue("@mode", 99);            
            cmd21.Parameters.AddWithValue("@userid", Session["UserId"].ToString());           
            SqlDataAdapter da = new SqlDataAdapter(cmd21);            
            DataTable dt = new DataTable();
            dt.Clear();
            da.Fill(dt);
            DataTableReader reader = new DataTableReader(dt);
           int c = 0;
            bool firstTime = true;

            DataTable dtSchema = new DataTable();
            dtSchema.Clear();
            dtSchema = reader.GetSchemaTable();
            var listCols = new List<DataColumn>();
            if (dtSchema != null)
            {
                try
                {
                    foreach (DataRow drow in dtSchema.Rows)
                    {
                        string columnName = Convert.ToString(drow["ColumnName"]);
                        var column = new DataColumn(columnName, (Type)(drow["DataType"]));
                        column.Unique = (bool)drow["IsUnique"];
                        column.AllowDBNull = (bool)drow["AllowDBNull"];
                        column.AutoIncrement = (bool)drow["IsAutoIncrement"];
                        listCols.Add(column);
                        ResultsData1.Columns.Add(column);

                    }
                }
                catch (Exception ex)
                {
                    Response.Write(ex);
                }
            }


Это дает ошибку при
<pre>ResultsData1.Columns.Add(column);


Что я уже пробовал:

Я создал две глобальные переменные как
static private int rowsPerSheet = 200;
    static private DataTable ResultsData1 = new DataTable();


Теперь на событии нажатия кнопки у меня есть следующий код

protected void btnmeeting_Click(object sender, EventArgs e)
       {
           ResultsData1.Clear();
           SqlConnection con211 = new SqlConnection(connstring);
           SqlCommand cmd21 = new SqlCommand("USP_Report", con211);
           cmd21.CommandType = CommandType.StoredProcedure;
           cmd21.Parameters.AddWithValue("@mode", 99);
           cmd21.Parameters.AddWithValue("@userid", Session["UserId"].ToString());
           SqlDataAdapter da = new SqlDataAdapter(cmd21);
           DataTable dt = new DataTable();
           dt.Clear();
           da.Fill(dt);
           DataTableReader reader = new DataTableReader(dt);
          int c = 0;
           bool firstTime = true;

           DataTable dtSchema = new DataTable();
           dtSchema.Clear();
           dtSchema = reader.GetSchemaTable();
           var listCols = new List<DataColumn>();
           if (dtSchema != null)
           {
               try
               {
                   foreach (DataRow drow in dtSchema.Rows)
                   {
                       string columnName = Convert.ToString(drow["ColumnName"]);
                       var column = new DataColumn(columnName, (Type)(drow["DataType"]));
                       column.Unique = (bool)drow["IsUnique"];
                       column.AllowDBNull = (bool)drow["AllowDBNull"];
                       column.AutoIncrement = (bool)drow["IsAutoIncrement"];
                       listCols.Add(column);
                       ResultsData1.Columns.Add(column);

                   }
               }
               catch (Exception ex)
               {
                   Response.Write(ex);
               }
           }

           // Call Read before accessing data.
           while (reader.Read())
           {
               DataRow dataRow = ResultsData1.NewRow();
               for (int i = 0; i < listCols.Count; i++)
               {
                   dataRow[(listCols[i])] = reader[i];
               }
               ResultsData1.Rows.Add(dataRow);
               c++;
               if (c == rowsPerSheet)
               {
                   c = 0;
                   ExportToOxml(firstTime);
                   ResultsData1.Clear();
                   firstTime = false;
               }
           }
           if (ResultsData1.Rows.Count > 0)
           {
               ExportToOxml(firstTime);
               ResultsData1.Clear();
           }
           // Call Close when done reading.
           reader.Close();

       }

Я также создал функцию для загрузки файла как
Эта функция загружает данные 200 строк на каждый лист

private static void ExportToOxml(bool firstTime)
        {
            const string fileName = @"E:\MyExcel1.xlsx";

            //Delete the file if it exists. 
            if (firstTime && File.Exists(fileName))
            {
                File.Delete(fileName);
            }

            uint sheetId = 1; //Start at the first sheet in the Excel workbook.

            if (firstTime)
            {
                //This is the first time of creating the excel file and the first sheet.
                // Create a spreadsheet document by supplying the filepath.
                // By default, AutoSave = true, Editable = true, and Type = xlsx.
                SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(fileName, SpreadsheetDocumentType.Workbook);

                // Add a WorkbookPart to the document.
                WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
                workbookpart.Workbook = new Workbook();

                // Add a WorksheetPart to the WorkbookPart.
                var worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
                var sheetData = new SheetData();
                worksheetPart.Worksheet = new Worksheet(sheetData);


                var bold1 = new Bold();
                CellFormat cf = new CellFormat();


                // Add Sheets to the Workbook.
                Sheets sheets;
                sheets = spreadsheetDocument.WorkbookPart.Workbook.
                    AppendChild<Sheets>(new Sheets());

                // Append a new worksheet and associate it with the workbook.
                var sheet = new Sheet()
                {
                    Id = spreadsheetDocument.WorkbookPart.
                        GetIdOfPart(worksheetPart),
                    SheetId = sheetId,
                    Name = "Sheet" + sheetId
                };
                sheets.Append(sheet);

                //Add Header Row.
                var headerRow = new Row();
                foreach (DataColumn column in ResultsData1.Columns)
                {
                    var cell = new Cell
                    {
                        DataType = CellValues.String,
                        CellValue = new CellValue(column.ColumnName)
                    };
                    headerRow.AppendChild(cell);
                }
                sheetData.AppendChild(headerRow);

                foreach (DataRow row in ResultsData1.Rows)
                {
                    var newRow = new Row();
                    foreach (DataColumn col in ResultsData1.Columns)
                    {
                        var cell = new Cell
                        {
                            DataType = CellValues.String,
                            CellValue = new CellValue(row[col].ToString())
                        };
                        newRow.AppendChild(cell);
                    }

                    sheetData.AppendChild(newRow);
                }

                ResultsData1.Clear();
                workbookpart.Workbook.Save();

                spreadsheetDocument.Close();
            }
            else
            {
                // Open the Excel file that we created before, and start to add sheets to it.
                var spreadsheetDocument = SpreadsheetDocument.Open(fileName, true);

                var workbookpart = spreadsheetDocument.WorkbookPart;
                if (workbookpart.Workbook == null)
                    workbookpart.Workbook = new Workbook();

                var worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
                var sheetData = new SheetData();
                worksheetPart.Worksheet = new Worksheet(sheetData);
                var sheets = spreadsheetDocument.WorkbookPart.Workbook.Sheets;

                if (sheets.Elements<Sheet>().Any())
                {
                    //Set the new sheet id
                    sheetId = sheets.Elements<Sheet>().Max(s => s.SheetId.Value) + 1;
                }
                else
                {
                    sheetId = 1;
                }

                // Append a new worksheet and associate it with the workbook.
                var sheet = new Sheet()
                {
                    Id = spreadsheetDocument.WorkbookPart.
                        GetIdOfPart(worksheetPart),
                    SheetId = sheetId,
                    Name = "Sheet" + sheetId
                };
                sheets.Append(sheet);

                //Add the header row here.
                var headerRow = new Row();

                foreach (DataColumn column in ResultsData1.Columns)
                {
                    var cell = new Cell
                    {
                        DataType = CellValues.String,
                        CellValue = new CellValue(column.ColumnName)
                    };
                    headerRow.AppendChild(cell);
                }
                sheetData.AppendChild(headerRow);

                foreach (DataRow row in ResultsData1.Rows)
                {
                    var newRow = new Row();

                    foreach (DataColumn col in ResultsData1.Columns)
                    {
                        var cell = new Cell
                        {
                            DataType = CellValues.String,
                            CellValue = new CellValue(row[col].ToString())
                        };
                        newRow.AppendChild(cell);
                    }

                    sheetData.AppendChild(newRow);
                }

                workbookpart.Workbook.Save();

                // Close the document.
                spreadsheetDocument.Close();
                ResultsData1.Clear();
            }
        }

Richard MacCutchan

Какую часть этого сообщения об ошибке вы не понимаете?

Suvendu Shekhar Giri

интересно то же самое :P

1 Ответов

Рейтинг:
9

Richard Deeming

Ваша хранимая процедура, USP_Report, возвращает два столбца, называемых "Идентификатор встречи клиента".

Один DataTable не может содержать два столбца с одинаковым именем.

Исправьте хранимую процедуру так, чтобы возвращаемые имена столбцов были уникальными.

Или исправьте свой код, чтобы проверить наличие дубликатов столбцов и переименовать их, если это необходимо:

foreach (DataRow drow in dtSchema.Rows)
{
    string rawColumnName = Convert.ToString(drow["ColumnName"]);
    
    int duplicateCount = 1;
    string columnName = rawColumnName;
    while (ResultsData1.Columns.Contains(columnName))
    {
        columnName = rawColumnName + " (" + duplicateCount + ")";
        duplicateCount++;
    }
    
    ...

NB: Вы также столкнетесь с проблемами, если несколько пользователей попытаются экспортировать данные одновременно, так как все запросы будут пытаться записать их в один и тот же файл. Вы можете закончить тем, что файл исчезнет, или данные из запросов разных пользователей будут перепутаны в одном файле.

Вы должны посмотреть, есть ли возможность создать файл в памяти, не сохраняя его на диске. Если нет, то вы должны использовать случайный файл для каждого пользователя и обязательно удалить его после использования TransmitFile / WriteFile чтобы отправить его пользователю.


РЕДАКТИРОВАТЬ: Проблема в том, что DataTable хранится в static поле. Это означает, что каждый запрос от каждый пользователь будет манипулировать тем же самым DataTable пример. При одновременном доступе нескольких пользователей к сайту вы, скорее всего, получите гораздо больше неясных и запутанных ошибок, поскольку изменения пользователей перезаписывают друг друга.

Снять static поле, а вместо него используйте локальную переменную. Вам нужно будет передать его в ExportToOxml метод как параметр.
private static void ExportToOxml(bool firstTime, DataTable ResultsData1)
{
    ...
}

protected void btnmeeting_Click(object sender, EventArgs e)
{
    DataTable ResultsData1 = new DataTable();
    ...
}

(Комментарий о конфликтах имен файлов все еще остается в силе.)


paul_vin

На самом деле, когда пользователь входит в систему, то время кулака, он загружает файл без каких-либо проблем.
Но когда во второй раз пользователь нажимает на кнопку загрузки, то он выдает вышеуказанную ошибку даже после того, как я очистил таблицу данных. так что же мне для этого делать? кроме того, я хочу развернуть
это решение на живом проекте в то время должно быть загружено любым клиентом на клиентской машине в папке Загрузки так. Итак, какой путь я должен дать для загрузки на клиентскую машину

Richard Deeming

Хорошо, я вижу проблему: вы храните DataTable в static поле.

Те средства каждый запрос от каждый пользователь будет использовать то же самое DataTable пример.

Я могу только предположить, что вы все еще тестируете этот код в Visual Studio. Если бы вы развернули его, я ожидал бы увидеть гораздо более неясные ошибки, поскольку несколько запросов пытались бы манипулировать одним и тем же объектом одновременно.

Удалите статическое поле и используйте вместо него локальную переменную. Вам нужно будет передать его в ExportToOxml метод как параметр.

paul_vin

Во первых спасибо за вышеуказанное решение
Как я должен ограничить загрузку одного пользователя за раз.
не могли бы вы предоставить мне код и где я должен интегрироваться?
кроме того, я использовал статический путь здесь, но я хочу динамический путь, так что же я изменяю
надо делать и где

Richard Deeming

Не ограничивайте его одним пользователем. Снять static поле и используйте локальную переменную. Таким образом, не будет никаких проблем с одновременной загрузкой данных несколькими пользователями.

Чтобы использовать динамический путь, просто создайте случайное имя файла:

string folder = System.IO.Path.GetTempPath();
string fileName = System.IO.Path.Combine(folder, Guid.NewGuid().ToString("N") + ".xlsx");

Когда вы используете TransmitFile или WriteFile чтобы отправить файл пользователю, вы можете использовать Content-Disposition заголовок для установки имени файла:
response.AddHeader("Content-Disposition", "attachment; filename=Report.xlsx");
response.TransmitFile(fileName);