Обзор этого ниже.Некоторые вещи могут различаться в зависимости от вашей среды и того, как вы хотите регистрировать имена папок и файлов, в которых были ошибки, но это должно помочь вам начать работу в правильном направлении.
СозданиеПеременная int, вы можете вызвать это «ErrorCount» и убедиться, что его значение установлено равным 0. Это будет использовано позже в журнале ошибок.
Создайте задачу «Выполнение SQL», которая создасттаблица, которая будет использоваться для хранения папки и имени файла.«Имя файла» - это ключевое слово в T-SQL, поэтому используются идентификаторы (квадратные скобки).Они не обязательны, но облегчают чтение.
- Поскольку вы уже используете цикл Foreach для загрузки файлов, я предполагаю, что переменная уже сопоставлена для хранения файлаимя для каждой итерации.Если вы этого не сделали, добавьте строковую переменную с индексом 0 на панели «Переменные переменные» цикла Foreach.
В задаче потока данных, загружающей файлы, добавьте обработчик событий OnError
с задачей скрипта C #.В редакторе задач сценария добавьте строковую переменную, содержащую имя файла (индекс 0 в цикле Foreach) в поле ReadOnlyVariables
.В поле ReadWriteVariables
добавьте созданную ранее переменную «ErrorCount» и системную переменную System::Propagate
.Это будет использовано позже, чтобы разрешить обработку последующих файлов после ошибки.
Код для этой задачи сценария приведен ниже в этом посте.Вам нужно будет добавить ссылки на пространства имен System.IO
и System.Data.SqlClient
.Событие OnError запускается один раз для каждой ошибки , а не только тогда, когда был файл с ошибкой.В этом примере имя файла регистрируется только в том случае, если пользовательская переменная «ErrorCount» имеет значение 0. После того, как файл и папка зарегистрированы, эта переменная устанавливается в 1, чтобы избежать одновременной регистрации одного и того же файла несколько раз.Методы Path.GetDirectoryName
и Path.GetFileName
используются для получения имен папок и файлов соответственно.Хотя все загружаемые вами файлы, скорее всего, имеют одинаковое расширение, Path.GetFileName
по-прежнему используется для возврата расширения файла с именем файла.Если вы не хотите видеть расширение файла, используйте метод Path.GetFileNameWithoutExtension
.
SSPI
установлено для встроенной безопасности, чтобы указать, что будет использоваться аутентификация Windows.Чтобы использовать проверку подлинности SQL Server, установите для нее значение false
и добавьте соответствующие значения для свойств User ID
и Password
.Я бы рекомендовал использовать параметры, то есть объекты SqlParameter
ниже, вместо того, чтобы создавать команду SQL в виде объединенной строки.Ввод по умолчанию ParameterDirection
, но они все еще определены для ясности.Этот сценарий берет проанализированные имена папок и файлов и вставляет их в таблицу, в данном примере с именем ErrorFiles
, которая будет использоваться для хранения файлов, в которых возникли ошибки во время выполнения пакета, до их записи в файл.Хотя вставка с помощью задачи «Выполнение SQL» будет проще, методы в пространстве имен System.IO
позволяют корректно получить имя папки и файла при изменении пути к файлу.Если используемая папка никогда не изменяется, можно выполнить задачу «Выполнение SQL» с функцией T-SQL SUBSTRING
во вставке, чтобы проанализировать имя папки и файла из переменной, в которой они хранятся.
После задачи потока данных добавьте еще одну задачу сценария в цикл по каждому элементу.Подключите это к Задаче потока данных и измените операцию оценки для Ограничение приоритета на Выражение и добавьте выражение ниже.Это обеспечит выполнение следующей задачи сценария только в том случае, если во время этой итерации цикла Foreach произошла ошибка, путем проверки значения переменной «ErrorCount».
В этой задаче сценариядобавьте «ErrorCount» в поле ReadWriteVariables
и аналогично установке этого значения в 1 ранее, теперь установите его обратно в 0 (Dts.Variables["User::ErrorCount"].Value = 0
).Это делается для того, чтобы файлы, которые приводят к ошибке в последующих итерациях цикла Foreach, также регистрировались.
После цикла по каждому элементу добавьте задачу потока данных с источником OLE DB.Установите для режима доступа к данным команду SQL и выберите столбцы FolderName и FileName из таблицы, в которой хранятся файлы с ошибками.Если вы не создали эту таблицу отдельно, вы можете установить для ValidateExternalMetadata
значение false и добавить выходные столбцы в папку «Внешние и выходные столбцы» на вкладке «Свойства ввода и вывода» в расширенном редакторе.Однако, если вы не знакомы с этим, может быть проще просто запустить CREATE TABLE
DDL и определить метаданные таким образом.В этой задаче потока данных добавьте пункт назначения плоского файла, который подключен к источнику OLE DB.Создайте новый диспетчер плоских файлов с именем файла, который вы хотите использовать для хранения имен файлов, содержащих ошибки.Вы можете захотеть использовать выражение в имени файла, чтобы сделать его уникальным при каждом выполнении пакета.Пример выражения приведен ниже в этом посте.Это просто использует текущую дату.Если вы планируете запускать это несколько раз в течение одного дня, вы можете добавить временную метку или иным образом сделать каждое имя файла уникальным.Это можно установить в качестве имени выходного файла, добавив это выражение в переменную и используя его в качестве свойства ConnectionString
диспетчера плоских файлов.
Затем добавьте Execute SQLЗадача, следующая за этой задачей потока данных.Для SQLStatement
добавьте SQL, чтобы удалить таблицу, в которой хранятся имена файлов с ошибками, если таковые существуют.Хотя в этом нет необходимости, поскольку первоначальная задача, которая создает эту таблицу, удаляет ее, это позволяет избежать наличия дополнительной таблицы в вашей базе данных.
Выражение ограничения предшествования:
@[User::ErrorCount] > 0
Выражение строки подключения диспетчера соединений с плоскими файлами:
"C:\\Your Folder\\" + (DT_STR, 4, 1252)DATEPART("Year", GETDATE()) + "_"
+ (DT_STR, 2, 1252)DATEPART("Month", GETDATE()) + "_"
+ (DT_STR, 2, 1252)DATEPART("Day", GETDATE()) +"_"
+ "ErrorFiles.txt"
Таблица файлов ошибок DDL:
IF(OBJECT_ID(N'YourDatabase.DBO.ERRORFILES') IS NOT NULL)
BEGIN
DROP TABLE YourDatabase.DBO.ERRORFILES
END
CREATE TABLE YourDatabase.DBO.ERRORFILES
(
FOLDERNAME VARCHAR(100),
[FILENAME] VARCHAR(100)
)
Код задачи сценария обработчика события OnError:
if (Convert.ToInt32(Dts.Variables["User::ErrorCount"].Value.ToString()) == 0)
{
string connString = @"Data Source=YourSQLServerInstance;Initial Catalog=YourDatabase;Integrated Security=SSPI";
string cmd = @"Insert into dbo.ErrorFiles (FolderName,[FileName]) values (@folderName, @fileName)";
//parse variable with file that caused error
string errorFileFullName = Dts.Variables["User::NameForTable"].Value.ToString();
//get folder
string errorFolderName = Path.GetDirectoryName(errorFileFullName);
//get only file name
string errorFileName = Path.GetFileName(errorFileFullName);
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand sql = new SqlCommand(cmd, conn);
SqlParameter pFolderName = new SqlParameter("@folderName", SqlDbType.VarChar);
pFolderName.Direction = ParameterDirection.Input;
pFolderName.Value = errorFolderName;
pFolderName.Size = 100;
SqlParameter pFileName = new SqlParameter("@fileName", SqlDbType.VarChar);
pFileName.Direction = ParameterDirection.Input;
pFileName.Value = errorFileName;
pFileName.Size = 100;
sql.Parameters.Add(pFolderName);
sql.Parameters.Add(pFileName);
conn.Open();
sql.ExecuteNonQuery();
//avoid failing Foreach Loop so other files are processed
Dts.Variables["System::Propagate"].Value = false;
//prevent event handler from firing multiple times.
Dts.Variables["User::ErrorCount"].Value = 1;
}
}