Programando objetos AMO fundamentais
Os objetos fundamentais são geralmente simples e diretos. Esses objetos são normalmente criados e instanciados e, quando não são mais necessários, o usuário se desconecta deles. As classes fundamentais incluem os seguintes objetos: Server, Database, DataSource e DataSourceView. O único objeto complexo dos objetos fundamentais AMO é o DataSourceView, que exige detalhes para a criação do modelo abstrato que representa a exibição da fonte de dados.
Os objetos Server e Database são normalmente necessários para o uso de objetos contidos como objetos OLAP ou objetos de mineração de dados.
Este tópico contém as seguintes seções:
Objetos do servidor
Objetos de exceção AMOException
Objetos de banco de dados
Objetos DataSource
Objetos DataSourceView
Objetos do servidor
A utilização de um objeto Server exige as seguintes etapas: conexão ao servidor, verificação se o objeto Server está conectado ao servidor e, se for o caso, desconexão do Server a partir do servidor.
Conectando-se ao objeto do servidor
A conexão ao servidor consiste em ter a cadeia de conexão correta.
O código de exemplo a seguir retornará um objeto Server se a conexão tiver êxito ou retornará null se ocorrer um erro. Os erros ocorridos durante o processo de conexão serão manipulados em uma construção try/catch. Os erros de AMO são capturados por meio da classe de exceção AmoException. Neste exemplo, o erro é mostrado ao usuário em uma caixa de mensagem.
static Server ServerConnect( String strStringConnection)
{
string methodCaption = "ServerConnect method";
Server svr = new Server();
try
{
svr.Connect(strStringConnection);
}
#region ErrorHandling
catch (AmoException e)
{
MessageBox.Show( "AMO exception " + e.ToString());
svr = null;
}
catch (Exception e)
{
MessageBox.Show("General exception " + e.ToString());
svr = null;
}
#endregion
return svr;
}
A estrutura da cadeia de conexão é:
"Data source=<nome do servidor>".
Para obter mais informações sobre cadeias de conexão, consulte ConnectionString.
Validando a conexão
Antes de programar os objetos Server, verifique se ainda está conectado ao servidor. O código de exemplo a seguir mostra como fazer isso. O exemplo supõe que svr seja um objeto Server existente em seu código.
if ( (svr != null) && ( svr.Connected))
{
// Do what it is needed if connection is good
}
Desconectando do servidor
Assim que tiver concluído, você poderá se desconectar do servidor usando o método Disconnect. O código de exemplo a seguir mostra como fazer isso. O exemplo supõe que svr seja um objeto Server existente em seu código.
if ( (svr != null) && ( svr.Connected))
{
svr.Disconnect()
}
Objetos de exceção AmoException
O AMO lançará exceções quando problemas diferentes forem encontrados. Para obter uma explicação detalhada sobre exceções, consulte Outras classes e métodos AMO. O código de exemplo a seguir mostra a forma correta de capturar exceções no AMO:
try
{
//... some AMO code in here
}
catch ( OutOfSynchException e)
{
// error handling code for OutOfSynchException
}
catch ( OperationException e)
{
// error handling code for OperationException
}
catch ( ResponseFormatException e)
{
// error handling code for ResponseFormatException
}
catch ( ConnectionException e)
{
// error handling code for ConnectionException
}
catch ( AMOException e)
{
//... here is the place where you end if it is an AMO exception, but none of the previous exceptions
// if you start with AMOException in the first catch you will never see any one of the previous exceptions
}
Objetos de banco de dados
Trabalhar com um objeto Database é muito simples e direto. Você obtém um banco de dados existente da coleção de banco de dados do objeto Server.
Criando, descartando e localizando um banco de dados
O código de exemplo a seguir mostra como criar um banco de dados quando um nome de banco de dados. Antes de criar o banco de dados, consulte o DatabaseCollection do servidor para verificar a existência do banco de dados. Se o banco de dados existir, será descartado e posteriormente criado; se não existir, então será criado. Se o banco de dados tiver de ser descartado, então primeiro será obtido da coleção de bancos de dados.
static Database CreateDatabase(Server svr, String DatabaseName)
{
Database db = null;
if ( (svr != null) && ( svr.Connected))
{
// Drop the database if it already exists
db = svr.Databases.FindByName(DatabaseName);
if (db != null)
{
db.Drop();
}
// Create the database
db = svr.Databases.Add(DatabaseName);
db.Update();
}
return db;
}
Para determinar a existência de um banco de dados na coleção de banco de dados, será usado o método FindByName. Se o banco de dados existir, então o método retornará o objeto de banco de dados encontrado; caso contrário, retornará um objeto nulo.
Assim que o objeto Database for acrescentado à coleção de bancos de dados, o servidor deverá que ser atualizado usando seu método Update. Não atualizar o servidor fará com que o objeto Database não seja criado no servidor.
Processando um banco de dados
O processamento de um banco de dados, com todos os seus objetos filhos, é muito simples, já que o objeto Database inclui um método Process.
O método Process pode incluir parâmetros, mas eles não são obrigatórios. Se nenhum parâmetro for especificado, todos os objetos filhos serão processados com sua opção ProcessDefault. Para obter mais informações sobre as opções de processamento, consulte Microsoft.AnalysisServices.Database.
- O código de exemplo a seguir processa um banco de dados por seu valor padrão.
static Database ProcessDatabase(Database db, ProcessType pt)
{
db.Process( pt);
return db;
}
Objetos DataSource
Um objeto DataSource é o vínculo entre o Analysis Services e o banco de dados onde os dados residem. O esquema que representa o modelo subjacente para o Analysis Services é definido pelo objeto DataSourceView. Um objeto DataSource pode ser visto como uma cadeia de conexão ao banco de dados onde os dados residem.
O código de exemplo a seguir mostra como criar um objeto DataSource. O exemplo verifica se o servidor ainda existe, se o objeto Server está conectado e se o banco de dados existe. Se o objeto DataSource existir, será descartado e recriado. O objeto DataSource é criado com o mesmo nome e ID interna. Neste exemplo, nenhuma verificação será executada na cadeia de caracteres de conexão.
static string CreateDataSource(Database db, string strDataSourceName, string strConnectionString)
{
Server svr = db.Parent;
DataSource ds = db.DataSources.FindByName(strDataSourceName);
if (ds != null)
ds.Drop();
// Create the data source
ds = db.DataSources.Add(strDataSourceName, strDataSourceName);
ds.ConnectionString = strConnectionString;
// Send the data source definition to the server.
ds.Update();
return ds.Name;
}
Objetos DataSourceView
O objeto DataSourceView é responsável por armazenar o modelo de esquema para o Analysis Services. Para que o objeto DataSourceView armazene o esquema, primeiro o esquema deverá ser criado. Os esquemas são criados sobre objetos DataSet, a partir do namespace System.Data.
O exemplo código a seguir criará parte do esquema incluído no exemplo de projeto do Analysis Services para a AdventureWorks. Para obter mais informações sobre como instalar os exemplos, consulte Bancos de dados de exemplo AdventureWorks2008R2. O exemplo atual cria definições de esquema para tabelas, colunas computadas, relações e relações compostas. Os esquemas são conjuntos de dados persistentes.
O código de exemplo faz o seguinte:
Crie um objeto DataSourceView.
Primeiro verifique a existência do objeto DataSource; se for true, descarte DataSource e crie-o. Se DataSource não existir, crie-o.
Abra uma conexão com o banco de dados usando a cadeia de conexão DataSource.
Crie o esquema.
O esquema consiste no seguinte:
Uma definição de tabela, método AddTable().
Um conjunto opcional de colunas calculadas, método AddComputedColumn().
Um conjunto opcional de relações, AddRelation.
Um conjunto opcional de relações compostas, AddCompositeRelations.
Atualize o servidor.
Observação |
---|
O código de exemplo a seguir foi resumido para fins de legibilidade; o código completo foi incluído no final deste tópico. |
Observação |
---|
Os métodos a seguir fazem parte do código de exemplo: AddTable, AddComputedColumn, AddRelation e AddCompositeRelation. |
Observação |
---|
A cláusula 'WHERE 1=0' serve para impedir que a consulta retorne linhas para o objeto DataSet. |
static DataSourceView CreateDataSourceView(Database db, string strDataSourceName)
{
// Create the data source view
DataSourceView dsv = db.DataSourceViews.FindByName(strDataSourceName);
if ( dsv != null)
dsv.Drop();
dsv = db.DataSourceViews.Add(strDataSourceName);
dsv.DataSourceID = strDataSourceName;
dsv.Schema = new DataSet();
dsv.Schema.Locale = CultureInfo.CurrentCulture;
// Open a connection to the data source
OleDbConnection connection
= new OleDbConnection(dsv.DataSource.ConnectionString);
connection.Open();
#region Create tables
// Add the DimTime table
AddTable(dsv, connection, "DimTime");
AddComputedColumn(dsv, connection, "DimTime", "SimpleDate", "DATENAME(mm, FullDateAlternateKey) + ' ' + DATENAME(dd, FullDateAlternateKey) + ',' + ' ' + DATENAME(yy, FullDateAlternateKey)");
// Add the DimProductCategory table
AddTable(dsv, connection, "DimProductCategory");
// Add the DimProductSubcategory table
AddTable(dsv, connection, "DimProductSubcategory");
AddRelation(dsv, "DimProductSubcategory", "ProductCategoryKey", "DimProductCategory", "ProductCategoryKey");
// Add the FactInternetSales table
AddTable(dsv, connection, "FactInternetSales");
"DimTime", "TimeKey");
AddRelation(dsv, "FactInternetSales", "ShipDateKey", "DimTime", "TimeKey");
AddRelation(dsv, "FactInternetSales", "DueDateKey", "DimTime", "TimeKey");
// Add the FactInternetSalesReason table
AddTable(dsv, connection, "FactInternetSalesReason");
AddCompositeRelation(dsv, "FactInternetSalesReason", "FactInternetSales", "SalesOrderNumber", "SalesOrderLineNumber");
dsv.Update();
#endregion
// Send the data source view definition to the server
dsv.Update();
return dsv;
}
static void AddTable(DataSourceView dsv, OleDbConnection connection, String tableName)
{
string strSelectText = "SELECT * FROM [dbo].[" + tableName + "] WHERE 1=0";
OleDbDataAdapter adapter = new OleDbDataAdapter(strSelectText, connection);
DataTable[] dataTables = adapter.FillSchema(dsv.Schema,
SchemaType.Mapped, tableName);
DataTable dataTable = dataTables[0];
dataTable.ExtendedProperties.Add("TableType", "Table");
dataTable.ExtendedProperties.Add("DbSchemaName", "dbo");
dataTable.ExtendedProperties.Add("DbTableName", tableName);
dataTable.ExtendedProperties.Add("FriendlyName", tableName);
dataTable = null;
dataTables = null;
adapter = null;
}
static void AddComputedColumn(DataSourceView dsv, OleDbConnection connection, String tableName, String computedColumnName, String expression)
{
DataSet tmpDataSet = new DataSet();
tmpDataSet.Locale = CultureInfo.CurrentCulture;
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT ("
+ expression + ") AS [" + computedColumnName + "] FROM [dbo].["
+ tableName + "] WHERE 1=0", connection);
DataTable[] dataTables = adapter.FillSchema(tmpDataSet,
SchemaType.Mapped, tableName);
DataTable dataTable = dataTables[0];
DataColumn dataColumn = dataTable.Columns[computedColumnName];
dataTable.Constraints.Clear();
dataTable.Columns.Remove(dataColumn);
dataColumn.ExtendedProperties.Add("DbColumnName", computedColumnName);
dataColumn.ExtendedProperties.Add("ComputedColumnExpression",
expression);
dataColumn.ExtendedProperties.Add("IsLogical", "True");
dsv.Schema.Tables[tableName].Columns.Add(dataColumn);
dataColumn = null;
dataTable = null;
dataTables = null;
adapter = null;
tmpDataSet = null;
}
static void AddRelation(DataSourceView dsv, String fkTableName, String fkColumnName, String pkTableName, String pkColumnName)
{
DataColumn fkColumn
= dsv.Schema.Tables[fkTableName].Columns[fkColumnName];
DataColumn pkColumn
= dsv.Schema.Tables[pkTableName].Columns[pkColumnName];
dsv.Schema.Relations.Add("FK_" + fkTableName + "_"
+ fkColumnName, pkColumn, fkColumn, true);
}
static void AddCompositeRelation(DataSourceView dsv, String fkTableName, String pkTableName, String columnName1, String columnName2)
{
DataColumn[] fkColumns = new DataColumn[2];
fkColumns[0] = dsv.Schema.Tables[fkTableName].Columns[columnName1];
fkColumns[1] = dsv.Schema.Tables[fkTableName].Columns[columnName2];
DataColumn[] pkColumns = new DataColumn[2];
pkColumns[0] = dsv.Schema.Tables[pkTableName].Columns[columnName1];
pkColumns[1] = dsv.Schema.Tables[pkTableName].Columns[columnName2];
dsv.Schema.Relations.Add("FK_" + fkTableName + "_" + columnName1
+ "_" + columnName2, pkColumns, fkColumns, true);
}
No código de exemplo, os métodos AddTable e AddComputedColumn usam o método FillSchema do objeto DataAdapter para adicionar uma DataTable a um DataSet e para configurar o esquema para que ele corresponda ao da fonte de dados. As propriedades estendidas adicionam as informações necessárias à configuração do esquema para o Analysis Services.
No código de exemplo, os métodos AddRelation e AddCompositeRelation adicionam as colunas de relação, dependendo do esquema e das colunas existentes no modelo. As colunas devem fazer parte das tabelas definidas no esquema para que esses métodos funcionem.
A seguir, o código de exemplo completo:
static DataSourceView CreateDataSourceView(Database db, string strDataSourceName)
{
// Create the data source view
DataSourceView dsv = db.DataSourceViews.FindByName(strDataSourceName);
if ( dsv != null)
dsv.Drop();
dsv = db.DataSourceViews.Add(strDataSourceName);
dsv.DataSourceID = strDataSourceName;
dsv.Schema = new DataSet();
dsv.Schema.Locale = CultureInfo.CurrentCulture;
// Open a connection to the data source
OleDbConnection connection
= new OleDbConnection(dsv.DataSource.ConnectionString);
connection.Open();
#region Create tables
// Add the DimTime table
AddTable(dsv, connection, "DimTime");
AddComputedColumn(dsv, connection, "DimTime", "SimpleDate", "DATENAME(mm, FullDateAlternateKey) + ' ' + DATENAME(dd, FullDateAlternateKey) + ',' + ' ' + DATENAME(yy, FullDateAlternateKey)");
AddComputedColumn(dsv, connection, "DimTime", "CalendarYearDesc", "'CY' + ' ' + CalendarYear");
AddComputedColumn(dsv, connection, "DimTime", "CalendarSemesterDesc", "CASE WHEN CalendarSemester = 1 THEN 'H1'+' '+ 'CY' +' '+ CONVERT(CHAR (4), CalendarYear) ELSE 'H2'+' '+ 'CY' +' '+ CONVERT(CHAR (4), CalendarYear) END");
AddComputedColumn(dsv, connection, "DimTime", "CalendarQuarterDesc", "'Q' + CONVERT(CHAR (1), CalendarQuarter) +' '+ 'CY' +' '+ CONVERT(CHAR (4), CalendarYear)");
AddComputedColumn(dsv, connection, "DimTime", "MonthName", "EnglishMonthName+' '+ CONVERT(CHAR (4), CalendarYear)");
AddComputedColumn(dsv, connection, "DimTime", "FiscalYearDesc", "'FY' + ' ' + FiscalYear");
AddComputedColumn(dsv, connection, "DimTime", "FiscalSemesterDesc", "CASE WHEN FiscalSemester = 1 THEN 'H1'+' '+ 'FY' +' '+ CONVERT(CHAR (4), FiscalYear) ELSE 'H2'+' '+ 'FY' +' '+ CONVERT(CHAR (4), FiscalYear) END");
AddComputedColumn(dsv, connection, "DimTime", "FiscalQuarterDesc", "'Q' + CONVERT(CHAR (1), FiscalQuarter) +' '+ 'FY' +' '+ CONVERT(CHAR (4), FiscalYear)");
AddComputedColumn(dsv, connection, "DimTime", "FiscalMonthNumberOfYear", "CASE WHEN MonthNumberOfYear = '1' THEN CONVERT(int,'7') WHEN MonthNumberOfYear = '2' THEN CONVERT(int,'8') WHEN MonthNumberOfYear = '3' THEN CONVERT(int,'9') WHEN MonthNumberOfYear = '4' THEN CONVERT(int,'10') WHEN MonthNumberOfYear = '5' THEN CONVERT(int,'11') WHEN MonthNumberOfYear = '6' THEN CONVERT(int,'12') WHEN MonthNumberOfYear = '7' THEN CONVERT(int,'1') WHEN MonthNumberOfYear = '8' THEN CONVERT(int,'2') WHEN MonthNumberOfYear = '9' THEN CONVERT(int,'3') WHEN MonthNumberOfYear = '10' THEN CONVERT(int,'4') WHEN MonthNumberOfYear = '11' THEN CONVERT(int,'5') WHEN MonthNumberOfYear = '12' THEN CONVERT(int,'6') END");
dsv.Update();
// Add the DimGeography table
AddTable(dsv, connection, "DimGeography");
// Add the DimProductCategory table
AddTable(dsv, connection, "DimProductCategory");
// Add the DimProductSubcategory table
AddTable(dsv, connection, "DimProductSubcategory");
AddRelation(dsv, "DimProductSubcategory", "ProductCategoryKey", "DimProductCategory", "ProductCategoryKey");
// Add the DimProduct table
AddTable(dsv, connection, "DimProduct");
AddComputedColumn(dsv, connection, "DimProduct", "ProductLineName", "CASE ProductLine WHEN 'M' THEN 'Mountain' WHEN 'R' THEN 'Road' WHEN 'S' THEN 'Accessory' WHEN 'T' THEN 'Touring' ELSE 'Components' END");
AddRelation(dsv, "DimProduct", "ProductSubcategoryKey", "DimProductSubcategory", "ProductSubcategoryKey");
dsv.Update();
// Add the DimCustomer table
AddTable(dsv, connection, "DimCustomer");
AddComputedColumn(dsv, connection, "DimCustomer", "FullName", "CASE WHEN MiddleName IS NULL THEN FirstName + ' ' + LastName ELSE FirstName + ' ' + MiddleName + ' ' + LastName END");
AddComputedColumn(dsv, connection, "DimCustomer", "GenderDesc", "CASE WHEN Gender = 'M' THEN 'Male' ELSE 'Female' END");
AddComputedColumn(dsv, connection, "DimCustomer", "MaritalStatusDesc", "CASE WHEN MaritalStatus = 'S' THEN 'Single' ELSE 'Married' END");
AddRelation(dsv, "DimCustomer", "GeographyKey", "DimGeography", "GeographyKey");
// Add the DimReseller table
AddTable(dsv, connection, "DimReseller");
AddComputedColumn(dsv, connection, "DimReseller", "OrderFrequencyDesc", "CASE WHEN OrderFrequency = 'A' THEN 'Annual' WHEN OrderFrequency = 'S' THEN 'Bi-Annual' ELSE 'Quarterly' END");
AddComputedColumn(dsv, connection, "DimReseller", "OrderMonthDesc", "CASE WHEN OrderMonth = '1' THEN 'January' WHEN OrderMonth = '2' THEN 'February' WHEN OrderMonth = '3' THEN 'March' WHEN OrderMonth = '4' THEN 'April' WHEN OrderMonth = '5' THEN 'May' WHEN OrderMonth = '6' THEN 'June' WHEN OrderMonth = '7' THEN 'July' WHEN OrderMonth = '8' THEN 'August' WHEN OrderMonth = '9' THEN 'September' WHEN OrderMonth = '10' THEN 'October' WHEN OrderMonth = '11' THEN 'November' WHEN OrderMonth = '12' THEN 'December' ELSE 'Never Ordered' END");
// Add the DimCurrency table
AddTable(dsv, connection, "DimCurrency");
dsv.Update();
// Add the DimSalesReason table
AddTable(dsv, connection, "DimSalesReason");
// Add the FactInternetSales table
AddTable(dsv, connection, "FactInternetSales");
AddRelation(dsv, "FactInternetSales", "ProductKey", "DimProduct", "ProductKey");
AddRelation(dsv, "FactInternetSales", "CustomerKey", "DimCustomer", "CustomerKey");
AddRelation(dsv, "FactInternetSales", "OrderDateKey", "DimTime", "TimeKey");
AddRelation(dsv, "FactInternetSales", "ShipDateKey", "DimTime", "TimeKey");
AddRelation(dsv, "FactInternetSales", "DueDateKey", "DimTime", "TimeKey");
AddRelation(dsv, "FactInternetSales", "CurrencyKey", "DimCurrency", "CurrencyKey");
dsv.Update();
// Add the FactResellerSales table
AddTable(dsv, connection, "FactResellerSales");
AddRelation(dsv, "FactResellerSales", "ProductKey", "DimProduct", "ProductKey");
AddRelation(dsv, "FactResellerSales", "ResellerKey", "DimReseller", "ResellerKey");
AddRelation(dsv, "FactResellerSales", "OrderDateKey", "DimTime", "TimeKey");
AddRelation(dsv, "FactResellerSales", "ShipDateKey", "DimTime", "TimeKey");
AddRelation(dsv, "FactResellerSales", "DueDateKey", "DimTime", "TimeKey");
AddRelation(dsv, "FactResellerSales", "CurrencyKey", "DimCurrency", "CurrencyKey");
// Add the FactInternetSalesReason table
AddTable(dsv, connection, "FactInternetSalesReason");
AddCompositeRelation(dsv, "FactInternetSalesReason", "FactInternetSales", "SalesOrderNumber", "SalesOrderLineNumber");
dsv.Update();
// Add the FactCurrencyRate table
AddTable(dsv, connection, "FactCurrencyRate");
AddRelation(dsv, "FactCurrencyRate", "CurrencyKey", "DimCurrency", "CurrencyKey");
AddRelation(dsv, "FactCurrencyRate", "TimeKey", "DimTime", "TimeKey");
#endregion
// Send the data source view definition to the server
dsv.Update();
return dsv;
}
static void AddTable(DataSourceView dsv, OleDbConnection connection, String tableName)
{
string strSelectText = "SELECT * FROM [dbo].[" + tableName + "] WHERE 1=0";
OleDbDataAdapter adapter = new OleDbDataAdapter(strSelectText, connection);
DataTable[] dataTables = adapter.FillSchema(dsv.Schema,
SchemaType.Mapped, tableName);
DataTable dataTable = dataTables[0];
dataTable.ExtendedProperties.Add("TableType", "Table");
dataTable.ExtendedProperties.Add("DbSchemaName", "dbo");
dataTable.ExtendedProperties.Add("DbTableName", tableName);
dataTable.ExtendedProperties.Add("FriendlyName", tableName);
dataTable = null;
dataTables = null;
adapter = null;
}
static void AddComputedColumn(DataSourceView dsv, OleDbConnection connection, String tableName, String computedColumnName, String expression)
{
DataSet tmpDataSet = new DataSet();
tmpDataSet.Locale = CultureInfo.CurrentCulture;
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT ("
+ expression + ") AS [" + computedColumnName + "] FROM [dbo].["
+ tableName + "] WHERE 1=0", connection);
DataTable[] dataTables = adapter.FillSchema(tmpDataSet,
SchemaType.Mapped, tableName);
DataTable dataTable = dataTables[0];
DataColumn dataColumn = dataTable.Columns[computedColumnName];
dataTable.Constraints.Clear();
dataTable.Columns.Remove(dataColumn);
dataColumn.ExtendedProperties.Add("DbColumnName", computedColumnName);
dataColumn.ExtendedProperties.Add("ComputedColumnExpression",
expression);
dataColumn.ExtendedProperties.Add("IsLogical", "True");
dsv.Schema.Tables[tableName].Columns.Add(dataColumn);
dataColumn = null;
dataTable = null;
dataTables = null;
adapter = null;
tmpDataSet = null;
}
static void AddRelation(DataSourceView dsv, String fkTableName, String fkColumnName, String pkTableName, String pkColumnName)
{
DataColumn fkColumn
= dsv.Schema.Tables[fkTableName].Columns[fkColumnName];
DataColumn pkColumn
= dsv.Schema.Tables[pkTableName].Columns[pkColumnName];
dsv.Schema.Relations.Add("FK_" + fkTableName + "_"
+ fkColumnName, pkColumn, fkColumn, true);
}
static void AddCompositeRelation(DataSourceView dsv, String fkTableName, String pkTableName, String columnName1, String columnName2)
{
DataColumn[] fkColumns = new DataColumn[2];
fkColumns[0] = dsv.Schema.Tables[fkTableName].Columns[columnName1];
fkColumns[1] = dsv.Schema.Tables[fkTableName].Columns[columnName2];
DataColumn[] pkColumns = new DataColumn[2];
pkColumns[0] = dsv.Schema.Tables[pkTableName].Columns[columnName1];
pkColumns[1] = dsv.Schema.Tables[pkTableName].Columns[columnName2];
dsv.Schema.Relations.Add("FK_" + fkTableName + "_" + columnName1
+ "_" + columnName2, pkColumns, fkColumns, true);
}
Consulte também
Referência
Conceitos
Arquitetura lógica (Analysis Services – Dados Multidimensionais)
Objetos de banco de dados (Analysis Services – Dados Multidimensionais)