在表格式模型中,數據表是數據的基底表示法。
數據表表示法
AMO 中的數據表
使用 AMO 來管理資料表時,沒有任何一對一物件相符。 在 AMO 中,數據表是由 Dimension 和 MeasureGroup表示。 若要讓量值群組存在, Cube 必須定義 來裝載量值群組。 若要讓維度、量值群組和 Cube 存在,必須定義數據源檢視物件,才能保存數據源的系結定義。
從程序的觀點來看,必須先建立數據源檢視,才能定義任何其他物件。 數據源檢視物件包含數據源中所有相關對象的對應。 關係型模型的對應會內嵌在數據源檢視中做為 .Net DataSet 物件,並儲存在 DSV 的 Schema 屬性中。
下列代碼段假設您有 SQL 用戶端連接字串、Select 語句的字典,對應至您想要在表格式模型中表示之關係模型中的所有數據表,以及具有數據源檢視名稱的變數 newDataSourceViewName(通常是關係資料庫的名稱)。
DataSet newDataSourceViewDataSet = new DataSet(newDataSourceViewName);
Foreach( String tableName in listOfSqlStatements.Keys)
{
String sqlStmt = listOfSqlStatements[tableName];
DataTable newTable = new DataTable(tableName);
using (SqlConnection SqlCnx = new SqlConnection(SqlCnxStr))
{
SqlDataAdapter dataAdapter = new SqlDataAdapter(sqlStmt, SqlCnx);
dataAdapter.FillSchema(newTable, SchemaType.Source);
}
newDataSourceViewDataSet.Tables.Add(newTable);
}
AMO.DataSourceView newDatasourceView = newDatabase.DataSourceViews.AddNew(newDataSourceViewName, newDataSourceViewName);
newDatasourceView.DataSourceID = newDatasource.ID; //This is the ID of the DataSource object
newDatasourceView.Schema = newDataSourceViewDataSet; //Here you are storing all the relational schema in the DSV
newDatasourceView.Update();
建立及更新數據源檢視之後,必須建立 Cube 物件,但在建立第一個數據表之前,才在伺服器中更新。 Cube 物件無法建立空白。 下列代碼段示範如何建立 Cube;代碼段假設您有非空字串 newCubeName,且 Cube 的名稱也已驗證重複專案。
modelCube = newDatabase.Cubes.Add(newCubeName, newCubeName);
modelCube.Source = new AMO.DataSourceViewBinding(newDatasourceView.ID);
modelCube.StorageMode = AMO.StorageMode.InMemory;
modelCube.Language = newDatabase.Language;
modelCube.Collation = newDatabase.Collation;
//Create initial MdxScript
AMO.MdxScript mdxScript = modelCube.MdxScripts.Add("MdxScript", "MdxScript");
StringBuilder initialCommand = new StringBuilder();
initialCommand.AppendLine("CALCULATE;");
initialCommand.AppendLine("CREATE MEMBER CURRENTCUBE.Measures.[__No measures defined] AS 1;");
initialCommand.AppendLine("ALTER CUBE CURRENTCUBE UPDATE DIMENSION Measures, Default_Member = [__No measures defined];");
mdxScript.Commands.Add(new AMO.Command(initialCommand.ToString()));
在本機定義 Cube 之後,即可建立和更新數據表。 下列程式概述建立資料表的必要步驟:
建立代表數據表且尚未更新伺服器的維度。
建立 RowNumber 屬性,並將其定義為維度的索引鍵屬性。
建立維度屬性,並使用與 RowNumber 的一對多關聯性加以標記。
將維度新增至 Cube 維度。
建立也代表數據表的量值群組。
將維度新增至量值群組。
將 AMO 預設量值物件建立至量值群組。 請注意,這是唯一使用 AMO 量值對象的時間;表格式模型中的導出量值定義於 AMO MdxScripts[“MdxScript”] 物件中。
建立預設分割區。
更新資料庫。
下列代碼段示範如何建立資料表:
private Boolean CreateTable(
AMO.Database db //the AMO database object where dimension are created
, AMO.Cube cb //the AMO cube where measure group is created
, DataTable dataTable //the schema of the table to be created
)
{
String tableID = dataTable.TableName;
if (db.Dimensions.Contains(tableID))
{
if (cb.MeasureGroups.Contains(tableID))
{
cb.MeasureGroups[tableID].Measures.Clear();
cb.MeasureGroups[tableID].Partitions.Clear();
cb.MeasureGroups.Remove(tableID, true);
}
if (cb.Dimensions.Contains(tableID))
{
cb.Dimensions.Remove(tableID, true);
}
db.Dimensions.Remove(tableID);
}
#region Create Dimension
//Define Dimension general properties
AMO.Dimension currentDimension = db.Dimensions.AddNew(tableID, tableID);
currentDimension.Source = new AMO.DataSourceViewBinding(newDatasourceView.ID);
currentDimension.StorageMode = AMO.DimensionStorageMode.InMemory;
currentDimension.UnknownMember = AMO.UnknownMemberBehavior.AutomaticNull;
currentDimension.UnknownMemberName = "Unknown";
currentDimension.ErrorConfiguration = new AMO.ErrorConfiguration();
currentDimension.ErrorConfiguration.KeyNotFound = AMO.ErrorOption.IgnoreError;
currentDimension.ErrorConfiguration.KeyDuplicate = AMO.ErrorOption.ReportAndStop;
currentDimension.ErrorConfiguration.NullKeyNotAllowed = AMO.ErrorOption.ReportAndStop;
currentDimension.Language = db.Language;
currentDimension.Collation = db.Collation;
currentDimension.ProactiveCaching = new AMO.ProactiveCaching();
TimeSpan defaultProactiveChachingTimeSpan = new TimeSpan(0, 0, -1);
currentDimension.ProactiveCaching.SilenceInterval = defaultProactiveChachingTimeSpan;
currentDimension.ProactiveCaching.Latency = defaultProactiveChachingTimeSpan;
currentDimension.ProactiveCaching.SilenceOverrideInterval = defaultProactiveChachingTimeSpan;
currentDimension.ProactiveCaching.ForceRebuildInterval = defaultProactiveChachingTimeSpan;
currentDimension.ProactiveCaching.Source = new AMO.ProactiveCachingInheritedBinding();
//Manualy add a "RowNumber" attribute as the key attribute of the dimension, until a primary key is defined
//"RowNumber" a required column for a tabular model and has to be of type AMO.AttributeType.RowNumber and binding AMO.RowNumberBinding.
//The name of the "RowNumber" attribute can be any name, as long as type and binding are correctly set
//By default, the MS client tools set the column name and column ID of the RowNumber attribute to "RowNumber"
//In this sample, to avoid problems, on any customer table that contains a column named 'RowNumber'
//the Id value of the column (in the dimension object) will be renamed to 'RowNumber_in_<TableName>' and the Name of the column will remain "RowNumber"
AMO.DimensionAttribute currentAttribute = currentDimension.Attributes.Add("RowNumber", "RowNumber");
currentAttribute.Type = AMO.AttributeType.RowNumber;
currentAttribute.KeyUniquenessGuarantee = true;
currentAttribute.Usage = AMO.AttributeUsage.Key;
currentAttribute.KeyColumns.Add(new AMO.DataItem());
currentAttribute.KeyColumns[0].DataType = System.Data.OleDb.OleDbType.Integer;
currentAttribute.KeyColumns[0].DataSize = 4;
currentAttribute.KeyColumns[0].NullProcessing = AMO.NullProcessing.Error;
currentAttribute.KeyColumns[0].Source = new AMO.RowNumberBinding();
currentAttribute.NameColumn = new AMO.DataItem();
currentAttribute.NameColumn.DataType = System.Data.OleDb.OleDbType.WChar;
currentAttribute.NameColumn.DataSize = 4;
currentAttribute.NameColumn.NullProcessing = AMO.NullProcessing.ZeroOrBlank;
currentAttribute.NameColumn.Source = new AMO.RowNumberBinding();
currentAttribute.OrderBy = AMO.OrderBy.Key;
currentAttribute.AttributeHierarchyVisible = false;
//Deferring AttributeRelationships until after adding each other attribute
//Add each column in the table as an attribute in the dimension
foreach (DataColumn dataColumn in dataTable.Columns)
{
string attributeID, attributeName;
if (dataColumn.ColumnName != "RowNumber")
{
attributeID = dataColumn.ColumnName;
}
else
{
attributeID = string.Format("RowNumber_in_{0}", dataTable.TableName);
}
attributeName = dataColumn.ColumnName;
currentAttribute = currentDimension.Attributes.Add(attributeName, attributeID);
currentAttribute.Usage = AMO.AttributeUsage.Regular;
currentAttribute.KeyUniquenessGuarantee = false;
currentAttribute.KeyColumns.Add(new AMO.DataItem(dataTable.TableName, dataColumn.ColumnName, AMO.OleDbTypeConverter.GetRestrictedOleDbType(dataColumn.DataType)));
currentAttribute.KeyColumns[0].Source = new AMO.ColumnBinding(dataTable.TableName, dataColumn.ColumnName);
currentAttribute.KeyColumns[0].NullProcessing = AMO.NullProcessing.Preserve;
currentAttribute.NameColumn = new AMO.DataItem(dataTable.TableName, dataColumn.ColumnName, System.Data.OleDb.OleDbType.WChar);
currentAttribute.NameColumn.Source = new AMO.ColumnBinding(dataTable.TableName, dataColumn.ColumnName);
currentAttribute.NameColumn.NullProcessing = AMO.NullProcessing.ZeroOrBlank;
currentAttribute.OrderBy = AMO.OrderBy.Key;
AMO.AttributeRelationship currentAttributeRelationship = currentDimension.Attributes["RowNumber"].AttributeRelationships.Add(currentAttribute.ID);
currentAttributeRelationship.Cardinality = AMO.Cardinality.Many;
currentAttributeRelationship.OverrideBehavior = AMO.OverrideBehavior.None;
}
#endregion
#region Add Dimension to Model cube
cb.Dimensions.Add(tableID, tableID, tableID);
#endregion
#region Add MeasureGroup to Model cube
AMO.MeasureGroup currentMeasureGroup = cb.MeasureGroups.Add(tableID, tableID);
currentMeasureGroup.StorageMode = AMO.StorageMode.InMemory;
currentMeasureGroup.ProcessingMode = AMO.ProcessingMode.Regular;
//Adding Dimension
AMO.DegenerateMeasureGroupDimension currentMGDim = new AMO.DegenerateMeasureGroupDimension(tableID);
currentMeasureGroup.Dimensions.Add(currentMGDim);
currentMGDim.ShareDimensionStorage = AMO.StorageSharingMode.Shared;
currentMGDim.CubeDimensionID = tableID;
foreach (AMO.CubeAttribute ca in cb.Dimensions[tableID].Attributes)
{
AMO.MeasureGroupAttribute mga = new AMO.MeasureGroupAttribute(ca.AttributeID);
if (mga.AttributeID == "RowNumber")
{
mga.Type = AMO.MeasureGroupAttributeType.Granularity;
AMO.DataItem rowNumberKeyColumn = new AMO.DataItem(new AMO.ColumnBinding(tableID, "RowNumber"));
rowNumberKeyColumn.DataType = System.Data.OleDb.OleDbType.Integer;
mga.KeyColumns.Add(rowNumberKeyColumn);
}
else
{
foreach (AMO.DataItem di in ca.Attribute.KeyColumns)
{
AMO.DataItem keyColumn = new AMO.DataItem(new AMO.ColumnBinding(tableID, ((AMO.ColumnBinding)di.Source).ColumnID));
keyColumn.DataType = di.DataType;
keyColumn.NullProcessing = AMO.NullProcessing.Preserve;
keyColumn.InvalidXmlCharacters = AMO.InvalidXmlCharacters.Remove;
mga.KeyColumns.Add(keyColumn);
}
}
currentMGDim.Attributes.Add(mga);
}
//Adding default Measure
String defaultMeasureID = string.Concat("_Count ", tableID);
AMO.Measure currentMeasure = currentMeasureGroup.Measures.Add(defaultMeasureID, defaultMeasureID);
currentMeasure.AggregateFunction = AMO.AggregationFunction.Count;
currentMeasure.DataType = AMO.MeasureDataType.BigInt;
AMO.DataItem currentMeasureSource = new AMO.DataItem(new AMO.RowBinding(tableID));
currentMeasureSource.DataType = System.Data.OleDb.OleDbType.BigInt;
currentMeasure.Source = currentMeasureSource;
//Partitions
AMO.Partition currentPartition = new AMO.Partition(tableID, tableID);
currentPartition.StorageMode = AMO.StorageMode.InMemory;
currentPartition.ProcessingMode = AMO.ProcessingMode.Regular;
currentPartition.Source = new AMO.QueryBinding(newDatasource.ID, (String)dataTable.ExtendedProperties["sqlStmt"]);
currentMeasureGroup.Partitions.Add(currentPartition);
#endregion
#region Update new objects in database
db.Update(AMO.UpdateOptions.ExpandFull, AMO.UpdateMode.UpdateOrCreate);
#endregion
return true;
}
謹慎
在發生失敗時,上述代碼段沒有任何錯誤檢查或清除程式。