Scripting avanzado
Esta es una introducción a las capacidades de scripting de Tabular Editor. Todo lo que aparece a continuación se aplica a ambos productos, pero los nombres difieren: lo que Tabular Editor 2 llama Scripting avanzado, en Tabular Editor 3 se denomina C# Scripts, con un editor dedicado, IntelliSense, un depurador de scripts y macros guardadas. Consulta C# Scripts para la experiencia en Tabular Editor 3 y Biblioteca de scripts de C# para ver ejemplos reales.
¿Qué es el scripting avanzado?
El objetivo de la interfaz de usuario de Tabular Editor es facilitar la ejecución de la mayoría de las tareas habituales al crear modelos tabulares. Por ejemplo, cambiar la carpeta de visualización de varias medidas a la vez es tan sencillo como seleccionar los objetos en el árbol del explorador y arrastrarlos y soltarlos para reorganizarlos. El menú contextual al hacer clic con el botón derecho del árbol del explorador ofrece una forma práctica de realizar muchas de estas tareas, como agregar o quitar objetos de las perspectivas, cambiar el nombre de varios objetos, etc.
Aun así, hay muchas otras tareas habituales del flujo de trabajo que no se realizan con la misma facilidad desde la interfaz de usuario. Por este motivo, Tabular Editor incorpora el scripting avanzado, que permite a los usuarios avanzados escribir un script con sintaxis de C# para manipular de forma más directa los objetos del modelo tabular cargado.
Objetos
La API de scripting proporciona acceso a dos objetos de nivel superior: Model y Selected. El primero contiene métodos y propiedades que te permiten manipular todos los objetos del modelo tabular, mientras que el segundo expone solo los objetos seleccionados actualmente en el árbol del explorador.
El objeto Model es un envoltorio de la clase Microsoft.AnalysisServices.Tabular.Model, que expone un subconjunto de sus propiedades, con algunos métodos y propiedades adicionales para facilitar las operaciones con traducciones, perspectivas y colecciones de objetos. Lo mismo se aplica a cualquier objeto derivado, como tabla, medida, columna, etc., que cuentan con su correspondiente objeto envoltorio. Consulta Scripting API para ver una lista completa de objetos, propiedades y métodos de la biblioteca de envoltorios de Tabular Editor.
La principal ventaja de trabajar a través de este envoltorio es que todos los cambios se pueden deshacer desde la interfaz de usuario de Tabular Editor. Pulsa Ctrl+Z después de ejecutar un script para deshacer todos los cambios que haya realizado el script. En Tabular Editor 3, el foco permanece en el editor de scripts después de ejecutar el script, así que haz clic en el Explorador TOM antes de pulsar Ctrl+Z. Consulta Deshacer en editores de texto. Además, este envoltorio ofrece métodos prácticos que convierten muchas tareas habituales en sencillas instrucciones de una sola línea. A continuación veremos algunos ejemplos. Damos por hecho que ya tienes cierta familiaridad con C# y LINQ, ya que estos aspectos de las capacidades de scripting de Tabular Editor no se tratarán aquí. Los usuarios que no estén familiarizados con C# y LINQ deberían poder seguir los ejemplos que se muestran a continuación.
Configurar las propiedades de los objetos
Si quieres cambiar la propiedad de un objeto en concreto, obviamente la forma más sencilla es hacerlo directamente desde la interfaz de usuario. Pero, a modo de ejemplo, veamos cómo podríamos conseguir lo mismo mediante un script.
Supongamos que quieres cambiar la cadena de formato de tu medida [Sales Amount] en la tabla 'FactInternetSales'. Si localizas la medida en el árbol del explorador, puedes arrastrarla directamente al editor de scripts. Tabular Editor generará entonces el siguiente código, que representa esta medida concreta en el Tabular Object Model:
Model.Tables["FactInternetSales"].Measures["Sales Amount"]
Añadir un punto (.) adicional después del corchete situado más a la derecha, debería aparecer el menú de autocompletado, mostrándote qué propiedades y métodos existen en esta medida concreta. Simplemente elige "FormatString" en el menú, o escribe las primeras letras y pulsa Tab. Luego, escribe un signo igual seguido de "0.0%". Cambiemos también la carpeta de visualización de esta medida. El código final debería quedar así:
Model.Tables["FactInternetSales"].Measures["Sales Amount"].FormatString = "0.0%";
Model.Tables["FactInternetSales"].Measures["Sales Amount"].DisplayFolder = "New Folder";
Nota: Recuerda poner el punto y coma (;) al final de cada línea. Es un requisito de C#. Si lo olvidas, recibirás un mensaje de error de sintaxis al intentar ejecutar el script.
Pulsa F5 o el botón "Play" situado encima del editor de scripts para ejecutar el script. Al instante, deberías ver cómo la medida se mueve por el árbol del explorador, reflejando el cambio en la carpeta de visualización. Si examinas la medida en la cuadrícula de propiedades, también deberías ver que la propiedad de la cadena de formato ha cambiado en consecuencia.
Trabajar con varios objetos a la vez
Muchos objetos del modelo de objetos son, en realidad, colecciones de varios objetos. Por ejemplo, cada objeto Table tiene una colección de medidas llamada "Measures". El wrapper expone una serie de propiedades y métodos prácticos de estas colecciones, lo que facilita establecer la misma propiedad en varios objetos a la vez. Esto se describe en detalle más abajo. Además, puedes usar todos los métodos de extensión estándar de LINQ para filtrar y recorrer los objetos de una colección.
A continuación se muestran algunos ejemplos de los métodos de extensión de LINQ más usados:
Collection.First([predicate])Devuelve el primer objeto de la colección que cumpla la condición opcional [predicate].Collection.Any([predicate])Devuelvetruesi la colección contiene algún objeto (opcionalmente, que cumpla la condición [predicate]).Collection.Where(predicate)Devuelve una colección que corresponde a la colección original filtrada por la condición del predicado.Collection.Select(map)Proyecta cada objeto de la colección en otro objeto según elmapespecificado.Collection.ForEach(action)Ejecuta la acción especificada sobre cada elemento de la colección.
En los ejemplos anteriores, predicate es una expresión lambda que toma un único objeto como entrada y devuelve un valor booleano como salida. Por ejemplo, si Collection es una colección de medidas, un predicate típico podría ser:
m => m.Name.Contains("Reseller")
Este predicate solo devolvería true si la propiedad Name de la medida contiene la cadena de caracteres "Reseller". Si necesitas una lógica más avanzada, envuelve la expresión entre llaves y usa la palabra clave return:
.Where(obj => {
if(obj is Column) {
return false;
}
return obj.Name.Contains("test");
})
Volviendo a los ejemplos anteriores, map es una expresión lambda que toma un único objeto como entrada y devuelve un único objeto como salida. action es una expresión lambda que toma un único objeto como entrada, pero no devuelve ningún valor.
Usa la funcionalidad de IntelliSense del editor de scripts avanzado para ver qué otros métodos de LINQ existen, o consulta la documentación de LINQ-to-Objects.
Trabajar con el objeto Model
Para hacer referencia rápidamente a cualquier objeto del modelo tabular cargado actualmente, puedes arrastrar y soltar el objeto desde el árbol del explorador hasta el editor de scripts avanzado:

Consulta la documentación de TOM para ver un resumen de las propiedades disponibles en Model y en sus objetos descendientes. Además, consulta Scripting API para ver un listado completo de las propiedades y métodos expuestos por el objeto contenedor.
Trabajar con el objeto Selected
Poder referirte explícitamente a cualquier objeto del Modelo tabular es ideal para algunos flujos de trabajo, pero a veces quieres seleccionar objetos concretos del árbol del explorador y luego ejecutar un script solo sobre los objetos seleccionados. Aquí es donde el objeto Selected resulta muy útil.
El objeto Selected proporciona una serie de propiedades que facilitan identificar la selección actual, así como limitarla a objetos de un tipo determinado. Al navegar con las carpetas de visualización, si hay una o varias carpetas seleccionadas en el árbol del explorador, todos sus elementos secundarios también se consideran seleccionados.
Para selecciones únicas, usa el nombre en singular del tipo de objeto al que quieres acceder. Por ejemplo,
Selected.Hierarchy
hace referencia a la jerarquía seleccionada actualmente en el árbol, siempre que haya seleccionada una única jerarquía. Usa el nombre del tipo en plural si quieres trabajar con selecciones múltiples:
Selected.Hierarchies
Todas las propiedades que existen en el objeto singular también existen en su forma plural, con algunas excepciones. Esto significa que puedes establecer el valor de estas propiedades para varios objetos a la vez, con una sola línea de código y sin usar los métodos de extensión LINQ mencionados anteriormente. Por ejemplo, supongamos que quieres mover todas las medidas seleccionadas actualmente a una nueva carpeta de visualización llamada "Test":
Selected.Measures.DisplayFolder = "Test";
Si actualmente no hay medidas seleccionadas en el árbol, el código anterior no hace nada y no se produce ningún error. De lo contrario, la propiedad DisplayFolder se establecerá en "Test" para todas las medidas seleccionadas (incluso para las medidas que estén dentro de carpetas, ya que el objeto Selected también incluye los objetos de las carpetas seleccionadas). Si usas la forma singular Measure en lugar de Measures, obtendrás un error, salvo que la selección actual contenga exactamente una medida.
Aunque no se puede establecer la propiedad Name de varios objetos a la vez, aún tienes algunas opciones. Si solo quieres reemplazar todas las apariciones de una cadena de caracteres por otra, puedes usar el método "Rename" incluido, de esta forma:
Selected.Measures
.Rename("Amount", "Value");
Esto reemplazaría cualquier aparición de la palabra "Amount" por "Value" en los nombres de todas las medidas seleccionadas actualmente. Como alternativa, puedes usar el método ForEach() de LINQ, tal y como se describe arriba, para incluir una lógica más avanzada:
Selected.Measures
.ForEach(m => { if(m.Name.Contains("Reseller")) m.Name += " DEPRECATED"; });
Este ejemplo añadirá el texto " DEPRECATED" al final de los nombres de todas las medidas seleccionadas cuyos nombres contengan la palabra "Reseller". Como alternativa, puedes usar el método de extensión Where() de LINQ para filtrar la colección antes de aplicar la operación ForEach(), lo que daría exactamente el mismo resultado:
Selected.Measures
.Where(m => m.Name.Contains("Reseller"))
.ForEach(m => m.Name += " DEPRECATED");
Métodos auxiliares
Para facilitar la depuración de scripts, Tabular Editor ofrece un conjunto de métodos auxiliares especiales. Internamente, se trata de métodos estáticos decorados con el atributo [ScriptMethod]. Este atributo permite que los scripts llamen a los métodos directamente, sin necesidad de especificar un espacio de nombres o un nombre de clase. Los complementos también pueden usar el atributo [ScriptMethod] para exponer métodos estáticos públicos para su uso en scripts, de forma similar.
Algunos de ellos pueden invocarse como métodos de extensión, por lo que object.Output(); y Output(object); son equivalentes.
Los que usarás con más frecuencia son Output() para inspeccionar un objeto en mitad del script; Info(), Warning() y Error() para mensajes; SaveFile() y ReadFile() para datos de texto; y ExportProperties() / ImportProperties() para exportar e importar valores de propiedades como TSV.
Métodos auxiliares de C# Script es la lista actualizada de todos los métodos auxiliares con su firma completa. Úsala en lugar del resumen que aparece aquí.
Depuración de scripts
Como se mencionó anteriormente, puedes usar el método Output(object); para pausar la ejecución del script y abrir un cuadro de diálogo con información sobre el objeto pasado como argumento. También puedes usar este método como método de extensión, invocándolo como object.Output();. El script se reanuda cuando se cierra el cuadro de diálogo.
El cuadro de diálogo aparecerá de una de estas cuatro formas, según el tipo de objeto que se envíe como salida:
- Los objetos individuales (como string, int y DateTime, excepto cualquier objeto que derive de TabularNamedObject) se mostrarán como un cuadro de diálogo de mensaje sencillo, invocando el método
.ToString()del objeto:

- Los TabularNamedObjects individuales (como tablas, medidas o cualquier otro NamedMetadataObject de TOM disponible en Tabular Editor) se mostrarán en una cuadrícula de propiedades, similar a cuando se ha seleccionado un objeto en el Tree Explorer. Las propiedades del objeto se pueden editar en la cuadrícula, pero ten en cuenta que, si se produce un error más adelante durante la ejecución del script, la edición se deshará automáticamente si "Rollback on error" está habilitado:

- Cualquier IEnumerable de objetos (excepto TabularNamedObjects) se mostrará en una lista, donde cada elemento de la lista muestra el valor de
.ToString()y el tipo del objeto en el IEnumerable:

- Cualquier IEnumerable de TabularNamedObjects hará que el cuadro de diálogo muestre una lista de los objetos a la izquierda y una cuadrícula de propiedades a la derecha. La cuadrícula de propiedades se rellenará con el objeto seleccionado en la lista, y las propiedades se pueden editar igual que cuando se envía a la salida un único TabularNamedObject:

Puedes marcar la casilla "Don't show more outputs" en la esquina inferior izquierda para evitar que el script se detenga en futuras invocaciones de .Output().
Referencias de «.NET»
Los scripts admiten la palabra clave using para acortar los nombres de clase, igual que el código fuente normal de C#, y pueden incorporar ensamblados externos con #r "<assembly name or DLL path>", la misma sintaxis que usan los scripts .csx.
Por ejemplo, el siguiente script ahora funcionará como se espera:
// Assembly references must be at the very top of the file:
#r "System.IO.Compression"
// Using keywords must come before any other statements:
using System.IO.Compression;
using System.IO;
var xyz = 123;
// Using statements still work the way they're supposed to:
using(var data = new MemoryStream())
using(var zip = new ZipArchive(data, ZipArchiveMode.Create))
{
// ...
}
De forma predeterminada, Tabular Editor incluye automáticamente las siguientes directivas using (aunque no estén especificadas en el script) para facilitar las tareas más comunes:
using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
using TabularEditor.TOMWrapper;
using TabularEditor.TOMWrapper.Utils;
using TabularEditor.UI;
Además, los siguientes ensamblados de .NET Framework se cargan de forma predeterminada:
- System.Dll
- System.Core.Dll
- System.Data.Dll
- System.Windows.Forms.Dll
- Microsoft.Csharp.Dll
- Newtonsoft.Json.Dll
- TomWrapper.Dll
- TabularEditor.Exe
- Microsoft.AnalysisServices.Tabular.Dll
Compilar con Roslyn
Note
Esta sección solo se aplica a Tabular Editor 2. Tabular Editor 3 compila los scripts de forma nativa con Roslyn, por lo que las características más recientes del lenguaje C# están disponibles sin necesidad de configuración y no hay ninguna ruta de compilador que configurar.
Tabular Editor 2 compila scripts con el compilador de C# incluido en .NET Framework, que admite C# 5. Para usar características más recientes del lenguaje, como la interpolación de cadenas, en su lugar configúralo para que use un compilador de Roslyn en Archivo > Preferencias > General. Especifica el directorio que contiene el ejecutable del compilador (csc.exe) y la versión del lenguaje que se le debe pasar:

Visual Studio 2017
En una instalación típica de Visual Studio 2017 Enterprise, el compilador Roslyn se encuentra aquí:
c:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Roslyn
Esto incluye las características del lenguaje C# 6.0 de forma predeterminada.

Visual Studio 2019
Para una instalación típica de Visual Studio 2019 Community, el compilador de Roslyn se encuentra aquí:
c:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Roslyn
El compilador que se incluye con VS2019 admite las características del lenguaje C# 8,0, que se pueden habilitar especificando lo siguiente como opciones del compilador:
-langversion:8.0
Visual Studio 2022
Para una instalación típica de Visual Studio 2022 Community Edition, el compilador de Roslyn se encuentra aquí:
C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\Roslyn\csc.exe
Si usa otra edición de Visual Studio 2022, la ruta puede variar ligeramente. Por ejemplo, para la Edición Enterprise, se encuentra en:
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\Roslyn
El compilador que se incluye con la actualización más reciente de VS2022 admite las características del lenguaje C# 12.0, que se pueden habilitar especificando lo siguiente como opciones del compilador:
-langversion:12.0