PageRenderTime 51ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/SSAS/AggManager/EditAggs.cs

#
C# | 1340 lines | 1061 code | 172 blank | 107 comment | 227 complexity | e3cc28809c7ce29741bec66fb4d1da02 MD5 | raw file
Possible License(s): CC-BY-SA-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*============================================================================
  2. File: EditAggs.cs
  3. Summary: Contains the form to add, delete, and change aggregations
  4. Part of Aggregation Manager
  5. Date: January 2007
  6. ------------------------------------------------------------------------------
  7. This file is part of the Microsoft SQL Server Code Samples.
  8. Copyright (C) Microsoft Corporation. All rights reserved.
  9. This source code is intended only as a supplement to Microsoft
  10. Development Tools and/or on-line documentation. See these other
  11. materials for detailed information regarding Microsoft code samples.
  12. THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  13. KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  15. PARTICULAR PURPOSE.
  16. ============================================================================*/
  17. /*
  18. * This file has been incorporated into BIDSHelper.
  19. * http://www.codeplex.com/BIDSHelper
  20. * and may have been altered from the orginal version which was released
  21. * as a Microsoft sample.
  22. *
  23. * The official version can be found on the sample website here:
  24. * http://www.codeplex.com/MSFTASProdSamples
  25. *
  26. ============================================================================*/
  27. using System;
  28. using System.Collections.Generic;
  29. using System.ComponentModel;
  30. using System.Data;
  31. using System.Drawing;
  32. using System.Text;
  33. using System.Windows.Forms;
  34. using Microsoft.AnalysisServices;
  35. using Microsoft.AnalysisServices.AdomdClient;
  36. namespace AggManager
  37. {
  38. public partial class EditAggs : Form
  39. {
  40. private MeasureGroup mg1;
  41. private AggregationDesign aggDes;
  42. string[,] dimAttributes;
  43. string[] dimNames;
  44. string[] dimIDs;
  45. bool boolHandleClick = false;
  46. bool boolIsRigid = false;
  47. bool boolInExpandOrCollapse = false;
  48. private Color nonMaterializedColor = Color.SteelBlue;
  49. private Color parentChildAttributeColor = Color.SlateGray;
  50. private Color belowGranularityColor = Color.LightSlateGray;
  51. enum SynchControls
  52. {
  53. SynchTreeToGrid = 1,
  54. SynchGridToTreeView = 2,
  55. Unknown = 3
  56. }
  57. SynchControls sychContr = SynchControls.Unknown;
  58. public EditAggs()
  59. {
  60. InitializeComponent();
  61. }
  62. public void Init(string strAggDesign,
  63. MeasureGroup mg,
  64. string[,] inDimAttributes,
  65. string[] inDimNames ,
  66. string[] inDimIDs)
  67. {
  68. this.Text = this.Text + " Aggregation Design: " + strAggDesign;
  69. mg1 = mg;
  70. aggDes = mg.AggregationDesigns.GetByName(strAggDesign);
  71. dimAttributes = inDimAttributes;
  72. dimNames = inDimNames;
  73. dimIDs = inDimIDs;
  74. DataTable myTable = new DataTable("Aggregations");
  75. DataColumn colItem = new DataColumn("Name", Type.GetType("System.String"));
  76. myTable.Columns.Add(colItem);
  77. colItem = new DataColumn("Aggregations", Type.GetType("System.String"));
  78. myTable.Columns.Add(colItem);
  79. colItem = new DataColumn("Type", Type.GetType("System.String"));
  80. myTable.Columns.Add(colItem);
  81. DataView myDataView = new DataView(myTable);
  82. dataGrid1.DataSource = myDataView;
  83. DataRow NewRow;
  84. foreach (Aggregation agg in aggDes.Aggregations)
  85. {
  86. NewRow = myTable.NewRow();
  87. NewRow["Aggregations"] = ConvertAggToSting(agg);
  88. NewRow["Name"] = agg.Name;
  89. myTable.Rows.Add(NewRow);
  90. }
  91. AddGridStyle();
  92. PopulateTreeView();
  93. checkBoxRelationships.Checked = true;
  94. int i = 0;
  95. foreach (DataRow dRow in myDataView.Table.Rows)
  96. {
  97. dataGrid1.CurrentRowIndex = i;
  98. dataGrid1_Click(null, null);
  99. i++;
  100. }
  101. myDataView.AllowNew = false;
  102. }
  103. /// <summary>
  104. /// Setting data grid column captions and width
  105. /// </summary>
  106. private void AddGridStyle()
  107. {
  108. DataView myDataView = (DataView)dataGrid1.DataSource;
  109. int iWidth0 = 100;
  110. int iWidth1 = 400;
  111. Graphics Graphics = dataGrid1.CreateGraphics();
  112. if (myDataView.Table.Rows.Count > 0)
  113. {
  114. int iColWidth = (int)(Graphics.MeasureString
  115. (myDataView.Table.Rows[0].ItemArray[0].ToString(),
  116. dataGrid1.Font).Width);
  117. iWidth0 = (int)System.Math.Max(iWidth0, iColWidth);
  118. iColWidth = (int)(Graphics.MeasureString
  119. (myDataView.Table.Rows[0].ItemArray[1].ToString(),
  120. dataGrid1.Font).Width);
  121. iWidth1 = (int)System.Math.Max(iWidth1, iColWidth);
  122. }
  123. DataGridTableStyle myGridStyle = new DataGridTableStyle();
  124. myGridStyle.MappingName = "Aggregations";
  125. DataGridTextBoxColumn nameColumnStyle = new DataGridTextBoxColumn();
  126. nameColumnStyle.MappingName = "Name";
  127. nameColumnStyle.HeaderText = "Name";
  128. nameColumnStyle.Width = iWidth0;
  129. myGridStyle.GridColumnStyles.Add(nameColumnStyle);
  130. DataGridTextBoxColumn nameColumnStyle2 = new DataGridTextBoxColumn();
  131. nameColumnStyle2.MappingName = "Type";
  132. nameColumnStyle2.HeaderText = "Type";
  133. nameColumnStyle2.Width = 50;
  134. myGridStyle.GridColumnStyles.Add(nameColumnStyle2);
  135. DataGridTextBoxColumn nameColumnStyle1 = new DataGridTextBoxColumn();
  136. nameColumnStyle1.MappingName = "Aggregations";
  137. nameColumnStyle1.HeaderText = "Aggregation Definition";
  138. nameColumnStyle1.Width = iWidth1;
  139. myGridStyle.GridColumnStyles.Add(nameColumnStyle1);
  140. dataGrid1.TableStyles.Add(myGridStyle);
  141. }
  142. private void buttonCancel_Click(object sender, EventArgs e)
  143. {
  144. this.Close();
  145. }
  146. private void buttonOK_Click(object sender, EventArgs e)
  147. {
  148. try
  149. {
  150. DataView myDataView;
  151. int i = 0;
  152. string strRow;
  153. string strAggName;
  154. if (!AggNamesAreValid()) return;
  155. this.Cursor = Cursors.WaitCursor;
  156. aggDes.Aggregations.Clear();
  157. myDataView = (DataView)dataGrid1.DataSource;
  158. foreach (DataRow dRow in myDataView.Table.Rows)
  159. {
  160. if (dRow.RowState.ToString() != "Deleted")
  161. {
  162. strAggName = dRow.ItemArray[0].ToString();
  163. strRow = dRow.ItemArray[1].ToString();
  164. i++;
  165. if (AddAggregationToAggDesign(
  166. aggDes,
  167. strRow,
  168. strAggName) == false)
  169. i--; // No aggregation has been added
  170. }
  171. }
  172. this.Cursor = Cursors.Default;
  173. //MessageBox.Show("Aggregation design: " + aggDes.Name + " has been updated with " + i.ToString() + " aggregations");
  174. this.DialogResult = DialogResult.OK;
  175. this.Close();
  176. }
  177. catch (Exception ex)
  178. {
  179. this.Cursor = Cursors.Default;
  180. if (!String.IsNullOrEmpty(ex.Message)) MessageBox.Show("Error: " + ex.Message);
  181. }
  182. }
  183. private bool AggNamesAreValid()
  184. {
  185. DataView myDataView = (DataView)dataGrid1.DataSource;
  186. string strAggName;
  187. List<string> aggNames = new List<string>();
  188. string sInvalidChars = BIDSHelper.SsasCharacters.Invalid_Name_Characters;
  189. foreach (DataRow dRow in myDataView.Table.Rows)
  190. {
  191. if (dRow.RowState != DataRowState.Deleted)
  192. {
  193. strAggName = dRow.ItemArray[0].ToString();
  194. if (strAggName.IndexOfAny(sInvalidChars.ToCharArray()) > 0)
  195. {
  196. MessageBox.Show(strAggName + " cannot contain any of the following characters: " + sInvalidChars);
  197. return false;
  198. }
  199. if (aggNames.Contains(strAggName))
  200. {
  201. MessageBox.Show(strAggName + " is a duplicate aggregation name.");
  202. return false;
  203. }
  204. aggNames.Add(strAggName);
  205. }
  206. }
  207. return true;
  208. }
  209. /// <summary>
  210. /// Helper function takes aggregation as input and returns string representation of aggregation
  211. /// </summary>
  212. private string ConvertAggToSting(Aggregation agg)
  213. {
  214. string outStr = "";
  215. AggregationAttribute aggAttr;
  216. AggregationDimension aggDim;
  217. foreach (MeasureGroupDimension mgDim in mg1.Dimensions)
  218. {
  219. aggDim = agg.Dimensions.Find(mgDim.CubeDimensionID);
  220. if (aggDim == null)
  221. {
  222. foreach (CubeAttribute cubeDimAttr in mgDim.CubeDimension.Attributes)
  223. outStr = outStr + "0";
  224. }
  225. else
  226. {
  227. foreach (CubeAttribute cubeDimAttr in mgDim.CubeDimension.Attributes)
  228. {
  229. aggAttr = aggDim.Attributes.Find(cubeDimAttr.AttributeID);
  230. if (aggAttr == null)
  231. outStr = outStr + "0";
  232. else
  233. outStr = outStr + "1";
  234. }
  235. }
  236. outStr = outStr + ",";
  237. }
  238. return outStr.Substring(0, outStr.Length - 1);
  239. }
  240. private void SetEstimatedSize(Aggregation agg)
  241. {
  242. double size = 0;
  243. double minSize = 0;
  244. bool bAggContainsAllGranularityAttributes = true;
  245. try
  246. {
  247. EstimatedAggSize oEstSize = GetEstimatedSize(agg, mg1);
  248. size = oEstSize.size;
  249. minSize = oEstSize.minSize;
  250. bAggContainsAllGranularityAttributes = oEstSize.bAggContainsAllGranularityAttributes;
  251. }
  252. catch { }
  253. finally
  254. {
  255. if (size != 0)
  256. {
  257. if (minSize != 0 && minSize < size && !bAggContainsAllGranularityAttributes)
  258. {
  259. lblEstimatedSize.Text = agg.Name + " Estimated Size: " + (minSize * 100).ToString("#0.00") + "% to " + (size * 100).ToString("#0.00") + "% of fact data";
  260. lblEstimatedSize.ForeColor = (size > .3333 ? Color.Red : Color.Black);
  261. }
  262. else
  263. {
  264. lblEstimatedSize.Text = agg.Name + " Estimated Size: " + (size * 100).ToString("#0.00") + "% of fact data";
  265. lblEstimatedSize.ForeColor = (size > .3333 ? Color.Red : Color.Black);
  266. }
  267. }
  268. else
  269. {
  270. lblEstimatedSize.Text = agg.Name + " Estimated Size: Unknown (please update EstimatedRows on measure group)";
  271. lblEstimatedSize.ForeColor = Color.Black;
  272. }
  273. }
  274. }
  275. public class EstimatedAggSize
  276. {
  277. public double size = 0;
  278. public double minSize = 0;
  279. public bool bAggContainsAllGranularityAttributes = true;
  280. public Aggregation agg;
  281. }
  282. /// <summary>
  283. /// Returns the estimated size of this aggregation.
  284. /// </summary>
  285. /// <param name="agg"></param>
  286. /// <returns></returns>
  287. public static EstimatedAggSize GetEstimatedSize(Aggregation agg)
  288. {
  289. return GetEstimatedSize(agg, agg.ParentMeasureGroup);
  290. }
  291. /// <summary>
  292. /// Returns the estimated size of this aggregation. Use this signature which takes in the MeasureGroup when the agg is not attached to a ParentMeasureGroup.
  293. /// </summary>
  294. /// <param name="agg"></param>
  295. /// <param name="mg1"></param>
  296. /// <returns></returns>
  297. public static EstimatedAggSize GetEstimatedSize(Aggregation agg, MeasureGroup mg1)
  298. {
  299. double size = 0;
  300. double minSize = 0;
  301. bool bAggContainsAllGranularityAttributes = true;
  302. AggregationAttribute aggAttr;
  303. AggregationDimension aggDim;
  304. double dblAggCardinality = 1;
  305. long iNumSurrogateKeysInAgg = 0;
  306. int iMeasureGroupDimensionsCount = 0;
  307. long lngMaxAggDimensionCardinality = 0;
  308. foreach (MeasureGroupDimension mgDim in mg1.Dimensions)
  309. {
  310. long iDimGranularityCardinality = 0;
  311. double dblDimAggCardinality = 1;
  312. bool bDimAggCardinalityFound = false;
  313. if (!(mgDim is RegularMeasureGroupDimension)) continue; //m2m dimensions apparently aren't stored in the agg since they're calculated at runtime
  314. iMeasureGroupDimensionsCount++; //don't count m2m dimensions
  315. MeasureGroupAttribute granularity = null;
  316. RegularMeasureGroupDimension regMgDim = (RegularMeasureGroupDimension)mgDim;
  317. foreach (MeasureGroupAttribute mgDimAttr in regMgDim.Attributes)
  318. {
  319. if (mgDimAttr.Type == MeasureGroupAttributeType.Granularity)
  320. {
  321. iDimGranularityCardinality = mgDimAttr.Attribute.EstimatedCount;
  322. granularity = mgDimAttr;
  323. break;
  324. }
  325. }
  326. aggDim = agg.Dimensions.Find(mgDim.CubeDimensionID);
  327. if (aggDim == null || granularity == null || aggDim.Attributes.Find(granularity.AttributeID) == null)
  328. bAggContainsAllGranularityAttributes = false;
  329. if (aggDim != null)
  330. {
  331. foreach (CubeAttribute cubeAttr in mgDim.CubeDimension.Attributes)
  332. {
  333. aggAttr = aggDim.Attributes.Find(cubeAttr.AttributeID);
  334. if (aggAttr != null)
  335. {
  336. if (!CanReachAttributeFromChildInAgg(aggAttr, mgDim.Dimension.KeyAttribute, false)) //redundant attributes don't increase the cardinality of the attribute
  337. {
  338. dblDimAggCardinality *= (cubeAttr.Attribute.EstimatedCount == 0 ? 1 : cubeAttr.Attribute.EstimatedCount);
  339. }
  340. bDimAggCardinalityFound = true;
  341. iNumSurrogateKeysInAgg++; //apparently every key, even redundant keys, get stored in the agg
  342. }
  343. }
  344. }
  345. if (dblDimAggCardinality > iDimGranularityCardinality)
  346. {
  347. //shouldn't be more than granularity cardinality because auto-exists prevents that
  348. dblDimAggCardinality = (iDimGranularityCardinality == 0 ? 1 : iDimGranularityCardinality);
  349. }
  350. if (bDimAggCardinalityFound)
  351. {
  352. dblAggCardinality *= dblDimAggCardinality;
  353. if (lngMaxAggDimensionCardinality < dblAggCardinality) lngMaxAggDimensionCardinality = (long)dblDimAggCardinality;
  354. }
  355. }
  356. if (mg1.EstimatedRows != 0 && dblAggCardinality != 0)
  357. {
  358. long iMeasureBytes = 0;
  359. foreach (Microsoft.AnalysisServices.Measure m in mg1.Measures)
  360. {
  361. if (m.DataType == MeasureDataType.Inherited)
  362. {
  363. if (m.Source.DataSize > 0)
  364. iMeasureBytes += m.Source.DataSize;
  365. else if (m.Source.DataType == System.Data.OleDb.OleDbType.Integer)
  366. iMeasureBytes += 4;
  367. else if (m.Source.DataType == System.Data.OleDb.OleDbType.SmallInt)
  368. iMeasureBytes += 2;
  369. else if (m.Source.DataType == System.Data.OleDb.OleDbType.TinyInt)
  370. iMeasureBytes += 1;
  371. else
  372. iMeasureBytes += 8;
  373. }
  374. else
  375. {
  376. if (m.DataType == MeasureDataType.Integer)
  377. iMeasureBytes += 4;
  378. else if (m.DataType == MeasureDataType.SmallInt)
  379. iMeasureBytes += 2;
  380. else if (m.DataType == MeasureDataType.TinyInt)
  381. iMeasureBytes += 1;
  382. else
  383. iMeasureBytes += 8;
  384. }
  385. }
  386. //the size of each row is 4 bytes for each surrogate key plus the size of measures
  387. long lngFactTableRowSize = (iMeasureGroupDimensionsCount * 4 + iMeasureBytes);
  388. long lngAggRowSize = (iNumSurrogateKeysInAgg * 4 + iMeasureBytes);
  389. if (dblAggCardinality > mg1.EstimatedRows) //this is not possible in the data
  390. {
  391. dblAggCardinality = mg1.EstimatedRows;
  392. }
  393. //multiply the estimated rows by the size of each row
  394. size = ((double)(dblAggCardinality * lngAggRowSize)) / ((double)(mg1.EstimatedRows * lngFactTableRowSize));
  395. //purposefully don't prevent size from being over 1 because an agg can be larger than the fact table if it has more dimension attribute keys than the fact table
  396. if (lngMaxAggDimensionCardinality > mg1.EstimatedRows) //this is not possible in the data
  397. {
  398. lngMaxAggDimensionCardinality = mg1.EstimatedRows;
  399. }
  400. //calculate the min size (best case scenario when there is lots of sparsity in fact table) so you can present a range to the user and give the user an idea of the uncertainty
  401. minSize = ((double)(lngMaxAggDimensionCardinality * lngAggRowSize)) / ((double)(mg1.EstimatedRows * lngFactTableRowSize));
  402. }
  403. EstimatedAggSize ret = new EstimatedAggSize();
  404. ret.minSize = minSize;
  405. ret.size = size;
  406. ret.bAggContainsAllGranularityAttributes = bAggContainsAllGranularityAttributes;
  407. ret.agg = agg;
  408. return ret;
  409. }
  410. public static string GetEstimatedAggSizeRange(EstimatedAggSize estimate)
  411. {
  412. if (estimate.size == 0)
  413. {
  414. return null;
  415. }
  416. else if (estimate.minSize != 0 && estimate.minSize < estimate.size && !estimate.bAggContainsAllGranularityAttributes)
  417. {
  418. return (estimate.minSize * 100).ToString("#0.00") + "% to " + (estimate.size * 100).ToString("#0.00") + "%";
  419. }
  420. else
  421. {
  422. return (estimate.size * 100).ToString("#0.00") + "%";
  423. }
  424. }
  425. private static bool CanReachAttributeFromChildInAgg(AggregationAttribute attr, DimensionAttribute current, bool bChildIsInAgg)
  426. {
  427. bChildIsInAgg = bChildIsInAgg || attr.Parent.Attributes.Contains(current.ID);
  428. foreach (AttributeRelationship r in current.AttributeRelationships)
  429. {
  430. if (r.AttributeID == attr.AttributeID && bChildIsInAgg)
  431. {
  432. return true;
  433. }
  434. else
  435. {
  436. if (CanReachAttributeFromChildInAgg(attr, r.Attribute, bChildIsInAgg)) return true;
  437. }
  438. }
  439. return false;
  440. }
  441. Boolean AddAggregationToAggDesign(AggregationDesign aggDesign, string instr, string aggName)
  442. {
  443. try
  444. {
  445. Aggregation agg;
  446. agg = aggDesign.Aggregations.Find(aggName);
  447. if (agg != null)
  448. aggName = "Aggregation " + aggDesign.Aggregations.Count.ToString();
  449. if (aggName == "")
  450. aggName = "Aggregation " + aggDesign.Aggregations.Count.ToString();
  451. agg = aggDesign.Aggregations.Add(aggName, aggName);
  452. string a1;
  453. int dimNum = 0;
  454. int attrNum = 0;
  455. bool newDim = true;
  456. for (int i = 0; i < instr.Length; i++)
  457. {
  458. a1 = instr[i].ToString();
  459. switch (a1)
  460. {
  461. case ",":
  462. dimNum++;
  463. attrNum = -1;
  464. newDim = true;
  465. break;
  466. case "0":
  467. break;
  468. case "1":
  469. if (newDim)
  470. {
  471. agg.Dimensions.Add(dimIDs[dimNum]);
  472. newDim = false;
  473. }
  474. agg.Dimensions[dimIDs[dimNum]].Attributes.Add(dimAttributes[dimNum, attrNum]);
  475. break;
  476. default:
  477. break;
  478. }
  479. attrNum++;
  480. }
  481. return true;
  482. }
  483. catch (Exception ex)
  484. {
  485. MessageBox.Show("Problem saving " + aggName + ": " + ex.Message);
  486. throw new Exception(""); //blank exception means not to report it
  487. }
  488. }
  489. private Aggregation GetAggregationFromString(string aggregationName, string instr)
  490. {
  491. Aggregation agg = new Aggregation();
  492. agg.Name = aggregationName;
  493. string a1;
  494. int dimNum = 0;
  495. int attrNum = 0;
  496. bool newDim = true;
  497. for (int i = 0; i < instr.Length; i++)
  498. {
  499. a1 = instr[i].ToString();
  500. switch (a1)
  501. {
  502. case ",":
  503. dimNum++;
  504. attrNum = -1;
  505. newDim = true;
  506. break;
  507. case "0":
  508. break;
  509. case "1":
  510. if (newDim)
  511. {
  512. agg.Dimensions.Add(dimIDs[dimNum]);
  513. newDim = false;
  514. }
  515. agg.Dimensions[dimIDs[dimNum]].Attributes.Add(dimAttributes[dimNum, attrNum]);
  516. break;
  517. default:
  518. break;
  519. }
  520. attrNum++;
  521. }
  522. return agg;
  523. }
  524. /// <summary>
  525. /// Called to populate tree view representing dimension attributes
  526. /// </summary>
  527. public void PopulateTreeView()
  528. {
  529. treeViewAggregation.SuspendLayout();
  530. treeViewAggregation.Nodes.Clear();
  531. if (!checkBoxRelationships.Checked)
  532. {
  533. foreach (MeasureGroupDimension mgDim in mg1.Dimensions)
  534. {
  535. TreeNode parentNode = treeViewAggregation.Nodes.Add(mgDim.CubeDimensionID, mgDim.CubeDimension.Name);
  536. if (mgDim is ManyToManyMeasureGroupDimension)
  537. parentNode.StateImageIndex = 3;
  538. else
  539. parentNode.StateImageIndex = 2;
  540. foreach (CubeAttribute cubeDimAttr in mgDim.CubeDimension.Attributes)
  541. {
  542. TreeNode childNode = parentNode.Nodes.Add(cubeDimAttr.AttributeID, cubeDimAttr.Attribute.Name);
  543. if (!cubeDimAttr.AttributeHierarchyEnabled)
  544. {
  545. childNode.NodeFont = new Font(treeViewAggregation.Font, FontStyle.Italic);
  546. childNode.ForeColor = Color.Gray;
  547. }
  548. else if (mgDim is ReferenceMeasureGroupDimension)
  549. {
  550. ReferenceMeasureGroupDimension refDim = (ReferenceMeasureGroupDimension)mgDim;
  551. if (refDim.Materialization == ReferenceDimensionMaterialization.Indirect)
  552. {
  553. childNode.ForeColor = Color.Red;
  554. }
  555. }
  556. else if (cubeDimAttr.Attribute.Usage == AttributeUsage.Parent)
  557. {
  558. childNode.ForeColor = Color.Red;
  559. }
  560. }
  561. }
  562. }
  563. else
  564. {
  565. foreach (MeasureGroupDimension mgDim in mg1.Dimensions)
  566. {
  567. TreeNode parentNode = treeViewAggregation.Nodes.Add(mgDim.CubeDimensionID, mgDim.CubeDimension.Name);
  568. if (mgDim is ManyToManyMeasureGroupDimension)
  569. parentNode.StateImageIndex = 3;
  570. else
  571. parentNode.StateImageIndex = 2;
  572. foreach (CubeAttribute cubeDimAttr in mgDim.CubeDimension.Attributes)
  573. if (cubeDimAttr.Attribute.Usage == AttributeUsage.Key)
  574. {
  575. parentNode = parentNode.Nodes.Add(cubeDimAttr.AttributeID, cubeDimAttr.Attribute.Name);
  576. AddTreeViewNodeChildren(parentNode, cubeDimAttr,mgDim);
  577. }
  578. }
  579. }
  580. treeViewAggregation.ExpandAll();
  581. treeViewAggregation.Nodes[0].EnsureVisible(); //scroll to top
  582. treeViewAggregation.ResumeLayout(false);
  583. }
  584. /// <summary>
  585. /// Recursive function. Adds nodes to the tree view control.
  586. /// Adds nodes accourding to attribute relationships
  587. /// </summary>
  588. private void AddTreeViewNodeChildren(TreeNode node, CubeAttribute cubeDimAttr , MeasureGroupDimension mgDim)
  589. {
  590. bool bIsAtOrAboveGranularity = ValidateAggs.IsAtOrAboveGranularity(cubeDimAttr.Attribute, mgDim);
  591. if (!bIsAtOrAboveGranularity)
  592. {
  593. node.ForeColor = belowGranularityColor;
  594. }
  595. else if (mgDim is ReferenceMeasureGroupDimension)
  596. {
  597. ReferenceMeasureGroupDimension refDim = (ReferenceMeasureGroupDimension)mgDim;
  598. if (refDim.Materialization == ReferenceDimensionMaterialization.Indirect)
  599. {
  600. node.ForeColor = nonMaterializedColor;
  601. }
  602. }
  603. else if (cubeDimAttr.Attribute.Usage == AttributeUsage.Parent)
  604. {
  605. node.ForeColor = parentChildAttributeColor;
  606. }
  607. foreach (AttributeRelationship attRel in cubeDimAttr.Attribute.AttributeRelationships)
  608. {
  609. CubeAttribute childAttr = cubeDimAttr.Parent.Attributes.Find(attRel.AttributeID);
  610. if (childAttr == null) break;
  611. TreeNode childNode = node.Nodes.Add(childAttr.AttributeID, childAttr.Attribute.Name);
  612. if (!childAttr.AttributeHierarchyEnabled)
  613. {
  614. childNode.NodeFont = new Font(treeViewAggregation.Font, FontStyle.Italic);
  615. childNode.ForeColor = Color.Gray;
  616. }
  617. childNode.Tag = attRel;
  618. AddTreeViewNodeChildren( childNode, childAttr,mgDim);
  619. }
  620. }
  621. private void EditAggs_Load(object sender, EventArgs e)
  622. {
  623. //Add menu item allowing for adding new aggregations to agg design
  624. MenuItem item1 = new MenuItem("Add Aggregation", new EventHandler(AddAggregationHandler));
  625. ContextMenu menu = new ContextMenu(new MenuItem[] { item1});
  626. this.dataGrid1.ContextMenu = menu;
  627. dataGrid1_Click(sender, e);
  628. //Add Expand/Collapse Events after everything else is loaded
  629. //this.treeViewAggregation.AfterCollapse += new System.Windows.Forms.TreeViewEventHandler(this.treeViewAggregation_AfterExpandOrCollapse);
  630. this.treeViewAggregation.BeforeExpand += new System.Windows.Forms.TreeViewCancelEventHandler(this.treeViewAggregation_ExpandOrCollapse);
  631. this.treeViewAggregation.BeforeCollapse += new System.Windows.Forms.TreeViewCancelEventHandler(this.treeViewAggregation_ExpandOrCollapse);
  632. //this.treeViewAggregation.AfterExpand += new System.Windows.Forms.TreeViewEventHandler(this.treeViewAggregation_AfterExpandOrCollapse);
  633. }
  634. void AddAggregationHandler(object sender, EventArgs e)
  635. {
  636. DataView myDataView;
  637. myDataView = (DataView)dataGrid1.DataSource;
  638. String strAgg = "";
  639. int i = 0, j = 0;
  640. while (dimNames[i] != null)
  641. {
  642. j = 0;
  643. while (dimAttributes[i, j] != null)
  644. {
  645. strAgg = strAgg + "0";
  646. j++;
  647. }
  648. i++;
  649. strAgg = strAgg + ",";
  650. }
  651. strAgg = strAgg.Remove(strAgg.Length - 1);
  652. DataRow NewRow = myDataView.Table.NewRow();
  653. NewRow["Aggregations"] = strAgg;
  654. NewRow["Name"] = "Aggregation " + myDataView.Table.Rows.Count.ToString();
  655. myDataView.Table.Rows.Add(NewRow);
  656. dataGrid1.CurrentRowIndex = NewRow.Table.Rows.IndexOf(NewRow);
  657. dataGrid1_Click(null, null);
  658. }
  659. /// <summary>
  660. /// Helps select the correct data source row even when grid is sorted
  661. /// </summary>
  662. /// <returns></returns>
  663. private DataRow GetCurrentDataGridRow()
  664. {
  665. DataView myDataView = (DataView)dataGrid1.DataSource;
  666. return myDataView.Table.Select(null, myDataView.Sort)[dataGrid1.CurrentRowIndex];
  667. }
  668. /// <summary>
  669. /// Helps synchronizing aggregation definition in current row data grid control to
  670. /// aggregation definition presented as checked boxes for appropriate attributes in
  671. /// tree view control
  672. /// </summary>
  673. private void dataGrid1_Click(object sender, EventArgs e)
  674. {
  675. if (sychContr == SynchControls.SynchGridToTreeView)
  676. return;
  677. try
  678. {
  679. DataRow dr = GetCurrentDataGridRow();
  680. String strAgg = dr[1].ToString();
  681. String strAggName = dr[0].ToString();
  682. if (checkBoxRelationships.Checked)
  683. {
  684. sychContr = SynchControls.SynchGridToTreeView;
  685. if (CheckOffTreeView(strAgg))
  686. dr[2] = "Rigid";
  687. else
  688. dr[2] = "Flexible";
  689. }
  690. else
  691. {
  692. int i = 0;
  693. foreach (TreeNode parentNode in treeViewAggregation.Nodes)
  694. {
  695. foreach (TreeNode childNode in parentNode.Nodes)
  696. {
  697. if (strAgg[i].ToString() == "1")
  698. {
  699. sychContr = SynchControls.SynchGridToTreeView;
  700. childNode.Checked = true;
  701. childNode.BackColor = dataGrid1.HeaderBackColor;
  702. }
  703. else
  704. {
  705. sychContr = SynchControls.SynchGridToTreeView;
  706. childNode.Checked = false;
  707. childNode.BackColor = treeViewAggregation.BackColor;
  708. }
  709. i++;
  710. }
  711. i++;
  712. }
  713. }
  714. SetEstimatedSize(GetAggregationFromString(strAggName, strAgg));
  715. txtSummary.Text = GetCheckedNodeText(treeViewAggregation.Nodes);
  716. }
  717. catch
  718. { }
  719. sychContr = SynchControls.Unknown;
  720. }
  721. private string GetCheckedNodeText(TreeNodeCollection nodes)
  722. {
  723. string text = "";
  724. foreach (TreeNode tn in nodes)
  725. {
  726. if (tn.Checked)
  727. {
  728. int iCntMatchingName = 0;
  729. foreach (MeasureGroupDimension mgd in mg1.Dimensions)
  730. {
  731. foreach (CubeAttribute ca in mgd.CubeDimension.Attributes)
  732. {
  733. if (ca.AttributeHierarchyEnabled && ca.Attribute.AttributeHierarchyEnabled && string.Compare(ca.Attribute.Name, tn.Text, true) == 0)
  734. {
  735. iCntMatchingName++;
  736. }
  737. }
  738. }
  739. if (iCntMatchingName > 1)
  740. {
  741. //put the cube dimension name on the end to disambiguate
  742. TreeNode parentNode = tn;
  743. while (parentNode.Parent != null) //loop until you hit the dimension
  744. parentNode = parentNode.Parent;
  745. text += tn.Text + " (" + parentNode.Text + ")\r\n";
  746. }
  747. else
  748. {
  749. text += tn.Text + "\r\n";
  750. }
  751. }
  752. if (tn.Nodes.Count > 0)
  753. {
  754. text += GetCheckedNodeText(tn.Nodes);
  755. }
  756. }
  757. return text;
  758. }
  759. private void dataGrid1_CurrentCellChanged(object sender, EventArgs e)
  760. {
  761. dataGrid1_Click(sender, e);
  762. }
  763. /// <summary>
  764. /// Main function called when user checks/uncheckes dimension attribute.
  765. /// If attribute checked it needs to be added to the string representation of an aggregations
  766. /// </summary>
  767. private void treeViewAggregation_AfterCheck(object sender, TreeViewEventArgs e)
  768. {
  769. // If happen to synch Tree to grid, we should quit
  770. if (sychContr == SynchControls.SynchTreeToGrid)
  771. return;
  772. if (e.Action == TreeViewAction.Unknown && !boolHandleClick ) return;
  773. if (e.Node.Parent == null)
  774. return;
  775. DataRow dr = GetCurrentDataGridRow();
  776. String strAgg = dr[1].ToString();
  777. int i = 0;
  778. int intAttrCount = 0;
  779. TreeNode parent = e.Node.Parent;
  780. while (parent.Parent != null)
  781. {
  782. parent = parent.Parent;
  783. }
  784. if (parent == null) MessageBox.Show("Cannot find parent");
  785. string parentName = parent.Name;
  786. while (treeViewAggregation.Nodes[i].Name != parentName)
  787. {
  788. intAttrCount++;
  789. intAttrCount += mg1.Dimensions[treeViewAggregation.Nodes[i].Name].CubeDimension.Attributes.Count;
  790. i++;
  791. }
  792. if (checkBoxRelationships.Checked)
  793. {
  794. //Find a place of an attribute in the attr string
  795. int j = 0;
  796. foreach (CubeAttribute cubeDimAttr in mg1.Dimensions[treeViewAggregation.Nodes[i].Name].CubeDimension.Attributes)
  797. {
  798. if (cubeDimAttr.AttributeID == e.Node.Name)
  799. intAttrCount += j;
  800. j++;
  801. }
  802. }
  803. else
  804. {
  805. intAttrCount += e.Node.Index;
  806. }
  807. if (e.Node.Checked)
  808. {
  809. strAgg = strAgg.Insert(intAttrCount, "1");
  810. strAgg = strAgg.Remove(intAttrCount + 1, 1);
  811. System.Drawing.Color ii = dataGrid1.HeaderBackColor;
  812. e.Node.BackColor = ii;
  813. }
  814. else
  815. {
  816. strAgg = strAgg.Insert(intAttrCount, "0");
  817. strAgg = strAgg.Remove(intAttrCount + 1, 1);
  818. e.Node.BackColor = treeViewAggregation.BackColor;
  819. }
  820. dr[1] = strAgg;
  821. if (sychContr == SynchControls.SynchTreeToGrid)
  822. dataGrid1_Click(null, null);
  823. sychContr = SynchControls.Unknown;
  824. }
  825. private void checkBoxRelationships_CheckedChanged(object sender, EventArgs e)
  826. {
  827. PopulateTreeView();
  828. dataGrid1_Click(sender, e);
  829. }
  830. /// <summary>
  831. /// Takes aggregation string as an input and interates over nodes in tree view control
  832. /// if attribute participates in aggregation, function will check the check box for
  833. /// the attribute
  834. /// </summary>
  835. private bool CheckOffTreeView(string strAgg)
  836. {
  837. string a1;
  838. int dimNum = 0;
  839. int attrNum = 0;
  840. bool newDim = true;
  841. boolIsRigid = true;
  842. TreeNode dimNode = treeViewAggregation.Nodes[0];
  843. TreeNode attrNode;
  844. for (int i = 0; i < strAgg.Length; i++)
  845. {
  846. a1 = strAgg[i].ToString();
  847. switch (a1)
  848. {
  849. case ",":
  850. dimNum++;
  851. attrNum = -1;
  852. newDim = true;
  853. dimNode = treeViewAggregation.Nodes[dimNum];
  854. break;
  855. case "0":
  856. attrNode = FindChildNode(dimNode, dimAttributes[dimNum, attrNum]);
  857. if (attrNode != null)
  858. {
  859. attrNode.Checked = false;
  860. attrNode.BackColor = treeViewAggregation.BackColor;
  861. }
  862. break;
  863. case "1":
  864. if (newDim) newDim = false;
  865. attrNode = FindChildNodeAndRelationships(dimNode, dimAttributes[dimNum, attrNum]);
  866. if (attrNode != null)
  867. {
  868. attrNode.Checked = true;
  869. attrNode.BackColor = dataGrid1.HeaderBackColor;
  870. }
  871. break;
  872. default:
  873. break;
  874. }
  875. attrNum++;
  876. }
  877. treeViewAggregation.ExpandAll();
  878. return boolIsRigid;
  879. }
  880. private TreeNode FindChildNodeAndRelationships(TreeNode node, string strNodeID)
  881. {
  882. TreeNode returnNode;
  883. foreach (TreeNode childNode in node.Nodes)
  884. {
  885. if (childNode.Name == strNodeID)
  886. {
  887. if (childNode.Tag != null)
  888. if (((AttributeRelationship)childNode.Tag).RelationshipType == RelationshipType.Flexible)
  889. boolIsRigid = false;
  890. return childNode;
  891. }
  892. returnNode = FindChildNodeAndRelationships(childNode, strNodeID);
  893. if (returnNode != null)
  894. {
  895. if (node.Tag != null)
  896. if (((AttributeRelationship)node.Tag).RelationshipType == RelationshipType.Flexible)
  897. boolIsRigid = false;
  898. return returnNode;
  899. }
  900. }
  901. return null;
  902. }
  903. private TreeNode FindChildNode(TreeNode node, string strNodeID)
  904. {
  905. TreeNode returnNode;
  906. foreach (TreeNode childNode in node.Nodes)
  907. {
  908. if (childNode.Name == strNodeID)
  909. return childNode;
  910. returnNode = FindChildNode(childNode, strNodeID);
  911. if (returnNode != null)
  912. return returnNode;
  913. }
  914. return null;
  915. }
  916. /// <summary>
  917. /// Goes over every aggregation in the aggregation design and eliminates
  918. /// redundant attributes from every aggregation
  919. /// Redundant is an attribute in aggregation that in the attribute relationship chain appears on top
  920. /// of another attribute.
  921. /// For example State attribute should not be selected if City attribute appears in the aggregation.
  922. /// </summary>
  923. private void buttonOptimizeAgg_Click(object sender, EventArgs e)
  924. {
  925. if (checkBoxRelationships.Checked == false)
  926. {
  927. MessageBox.Show("Please switch to relationships view");
  928. return;
  929. }
  930. this.Cursor = Cursors.WaitCursor;
  931. DataView myDataView;
  932. myDataView = (DataView)dataGrid1.DataSource;
  933. boolHandleClick = true;
  934. int i = 0;
  935. foreach( DataRow dataGridRow in myDataView.Table.Rows)
  936. {
  937. dataGrid1.CurrentRowIndex = i;
  938. dataGrid1_Click(null,null);
  939. foreach (TreeNode node in treeViewAggregation.Nodes)
  940. OptimizeNode(node, false);
  941. i++;
  942. }
  943. boolHandleClick = false;
  944. DataRow dr = GetCurrentDataGridRow();
  945. SetEstimatedSize(GetAggregationFromString(dr[0].ToString(), dr[1].ToString()));
  946. txtSummary.Text = GetCheckedNodeText(treeViewAggregation.Nodes);
  947. this.Cursor = Cursors.Default;
  948. }
  949. private void OptimizeNode(TreeNode node, bool removeChecks)
  950. {
  951. bool localRemoveChecks = removeChecks;
  952. foreach (TreeNode childNode in node.Nodes)
  953. {
  954. localRemoveChecks = removeChecks;
  955. if (childNode.Checked == true)
  956. if (removeChecks) childNode.Checked = false;
  957. else localRemoveChecks = true;
  958. OptimizeNode(childNode, localRemoveChecks);
  959. }
  960. }
  961. private void buttonEliminateDupe_Click(object sender, EventArgs e)
  962. {
  963. DataView myDataView;
  964. myDataView = (DataView)dataGrid1.DataSource;
  965. int i = 0;
  966. List<string> uniqueAggs = new List<string>();
  967. while (i < myDataView.Table.Rows.Count)
  968. {
  969. if (uniqueAggs.Contains(myDataView.Table.Rows[i].ItemArray[1].ToString()))
  970. {
  971. myDataView.Table.Rows.Remove(myDataView.Table.Rows[i]);
  972. }
  973. else
  974. {
  975. uniqueAggs.Add(myDataView.Table.Rows[i].ItemArray[1].ToString());
  976. i++;
  977. }
  978. }
  979. }
  980. private void treeViewAggregation_Click(object sender, EventArgs e)
  981. {
  982. if (e is MouseEventArgs)
  983. {
  984. if (!boolInExpandOrCollapse)
  985. {
  986. MouseEventArgs me = (MouseEventArgs)e;
  987. TreeNode node = treeViewAggregation.GetNodeAt(me.Location);
  988. if (node.StateImageIndex >= 2) //this node is a dimension, so ignore clicks
  989. return;
  990. if (node.NodeFont != null && node.NodeFont.Italic && !node.Checked)
  991. {
  992. MessageBox.Show("The cube dimension attribute " + node.Text + " is marked AttributeHierarchyEnabled=false");
  993. }
  994. else if (node.ForeColor == nonMaterializedColor && !node.Checked) //show this warning unless they're unchecking it
  995. {
  996. MessageBox.Show("This dimension is related through a non-materialized reference relationship\n\nCreating aggregations on such a relationship is not valid is it can produce incorrect figures.");
  997. }
  998. else if (node.ForeColor == parentChildAttributeColor && !node.Checked) //show this warning unless they're unchecking it
  999. {
  1000. MessageBox.Show("This attribute is a parent-child attribute. Aggregations are not allowed on it.");
  1001. }
  1002. else if (node.ForeColor == belowGranularityColor && !node.Checked) //show this warning unless they're unchecking it
  1003. {
  1004. MessageBox.Show("This attribute is below granularity. Aggregations are not allowed on it.");
  1005. }
  1006. else
  1007. {
  1008. bool bFlipCheck = true;
  1009. TreeNode dimensionNode = node.Parent;
  1010. while (dimensionNode.Parent != null)
  1011. dimensionNode = dimensionNode.Parent;
  1012. MeasureGroupDimension mgDim = mg1.Dimensions.Find(dimensionNode.Name);
  1013. if (!node.Checked && mgDim is ManyToManyMeasureGroupDimension)
  1014. {
  1015. //check that all the joining dimensions are in the agg, if not, offer to do that
  1016. //also suggest not including the m2m dimension in the agg
  1017. DataRow currentDR = GetCurrentDataGridRow();
  1018. String strAgg = currentDR[1].ToString();
  1019. String strAggName = currentDR[0].ToString();
  1020. Aggregation agg = GetAggregationFromString(strAggName, strAgg);
  1021. ManyToManyMeasureGroupDimension m2mDim = (ManyToManyMeasureGroupDimension)mgDim;
  1022. MeasureGroup intermediateMG = m2mDim.MeasureGroup;
  1023. List<MeasureGroupAttribute> missing = new List<MeasureGroupAttribute>();
  1024. foreach (MeasureGroupDimension commonDim in intermediateMG.Dimensions)
  1025. {
  1026. if (!mgDim.Parent.Dimensions.Contains(commonDim.CubeDimensionID)) continue; //this isn't a shared dimension
  1027. MeasureGroupDimension dataMeasureGroupDim = mgDim.Parent.Dimensions[commonDim.CubeDimensionID];
  1028. if (dataMeasureGroupDim is ManyToManyMeasureGroupDimension) continue; //this shared dimension is m2m on the data measure group so don't include it
  1029. RegularMeasureGroupDimension regCommonDim = commonDim as RegularMeasureGroupDimension;
  1030. if (commonDim.CubeDimensionID != m2mDim.CubeDimensionID || regCommonDim == null)
  1031. {
  1032. //this is a common dimension and the granularity attribute on the intermediate measure group needs to be in the agg
  1033. bool bFoundGranularityAgg = false;
  1034. MeasureGroupAttribute mga = ValidateAggs.GetGranularityAttribute(regCommonDim);
  1035. AggregationDimension aggCommonDim = agg.Dimensions.Find(commonDim.CubeDimensionID);
  1036. if (aggCommonDim != null)
  1037. {
  1038. if (aggCommonDim.Attributes.Find(mga.AttributeID) != null)
  1039. {
  1040. bFoundGranularityAgg = true;
  1041. }
  1042. }
  1043. if (!bFoundGranularityAgg && mga != null)
  1044. {
  1045. missing.Add(mga);

Large files files are truncated, but you can click here to view the full file