BIML SSIS ScriptTask как источник данных — ошибка с OutputBuffer

Я получаю следующую ошибку при попытке создать пакет через BIML, используя ScriptTask в качестве источника данных. У меня есть большой (около 5 ГБ) файл XML для загрузки, и я хотел использовать StreamReader для загрузки данных в базу данных.

«Output0Buffer» не содержит определения для «PORTF_LIST», и не удалось найти метод расширения «PORTF_LIST», принимающий первый аргумент типа «Output0Buffer» (вам не хватает директивы using или ссылки на сборку?).

Это происходит для каждого столбца. Столбцы являются динамическими и исходят из отдельного метода в классе С#, который смотрит на dacpac, поэтому везде должны быть одинаковые имена и регистры.

Пример файла, как показано ниже:

<ANALYTICS>
  <INSTRUMENTS ASOF_DATE="3/31/2017" CREATE_DATE="4/2/2017" RECORDS="3763">
    <INSTRUMENT>
      <PORTF_LIST>XX1245897</PORTF_LIST>
      <PRT_FULL_NAME>Convertible Bonds</PRT_FULL_NAME>
      <ISIN>11803384</ISIN>
    </INSTRUMENT>
     </INSTRUMENTS>
</ANALYTICS>

Буфер вывода определяется, как показано ниже (есть 250 нечетных столбцов, но все они следуют одному и тому же шаблону:

           <OutputBuffers>
                <OutputBuffer Name="Output0" IsSynchronous="false">
                    <Columns>
<Column Name="PORTF_LIST" DataType="String" Length="255"/>
<Column Name="PRT_FULL_NAME" DataType="String" Length="255"/>
<Column Name="ISIN" DataType="String" Length="255"/>
                    </Columns>                    
                </OutputBuffer>                                 
            </OutputBuffers>   

Код задачи скрипта, в который я пытаюсь добавить в буфер, приведен ниже:

    <#@ property name="Elements" type="String" #>  
    <#@ property name="Columns" type="String" #>  
    <#@ property name="BufferColumns" type="String" #>  
    <#@ property name="RootElement" type="String" #>  
    <ScriptComponentProject ProjectCoreName="SC_eb1debcd2374468ebccbbfad4fbe5976" Name="XmlSource">
              <AssemblyReferences>
                <AssemblyReference AssemblyPath="Microsoft.SqlServer.DTSPipelineWrap" />
                <AssemblyReference AssemblyPath="Microsoft.SqlServer.DTSRuntimeWrap" />
                <AssemblyReference AssemblyPath="Microsoft.SqlServer.PipelineHost" />
                <AssemblyReference AssemblyPath="Microsoft.SqlServer.TxScript" />                  
                <AssemblyReference AssemblyPath="Microsoft.SqlServer.ManagedDTS.dll" />
                <AssemblyReference AssemblyPath="Microsoft.SqlServer.ScriptTask.dll" />
                <AssemblyReference AssemblyPath="System.dll" />
                <AssemblyReference AssemblyPath="System.AddIn.dll" />
                <AssemblyReference AssemblyPath="System.Data.dll" />
                <AssemblyReference AssemblyPath="System.Windows.Forms.dll" />
                <AssemblyReference AssemblyPath="System.Xml.dll" />
                <AssemblyReference AssemblyPath="System.Xml.Linq.dll" />
                <AssemblyReference AssemblyPath="System.Core.dll" />
             </AssemblyReferences>
            <OutputBuffers>
                <!--    
                Define what your buffer is called and what it looks like
                Must set IsSynchronous as false. Otherwise it is a transformation
                (one row enters, one row leaves) and not a source.
                -->
                <OutputBuffer Name="Output0" IsSynchronous="false">
                    <Columns>
                        <#=BufferColumns#>
                    </Columns>                    
                </OutputBuffer>                                 
            </OutputBuffers>              
              <Files>
                <File Path="Properties\AssemblyInfo.cs">
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyTitle("XmlSource")]
[assembly: AssemblyDescription("Script Component as source")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("XmlSource")]
[assembly: AssemblyCopyright("Copyright @ 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.0.*")]
</File>
<File Path="main.cs">
<![CDATA[

using System;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
using System.Security;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Windows.Forms;

[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{

        public override void PreExecute()
        {
            base.PreExecute();

        }

        public override void PostExecute()
        {
            base.PostExecute();
        }

        public string sourceFile =  Dts.Variables["User::FileName"].Value.ToString();

        public override void CreateNewOutputRows()
        {
            foreach (var myXmlData in (
                   from elements in StreamReader(sourceFile, "INSTRUMENT")
                   select new 
                        {
PORTF_LIST = elements.Element("PORTF_LIST").Value,
PRT_FULL_NAME = elements.Element("PRT_FULL_NAME").Value,
ISIN = elements.Element("ISIN").Value

                        }
                ))
                {
                    try
                    {
                        Output0Buffer.AddRow();
    Output0Buffer.PORTF_LIST = myXmlData.PORTF_LIST;
    Output0Buffer.PRT_FULL_NAME = myXmlData.PRT_FULL_NAME;
    Output0Buffer.ISIN = myXmlData.ISIN;
                    }
                    catch (Exception e)
                    {
                        string errorMessage = string.Format("Data retrieval failed: {0}", e.Message);
                        bool cancel;
                        ComponentMetaData.FireError(0, ComponentMetaData.Name, errorMessage,string.Empty,0, out cancel);
                    }

                }


        }


        public static IEnumerable<XElement> StreamReader(String filename, string elementName)
        {

                         // Create an XML reader for this file.
                        using (XmlReader reader = XmlReader.Create(filename))
                        {
                            reader.MoveToContent(); // will not advance reader if already on a content node; if successful, ReadState is Interactive
                            reader.Read();          // this is needed, even with MoveToContent and ReadState.Interactive
                            while(!reader.EOF && reader.ReadState == ReadState.Interactive)
                            {
                                if(reader.NodeType == XmlNodeType.Element && reader.Name.Equals(elementName))
                                {
                                     // this advances the reader...so it's either XNode.ReadFrom() or reader.Read(), but not both
                                     var matchedElement = XNode.ReadFrom(reader) as XElement;
                                     if(matchedElement != null)
                                         yield return matchedElement;
                                }
                                else
                                    reader.Read();
                            }
                            reader.Close();

                        }
        }

}
]]>
                </File>
              </Files>
              <ReadOnlyVariables>
                  <Variable Namespace="User" DataType="String" VariableName="FileName" />
              </ReadOnlyVariables>
              <ReadWriteVariables>
              </ReadWriteVariables>
            </ScriptComponentProject>

Я проверил код в консольном приложении, и он отлично читает файл XML, но не повезло с BIML. Есть около 250 нечетных столбцов, поэтому я стараюсь не делать это вручную, поэтому, если у вас есть какие-либо идеи, что я делаю неправильно, я был бы очень признателен!


person guytz72    schedule 05.12.2017    source источник
comment
Беглый взгляд через него, вещи выглядят приблизительно. Что меня задерживает, так это то, откуда берется ссылка на ColumnName. Я постараюсь выкроить немного времени после работы, чтобы получить рабочий репро. Есть ли шанс, что вы можете добавить образец содержимого sourceFile в вопрос?   -  person billinkc    schedule 05.12.2017
comment
Извини, Билл, мой плохой. Я исправил вопрос, теперь я удалил все столбцы для краткости, просто используя ColumnName в качестве примера. Эта ошибка возникает один раз для каждого столбца, который я назначаю столбцу буфера ниже: Output0Buffer.PORTF_LIST = myXmlData.PORTF_LIST; Output0Buffer.PRT_FULL_NAME = myXmlData.PRT_FULL_NAME; Output0Buffer.ISIN = myXmlData.ISIN; Я постараюсь получить урезанную версию файла.   -  person guytz72    schedule 06.12.2017
comment
В настоящее время я сталкиваюсь с аналогичной проблемой: я читаю определение таблицы из БД и хочу создать столбец вывода для каждого столбца в таблице. В моем сценарии biml в моих ‹columns›‹/columns› я перебираю свою коллекцию столбцов (foreach DataRow col in...), но получаю некоторую ошибку, например, текст не разрешен в столбцах.... Как вы построили свой ‹#=BufferColumns#›?   -  person Tyron78    schedule 21.12.2017


Ответы (1)


Кажется, задача скрипта не любит символы подчеркивания в OutputBuffer.

Я создал пакет-заглушку вручную, и при присвоении значения intellisense использовал PORTFLIST, а не PORTF_LIST.

Таким образом, этот фрагмент кода должен быть:

Output0Buffer.AddRow();
Output0Buffer.PORTFLIST = myXmlData.PORTF_LIST;
Output0Buffer.PRTFULLNAME = myXmlData.PRT_FULL_NAME;
Output0Buffer.ISIN = myXmlData.ISIN

У меня есть еще одна ошибка, моя любимая "EmitSsis. Внутренняя ошибка компилятора: рабочий процесс EmitSsis содержит фатальные ошибки", но, по крайней мере, эта решена!

Спасибо, Билл, за вашу помощь, и извините, что завел вас по дорожке сада с неправильным именем столбца в опубликованной ошибке, иначе вы, вероятно, знали бы об этой проблеме!

person guytz72    schedule 06.12.2017
comment
Не беспокойтесь, вы обогатили вселенную для следующего поколения людей, столкнувшихся с ошибкой. ;) - person billinkc; 06.12.2017