/// <summary> /// Build a model of the current Azure storage account. This model will be used to generate /// the typed code as well as the schema needed by LINQPad. /// </summary> /// <param name="properties">The current configuration.</param> /// <returns>A list of <see cref="CloudTable"/> instances that describe the current Azure /// storage model.</returns> private static IEnumerable <CloudTable> GetModel(StorageAccountProperties properties) { // make sure that we can make at least ModelLoadMaxParallelism concurrent // cals to azure table storage ServicePointManager.DefaultConnectionLimit = properties.ModelLoadMaxParallelism; var tableClient = properties.GetStorageAccount().CreateCloudTableClient(); // First get a list of all tables var model = (from tableName in tableClient.ListTables() select new CloudTable { Name = tableName.Name }).ToList(); var options = new ParallelOptions() { MaxDegreeOfParallelism = properties.ModelLoadMaxParallelism }; Parallel.ForEach(model, options, table => { var threadTableClient = properties.GetStorageAccount().CreateCloudTableClient(); var tableColumns = threadTableClient.GetTableReference(table.Name).ExecuteQuery(new TableQuery().Take(properties.NumberOfRows)) .SelectMany(row => row.Properties) .GroupBy(column => column.Key) .Select(grp => new TableColumn { Name = grp.Key, TypeName = GetType(grp.First().Value.PropertyType) }); var baseColumns = new List <TableColumn> { new TableColumn { Name = "PartitionKey", TypeName = GetType(EdmType.String) }, new TableColumn { Name = "RowKey", TypeName = GetType(EdmType.String) }, new TableColumn { Name = "Timestamp", TypeName = GetType(EdmType.DateTime) }, new TableColumn { Name = "ETag", TypeName = GetType(EdmType.String) } }; table.Columns = tableColumns.Concat(baseColumns).ToArray(); }); return(model); }
/// <summary> /// Build a model of the current Azure storage account. This model will be used to generate /// the typed code as well as the schema needed by LINQPad. /// </summary> /// <param name="properties">The current configuration.</param> /// <returns>A list of <see cref="CloudTable"/> instances that describe the current Azure /// storage model.</returns> private static IEnumerable <CloudTable> GetModel(StorageAccountProperties properties) { var tableClient = properties.GetStorageAccount().CreateCloudTableClient(); var dataContext = tableClient.GetDataServiceContext(); // Entity deserialization has to be handled in a particular way since we are using a GenericEntity to // to read all tables dataContext.ReadingEntity += OnReadingEntity; // First get a list of all tables var model = (from tableName in tableClient.ListTables() select new CloudTable { Name = tableName }).ToList(); // Then go through them foreach (var table in model) { // Read the first entity to determine the table's schema var firstRow = dataContext.CreateQuery <GenericEntity>(table.Name).Take(1).FirstOrDefault(); if (null == firstRow) { // If there is no first entity, set a list with the mandatory PartitionKey, RowKey and // Timestamp columns, which we know always exist table.Columns = new[] { new TableColumn { Name = "PartitionKey", TypeName = GetType("Edm.String") }, new TableColumn { Name = "RowKey", TypeName = GetType("Edm.String") }, new TableColumn { Name = "Timestamp", TypeName = GetType("Edm.DateTime") } }; } else { // Otherwise create a new TableColumn for each type table.Columns = from columnName in firstRow.Properties select new TableColumn { Name = columnName.Key, TypeName = GetType(columnName.Value) }; } } return(model); }
/// <summary> /// Gets the context constructor arguments. /// </summary> /// <param name="connectionInfo">The connection info.</param> /// <returns>An ordered collection of objects to pass to the data context as arguments.</returns> public override object[] GetContextConstructorArguments(IConnectionInfo connectionInfo) { var properties = new StorageAccountProperties(connectionInfo); var storageAccount = properties.GetStorageAccount(); return(new object[] { storageAccount.CreateCloudTableClient() }); }
/// <summary> /// Shows the connection dialog. /// </summary> /// <param name="connectionInfo">The connection info.</param> /// <param name="isNewConnection">if set to <c>true</c> [is new connection].</param> /// <returns></returns> public override bool ShowConnectionDialog(IConnectionInfo connectionInfo, bool isNewConnection) { if (isNewConnection) { var prop = new StorageAccountProperties(connectionInfo); prop.UseHttps = true; prop.NumberOfRows = 100; } bool?result = new ConnectionDialog(connectionInfo).ShowDialog(); return(result == true); }
/// <summary>Gets the text to display in the root Schema Explorer node for a given connection info.</summary> /// <param name="cxInfo">The connection information.</param> /// <returns>The text to display in the root Schema Explorer node for a given connection info</returns> public override string GetConnectionDescription(IConnectionInfo cxInfo) { var accountProperties = new StorageAccountProperties(cxInfo); var description = accountProperties.DisplayName; if (accountProperties.AzureEnvironment != AzureEnvironment.AzureGlobalCloud) { description += $" ({accountProperties.AzureEnvironment.Name})"; } return(description); }
/// <summary> /// Gets the context constructor arguments. /// </summary> /// <param name="connectionInfo">The connection info.</param> /// <returns>An ordered collection of objects to pass to the data context as arguments.</returns> public override object[] GetContextConstructorArguments(IConnectionInfo connectionInfo) { var properties = new StorageAccountProperties(connectionInfo); var storageAccount = properties.GetStorageAccount(); return(new object[] { storageAccount.TableEndpoint.ToString(), storageAccount.Credentials, storageAccount }); }
/// <summary> /// Shows the connection dialog. /// </summary> /// <param name="connectionInfo">The connection info.</param> /// <param name="isNewConnection">if set to <c>true</c> [is new connection].</param> /// <returns></returns> public override bool ShowConnectionDialog(IConnectionInfo cxInfo, ConnectionDialogOptions dialogOptions) { if (dialogOptions.IsNewConnection) { _ = new StorageAccountProperties(cxInfo) { UseHttps = true, NumberOfRows = 100 }; } bool?result = new ConnectionDialog(cxInfo).ShowDialog(); return(result == true); }
/// <summary> /// Gets the schema and builds the assembly. /// </summary> /// <param name="properties">The current configuration.</param> /// <param name="name">The <see cref="AssemblyName"/> instace of the assembly being created.</param> /// <param name="namepace">The namespace to be used in the generated code.</param> /// <param name="typeName">Name of the type of the typed data context.</param> /// <returns>A list of <see cref="ExplorerItem"/> instaces that describes the current schema.</returns> public static List <ExplorerItem> GetSchemaAndBuildAssembly(StorageAccountProperties properties, AssemblyName name, string @namepace, string typeName) { // Get the model from Azure storage var model = GetModel(properties); // Generate C# code var code = GenerateCode(typeName, @namepace, model); // And compile the code into the assembly BuildAssembly(name, code); // Generate the schema for LINQPad List <ExplorerItem> schema = GetSchema(model); return(schema); }
/// <summary> /// Gets the schema and builds the assembly. /// </summary> /// <param name="properties">The current configuration.</param> /// <param name="driverFolder">The driver folder. Used to resolve dependencies.</param> /// <param name="name">The <see cref="AssemblyName"/> instace of the assembly being created.</param> /// <param name="namepace">The namespace to be used in the generated code.</param> /// <param name="typeName">Name of the type of the typed data context.</param> /// <returns>A list of <see cref="ExplorerItem"/> instaces that describes the current schema.</returns> public static List<ExplorerItem> GetSchemaAndBuildAssembly(StorageAccountProperties properties, string driverFolder, AssemblyName name, string @namepace, string typeName) { // Get the model from Azure storage var model = GetModel(properties); // Generate C# code var code = GenerateCode(typeName, @namepace, model); // And compile the code into the assembly BuildAssembly(name, driverFolder, code); // Generate the schema for LINQPad List<ExplorerItem> schema = GetSchema(model); return schema; }
/// <summary> /// Build a model of the current Azure storage account. This model will be used to generate /// the typed code as well as the schema needed by LINQPad. /// </summary> /// <param name="properties">The current configuration.</param> /// <returns>A list of <see cref="CloudTable"/> instances that describe the current Azure /// storage model.</returns> private static IEnumerable <CloudTable> GetModel(StorageAccountProperties properties) { var tableClient = properties.GetStorageAccount().CreateCloudTableClient(); // First get a list of all tables var model = (from tableName in tableClient.ListTables() select new CloudTable { Name = tableName.Name }).ToList(); // Then go through them foreach (var table in model) { var tableColumns = tableClient.GetTableReference(table.Name).ExecuteQuery(new TableQuery().Take(properties.NumberOfRows)) .SelectMany(row => row.Properties) .GroupBy(column => column.Key) .Select(grp => new TableColumn { Name = grp.Key, TypeName = GetType(grp.First().Value.PropertyType) }); var baseColumns = new List <TableColumn> { new TableColumn { Name = "PartitionKey", TypeName = GetType(EdmType.String) }, new TableColumn { Name = "RowKey", TypeName = GetType(EdmType.String) }, new TableColumn { Name = "Timestamp", TypeName = GetType(EdmType.DateTime) }, new TableColumn { Name = "ETag", TypeName = GetType(EdmType.String) } }; table.Columns = tableColumns.Concat(baseColumns).ToArray(); } return(model); }
/// <summary> /// Gets the context constructor arguments. /// </summary> /// <param name="connectionInfo">The connection info.</param> /// <returns>An ordered collection of objects to pass to the data context as arguments.</returns> public override object[] GetContextConstructorArguments(IConnectionInfo connectionInfo) { var properties = new StorageAccountProperties(connectionInfo); var storageAccount = properties.GetStorageAccount(); return new object[] { storageAccount.CreateCloudTableClient() }; }
/// <summary> /// Gets the context constructor arguments. /// </summary> /// <param name="connectionInfo">The connection info.</param> /// <returns>An ordered collection of objects to pass to the data context as arguments.</returns> public override object[] GetContextConstructorArguments(IConnectionInfo connectionInfo) { var properties = new StorageAccountProperties(connectionInfo); var storageAccount = properties.GetStorageAccount(); return new object[] { storageAccount.TableEndpoint.ToString(), storageAccount.Credentials, storageAccount }; }
/// <summary> /// Build a model of the current Azure storage account. This model will be used to generate /// the typed code as well as the schema needed by LINQPad. /// </summary> /// <param name="properties">The current configuration.</param> /// <returns>A list of <see cref="CloudTable"/> instances that describe the current Azure /// storage model.</returns> private static IEnumerable<CloudTable> GetModel(StorageAccountProperties properties) { var tableClient = properties.GetStorageAccount().CreateCloudTableClient(); var dataContext = tableClient.GetDataServiceContext(); // Entity deserialization has to be handled in a particular way since we are using a GenericEntity to // to read all tables dataContext.ReadingEntity += OnReadingEntity; // First get a list of all tables var model = (from tableName in tableClient.ListTables() select new CloudTable { Name = tableName }).ToList(); // Then go through them foreach (var table in model) { // Read the first entity to determine the table's schema var firstRow = dataContext.CreateQuery<GenericEntity>(table.Name).Take(1).FirstOrDefault(); if (null == firstRow) { // If there is no first entity, set a list with the mandatory PartitionKey, RowKey and // Timestamp columns, which we know always exist table.Columns = new[] { new TableColumn { Name = "PartitionKey", TypeName = GetType("Edm.String") }, new TableColumn { Name = "RowKey", TypeName = GetType("Edm.String") }, new TableColumn { Name = "Timestamp", TypeName = GetType("Edm.DateTime") } }; } else { // Otherwise create a new TableColumn for each type table.Columns = from columnName in firstRow.Properties select new TableColumn { Name = columnName.Key, TypeName = GetType(columnName.Value) }; } } return model; }
/// <summary> /// Build a model of the current Azure storage account. This model will be used to generate /// the typed code as well as the schema needed by LINQPad. /// </summary> /// <param name="properties">The current configuration.</param> /// <returns>A list of <see cref="CloudTable"/> instances that describe the current Azure /// storage model.</returns> private static IEnumerable<CloudTable> GetModel(StorageAccountProperties properties) { var tableClient = properties.GetStorageAccount().CreateCloudTableClient(); // First get a list of all tables var model = (from tableName in tableClient.ListTables() select new CloudTable { Name = tableName.Name }).ToList(); // Then go through them foreach (var table in model) { var tableColumns = tableClient.GetTableReference(table.Name).ExecuteQuery(new TableQuery().Take(properties.NumberOfRows)) .SelectMany(row => row.Properties) .GroupBy(column => column.Key) .Select(grp => new TableColumn { Name = grp.Key, TypeName = GetType(grp.First().Value.PropertyType) }); var baseColumns = new List<TableColumn> { new TableColumn { Name = "PartitionKey", TypeName = GetType(EdmType.String) }, new TableColumn { Name = "RowKey", TypeName = GetType(EdmType.String) }, new TableColumn { Name = "Timestamp", TypeName = GetType(EdmType.DateTime) }, new TableColumn { Name = "ETag", TypeName = GetType(EdmType.String) } }; table.Columns = tableColumns.Concat(baseColumns).ToArray(); } return model; }
/// <summary> /// Initializes a new instance of the <see cref="ConnectionDialog"/> class. /// </summary> /// <param name="connectionInfo">The connection info.</param> public ConnectionDialog(IConnectionInfo connectionInfo) { InitializeComponent(); DataContext = new StorageAccountProperties(connectionInfo); }
/// <summary> /// Shows the connection dialog. /// </summary> /// <param name="connectionInfo">The connection info.</param> /// <param name="isNewConnection">if set to <c>true</c> [is new connection].</param> /// <returns></returns> public override bool ShowConnectionDialog(IConnectionInfo connectionInfo, bool isNewConnection) { if (isNewConnection) { var prop = new StorageAccountProperties(connectionInfo); prop.UseHttps = true; prop.NumberOfRows = 100; } bool? result = new ConnectionDialog(connectionInfo).ShowDialog(); return result == true; }