Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Level Up Your Biml: Best Practices and Coding Techniques (TUGA IT 2016)

687 views

Published on

Level Up Your Biml: Best Practices and Coding Techniques (Presented at TUGA IT in Lisbon, Portugal on May 21st 2016)

Published in: Data & Analytics
  • Be the first to comment

  • Be the first to like this

Level Up Your Biml: Best Practices and Coding Techniques (TUGA IT 2016)

  1. 1. TUGA IT 2016 LISBON, PORTUGAL
  2. 2. THANK YOU TO OUR SPONSORS
  3. 3. THANK YOU TO OUR TEAM ANDRÉ BATISTA ANDRÉ MELANCIA ANDRÉ VALA ANTÓNIO LOURENÇO BRUNO LOPES CLÁUDIO SILVA NIKO NEUGEBAUER RUI REISRICARDO CABRAL NUNO CANCELO PAULO MATOS PEDRO SIMÕES SANDRA MORGADO SANDRO PEREIRARUI BASTOS NUNO ÁRIAS SILVA
  4. 4. Level Up Your Biml: Best Practices and Coding Techniques Cathrine Wilhelmsen · TUGA IT · May 21st 2016
  5. 5. Session Description Is your Biml solution starting to remind you of a bowl of tangled spaghetti code? Good! That means you are solving real problems while saving a lot of time. The next step is to make sure that your solution does not grow too complex and confusing – you do not want to waste all that saved time on future maintenance! Attend this session for an overview of Biml best practices and coding techniques. Step by step, we will simplify and enhance our solution. Learn how to centralize and reuse code with Include files and the CallBimlScript method. Make your code easier to read and write by utilizing LINQ (Language-Integrated Queries). Share code between files by using Annotations and ObjectTags. And finally, if standard Biml is not enough to solve your problems, you can create your own C# helper classes and extension methods to implement custom logic. Start improving your code today and level up your Biml in no time!
  6. 6. You… …? Know basic Biml and BimlScript Completed BimlScript.com lessons Have created a staging environment
  7. 7. Next 70 minutes… …? Code Management Practical Biml Coding C# Classes and Methods
  8. 8. Cathrine Wilhelmsen @cathrinew cathrinewilhelmsen.net Data Warehouse Architect Business Intelligence Developer
  9. 9. Biml Tools
  10. 10. What do you need?
  11. 11. BIDS Helper Free open-source add-in for Visual Studio 60+ features for SSIS, SSAS and SSRS Includes basic Biml package generator bidshelper.codeplex.com
  12. 12. …or you can use the new Biml tools
  13. 13. BimlExpress Free add-in for Visual Studio Code editor with syntax highlighting and Biml Intellisense More frequent updates than BIDS Helper varigence.com/bimlexpress
  14. 14. BimlOnline Free browser-based Biml editor Code editor with Biml and C# Intellisense Reverse-engineer from SSIS to Biml bimlonline.com
  15. 15. BimlStudio Licensed full-featured development environment for Biml Visual designer and metadata modeling Full-stack automation and transformers varigence.com/bimlstudio
  16. 16. Comparing Biml Tools Free Biml Intellisense "Black Box" Free Full Intellisense Logical View Licensed Full IDE Preview BimlScript
  17. 17. Biml and BimlScript
  18. 18. Biml Business Intelligence Markup Language XML Language – just text Easy to read and write – but can be verbose You can use any tool to generate the Biml for you… (Text editor macros, Excel, PowerShell, T-SQL ++)
  19. 19. BimlScript …but use BimlScript :) Extend Biml with integrated C# (or VB) code blocks Allows you to generate, control and manipulate Biml Import metadata and quickly script entire solutions
  20. 20. BimlScript Code Nuggets <# … #> Control Nuggets (Control logic) <#= … #> Text Nuggets (Returns string) <#@ … #> Directives (Compiler instructions) <#+ … #> Class Nuggets (Create C# classes)
  21. 21. How does it work?
  22. 22. Yes, but how does it work?
  23. 23. Yes, but how does it actually work? <Biml xmlns="http://schemas.varigence.com/biml.xsd"> <Packages> <# foreach (var table in RootNode.Tables) { #> <Package Name="Load_<#=table.Name#>"></Package> <# } #> </Packages> </Biml> <Biml xmlns="http://schemas.varigence.com/biml.xsd"> <Packages> <Package Name="Load_Customer"/> <Package Name="Load_Product"/> <Package Name="Load_Sales"/> </Packages> </Biml>
  24. 24. Biml and BimlScript Flat XML "Just text" Generate, control and manipulate Biml with C#
  25. 25. Code Management
  26. 26. Don't Repeat Yourself Move common code to separate files Centralize and reuse in many projects Update code once for all projects 1. Include files 2. CallBimlScript with Parameters 3. Tiered Biml files
  27. 27. Include Files Include common code in multiple files and projects Can include many file types: .biml .txt .sql .cs Use the include directive <#@ include file="CommonCode.biml" #> The directive will be replaced by the included file Works like an automated Copy & Paste
  28. 28. Include Files
  29. 29. Include Files
  30. 30. Include Files
  31. 31. CallBimlScript with Parameters Works like a parameterized include (or stored procedure) File to be called (callee) specifies input parameters it accepts <#@ property name="Parameter" type="String" #> File that calls (caller) passes input parameters <#=CallBimlScript("CommonCode.biml", Parameter)#>
  32. 32. CallBimlScript with Parameters
  33. 33. CallBimlScript with Parameters
  34. 34. CallBimlScript with Parameters
  35. 35. CallBimlScript with Parameters
  36. 36. CallBimlScript with Parameters
  37. 37. Tiered Biml Files Split Biml code in multiple files and use the template directive: <#@ template tier="1" #> Compile Biml from lowest to highest tier to: • Solve logical dependencies • Simulate manual workflows For each tier, objects are added to the RootNode Higher tiers can use objects from lower tiers
  38. 38. What is this RootNode? When working with flat Biml, the <Biml> root element contains collections of root objects: <Biml> <Connections>...</Connections> <Databases>...</Databases> <Schemas>...</Schemas> <Tables>...</Tables> <Projects>...</Projects> <Packages>...</Packages> </Biml> When working with BimlScript, the RootNode contains collections of root objects: =
  39. 39. How do I query the RootNode? Query the RootNode to loop over collections: <# foreach (var table in RootNode.Tables) { #> Query the RootNode to get specific objects: <#=RootNode.Tables["Product"].Schema#>
  40. 40. Inside the Black Box: Tiered Biml Files <#@ template tier="1" #> <Connections>...</Connections> <#@ template tier="2" #> <Packages>...</Packages> <#@ template tier="3" #> <Package>...</Package>
  41. 41. Inside the Black Box: Tiered Biml Files <#@ template tier="1" #> <Connections>...</Connections> <#@ template tier="2" #> <Packages>...</Packages> <#@ template tier="3" #> <Package>...</Package>
  42. 42. Inside the Black Box: Tiered Biml Files <#@ template tier="1" #> <Connections>...</Connections> <#@ template tier="2" #> <Packages>...</Packages> <#@ template tier="3" #> <Package>...</Package>
  43. 43. Inside the Black Box: Tiered Biml Files <#@ template tier="1" #> <Connections>...</Connections> <#@ template tier="2" #> <Packages>...</Packages> <#@ template tier="3" #> <Package>...</Package>
  44. 44. Inside the Black Box: Tiered Biml Files <#@ template tier="1" #> <Connections>...</Connections> <#@ template tier="2" #> <Packages>...</Packages> <#@ template tier="3" #> <Package>...</Package>
  45. 45. Inside the Black Box: Tiered Biml Files <#@ template tier="1" #> <Connections>...</Connections> <#@ template tier="2" #> <Packages>...</Packages> <#@ template tier="3" #> <Package>...</Package>
  46. 46. Inside the Black Box: Tiered Biml Files <#@ template tier="1" #> <Connections>...</Connections> <#@ template tier="2" #> <Packages>...</Packages> <#@ template tier="3" #> <Package>...</Package>
  47. 47. Inside the Black Box: Tiered Biml Files <#@ template tier="1" #> <Connections>...</Connections> <#@ template tier="2" #> <Packages>...</Packages> <#@ template tier="3" #> <Package>...</Package>
  48. 48. Inside the Black Box: Tiered Biml Files <#@ template tier="1" #> <Connections>...</Connections> <#@ template tier="2" #> <Packages>...</Packages> <#@ template tier="3" #> <Package>...</Package>
  49. 49. Inside the Black Box: Tiered Biml Files <#@ template tier="1" #> <Connections>...</Connections> <#@ template tier="2" #> <Packages>...</Packages> <#@ template tier="3" #> <Package>...</Package>
  50. 50. Inside the Black Box: Tiered Biml Files
  51. 51. How do you use Tiered Biml files? 1. Create Biml files with specified tiers 2. Select all the tiered Biml files 3. Right-click and click Generate SSIS Packages 1 2 3
  52. 52. How does this actually work?
  53. 53. Debugging
  54. 54. Debugging Biml BimlExpress is a "black box": • You can only see the generated SSIS packages • It is not possible to see the compiled Biml first Add a high-tier helper file to save compiled Biml to file • Check Biml For Errors saves compiled Biml without generating packages
  55. 55. SaveFlatBimlToFile.biml Add the helper file to your project… <#@ template tier="999" #> <# System.IO.File.WriteAllText( @"C:BimlFlatBiml.xml", RootNode.GetBiml() ); #>
  56. 56. SaveFlatBimlToFile.biml …with a high tier so it is executed as the last step <#@ template tier="999" #> <# System.IO.File.WriteAllText( @"C:BimlFlatBiml.xml", RootNode.GetBiml() ); #>
  57. 57. SaveFlatBimlToFile.biml It creates a file… <#@ template tier="999" #> <# System.IO.File.WriteAllText( @"C:BimlFlatBiml.xml", RootNode.GetBiml() ); #>
  58. 58. SaveFlatBimlToFile.biml …at the specified path… <#@ template tier="999" #> <# System.IO.File.WriteAllText( @"C:BimlFlatBiml.xml", RootNode.GetBiml() ); #>
  59. 59. SaveFlatBimlToFile.biml …with all the Biml for all the objects in RootNode :) <#@ template tier="999" #> <# System.IO.File.WriteAllText( @"C:BimlFlatBiml.xml", RootNode.GetBiml() ); #>
  60. 60. How do you use this helper file? 1. Create the helper file 2. Select all the Biml files and the helper file 3. Right-click and click Check Biml For Errors 1 2 3
  61. 61. How is this helper file used?
  62. 62. Annotations and ObjectTags
  63. 63. Annotations and ObjectTags Biml Annotations != SSIS Annotations Annotations are string/string Key/Value pairs ObjectTags are string/object Key/Value pairs Use Annotations and ObjectTags to pass code between Biml files
  64. 64. Annotations Create annotations: <OleDbConnection Name="Destination" ConnectionString="…"> <Annotations> <Annotation Tag="Schema">AW2014</Annotation> </Annotations> </OleDbConnection> Use annotations: <# var destinationSchema = RootNode.OleDbConnections["Destination"].GetTag("Schema"); #>
  65. 65. ObjectTags Create ObjectTags: <# RootNode.OleDbConnections["Destination"].ObjectTag["TableFilter"] = new List<string> {"Product","ProductSubcategory","ProductCategory"}; #> Use ObjectTags: <# var TableFilter = (List<string>) RootNode.OleDbConnections["Destination"].ObjectTag["TableFilter"]; #>
  66. 66. LINQ
  67. 67. LINQ (Language-Integrated Query) One language to query: SQL Server Databases XML Documents Datasets Collections Two ways to write queries: SQL-like Syntax Extension Methods
  68. 68. LINQ Extension Methods ..and many, many more! Sort OrderBy, ThenBy Filter Where, OfType Group GroupBy Aggregate Count, Sum Check Collections All, Any, Contains Get Elements First, Last, ElementAt Project Collections Select, SelectMany
  69. 69. LINQ Extension Methods var numConnections = RootNode.Connections.Count() foreach (var table in RootNode.Tables.Where(…)) if (RootNode.Packages.Any(…))
  70. 70. LINQ and Lambda expressions Use lambda expressions to filter or specify values: .Where(table => table.Schema.Name == "Production") .OrderBy(table => table.Name)
  71. 71. LINQ and Lambda expressions For each element in the collection… .Where(table => table.Schema.Name == "Production") .OrderBy(table => table.Name)
  72. 72. LINQ and Lambda expressions …evaluate a criteria or get a value: .Where(table => table.Schema.Name == "Production") .OrderBy(table => table.Name)
  73. 73. LINQ: Filter collections Where() Returns the filtered collection with all elements that meet the criteria RootNode.Tables.Where(t => t.Schema.Name == "Production") OfType() Returns the filtered collection with all elements of the specified type RootNode.Connections.OfType<AstExcelOleDbConnectionNode>()
  74. 74. LINQ: Sort collections OrderBy() Returns the collection sorted by key… RootNode.Tables.OrderBy(t => t.Name) ThenBy() …then sorted by secondary key RootNode.Tables.OrderBy(t => t.Schema.Name) .ThenBy(t => t.Name)
  75. 75. LINQ: Sort collections OrderByDescending() Returns the collection sorted by key… RootNode.Tables.OrderByDescending(t => t.Name) ThenByDescending() …then sorted by secondary key RootNode.Tables.OrderBy(t => t.Schema.Name) .ThenByDescending(t => t.Name)
  76. 76. LINQ: Sort collections Reverse() Returns the collection sorted in reverse order RootNode.Tables.Reverse()
  77. 77. LINQ: Group collections GroupBy() Returns a collection of key-value pairs where each value is a new collection RootNode.Tables.GroupBy(t => t.Schema.Name)
  78. 78. LINQ: Aggregate collections Count() Returns the number of elements in the collection RootNode.Tables.Count() RootNode.Tables.Count(t => t.Schema.Name == "Production")
  79. 79. LINQ: Aggregate collections Sum() Returns the sum of the (numeric) values in the collection RootNode.Tables.Sum(t => t.Columns.Count) Average() Returns the average value of the (numeric) values in the collection RootNode.Tables.Average(t => t.Columns.Count)
  80. 80. LINQ: Aggregate collections Min() Returns the minimum value of the (numeric) values in the collection RootNode.Tables.Min(t => t.Columns.Count) Max() Returns the maximum value of the (numeric) values in the collection RootNode.Tables.Max(t => t.Columns.Count)
  81. 81. LINQ: Check collections All() Returns true if all elements in the collection meet the criteria RootNode.Databases.All(d => d.Name.StartsWith("A")) Any() Returns true if any element in the collection meets the criteria RootNode.Databases.Any(d => d.Name.Contains("DW"))
  82. 82. LINQ: Check collections Contains() Returns true if collection contains element RootNode.Databases.Contains(AdventureWorks2014)
  83. 83. LINQ: Get elements First() Returns the first element in the collection (that meets the criteria) RootNode.Tables.First() RootNode.Tables.First(t => t.Schema.Name == "Production") FirstOrDefault() Returns the first element in the collection or default value (that meets the criteria) RootNode.Tables.FirstOrDefault() RootNode.Tables.FirstOrDefault(t => t.Schema.Name == "Production")
  84. 84. LINQ: Get elements Last() Returns the last element in the collection (that meets the criteria) RootNode.Tables.Last() RootNode.Tables.Last(t => t.Schema.Name == "Production") LastOrDefault() Returns the last element in the collection or default value (that meets the criteria) RootNode.Tables.LastOrDefault() RootNode.Tables.LastOrDefault(t => t.Schema.Name == "Production")
  85. 85. LINQ: Get elements ElementAt() Returns the element in the collection at the specified index RootNode.Tables.ElementAt(42) ElementAtOrDefault() Returns the element in the collection or default value at the specified index RootNode.Tables.ElementAtOrDefault(42)
  86. 86. LINQ: Project collections Select() Creates a new collection from one collection A list of table names: RootNode.Tables.Select(t => t.Name) A list of table and schema names: RootNode.Tables.Select(t => new {t.Name, t.Schema.Name})
  87. 87. LINQ: Project collections SelectMany() Creates a new collection from many collections and merges the collections A list of all columns from all tables: RootNode.Tables.SelectMany(t => t.Columns)
  88. 88. How is LINQ used in Biml projects?
  89. 89. Classes and Methods
  90. 90. C# Classes and Methods BimlScript and LINQ not enough? Need to reuse C# code? Create your own classes and methods!
  91. 91. C# Classes and Methods: From this… public static class HelperClass { public static bool AnnotationTagExists(AstNode node, string tag) { if (node.GetTag(tag) != "") { return true; } else { return false; } } }
  92. 92. C# Classes and Methods: …to this public static class HelperClass { public static bool AnnotationTagExists(AstNode node, string tag) { if (node.GetTag(tag) != "") { return true; } return false; } }
  93. 93. C# Classes and Methods: …to this public static class HelperClass { public static bool AnnotationTagExists(AstNode node, string tag) { return (node.GetTag(tag) != "") ? true : false; } }
  94. 94. C# Classes and Methods: …to this public static class HelperClass { public static bool AnnotationTagExists(AstNode node, string tag) { return (node.GetTag(tag) != ""); } }
  95. 95. Where do you put your C# code? Inline code nuggets Included Biml files with code nuggets Reference code files
  96. 96. C# Classes and Methods: Inline <Biml xmlns="http://schemas.varigence.com/biml.xsd"> <# foreach (var table in RootNode.Tables) { #> <# if (HelperClass.AnnotationTagExists(table, "SourceSchema")) { #> ... <# } #> <# } #> </Biml> <#+ public static class HelperClass { public static bool AnnotationTagExists(AstNode node, string tag) { return (node.GetTag(tag) != "") ? true : false; } } #>
  97. 97. C# Classes and Methods: Included Files <#@ include file="HelperClass.biml" #> <Biml xmlns="http://schemas.varigence.com/biml.xsd"> <# foreach (var table in RootNode.Tables) { #> <# if (HelperClass.AnnotationTagExists(table, "SourceSchema")) { #> ... <# } #> <# } #> </Biml> <#+ public static class HelperClass { public static bool AnnotationTagExists(AstNode node, string tag) { return (node.GetTag(tag) != "") ? true : false; } } #>
  98. 98. C# Classes and Methods: Code Files <#@ code file="HelperClass.cs" #> <Biml xmlns="http://schemas.varigence.com/biml.xsd"> <# foreach (var table in RootNode.Tables) { #> <# if (HelperClass.AnnotationTagExists(table, "SourceSchema")) { #> ... <# } #> <# } #> </Biml> public static class HelperClass { public static bool AnnotationTagExists(AstNode node, string tag) { return (node.GetTag(tag) != "") ? true : false; } }
  99. 99. Extension Methods
  100. 100. Extension Methods "Make it look like the method belongs to an object instead of a helper class"
  101. 101. Extension Methods: From this… <#@ code file="HelperClass.cs" #> <Biml xmlns="http://schemas.varigence.com/biml.xsd"> <# foreach (var table in RootNode.Tables) { #> <# if (HelperClass.AnnotationTagExists(table, "SourceSchema")) { #> ... <# } #> <# } #> </Biml> public static class HelperClass { public static bool AnnotationTagExists(AstNode node, string tag) { return (node.GetTag(tag) != "") ? true : false; } }
  102. 102. Extension Methods: …to this <#@ code file="HelperClass.cs" #> <Biml xmlns="http://schemas.varigence.com/biml.xsd"> <# foreach (var table in RootNode.Tables) { #> <# if (HelperClass.AnnotationTagExists(table, "SourceSchema")) { #> ... <# } #> <# } #> </Biml> public static class HelperClass { public static bool AnnotationTagExists(this AstNode node, string tag) { return (node.GetTag(tag) != "") ? true : false; } }
  103. 103. Extension Methods: …to this <#@ code file="HelperClass.cs" #> <Biml xmlns="http://schemas.varigence.com/biml.xsd"> <# foreach (var table in RootNode.Tables) { #> <# if (table.AnnotationTagExists("SourceSchema")) { #> ... <# } #> <# } #> </Biml> public static class HelperClass { public static bool AnnotationTagExists(this AstNode node, string tag) { return (node.GetTag(tag) != "") ? true : false; } }
  104. 104. Extension Methods: …to this :) <#@ code file="HelperClass.cs" #> <Biml xmlns="http://schemas.varigence.com/biml.xsd"> <# foreach (var table in RootNode.Tables.Where(t => t.AnnotationTagExists("SourceSchema")) { #> ... <# } #> <# } #> </Biml> public static class HelperClass { public static bool AnnotationTagExists(this AstNode node, string tag) { return (node.GetTag(tag) != "") ? true : false; } }
  105. 105. Get things done Start small Start simple Start with ugly code Keep going Expand Improve Deliver often
  106. 106. @cathrinew cathrinewilhelmsen.net linkedin.com/in/cathrinewilhelmsen contact@cathrinewilhelmsen.net slideshare.net/cathrinewilhelmsen Biml resources and references: cathrinewilhelmsen.net/biml
  107. 107. THANK YOU TO OUR SPONSORS

×