diff --git a/Madd0.AzureStorageDriver/AzureDriver.cs b/Madd0.AzureStorageDriver/AzureDriver.cs index 4217a6a..b127548 100644 --- a/Madd0.AzureStorageDriver/AzureDriver.cs +++ b/Madd0.AzureStorageDriver/AzureDriver.cs @@ -15,6 +15,8 @@ namespace Madd0.AzureStorageDriver using System.Reflection; using LINQPad.Extensibility.DataContext; using Madd0.AzureStorageDriver.Properties; + using Madd0.UserQuery; + using Microsoft.WindowsAzure.Storage.Table.DataServices; /// /// LINQPad dynamic driver that lets users connect to an Azure Table Storage account. @@ -55,7 +57,9 @@ public override bool ShowConnectionDialog(IConnectionInfo connectionInfo, bool i { if (isNewConnection) { - new StorageAccountProperties(connectionInfo).UseLocalStorage = true; + var prop = new StorageAccountProperties(connectionInfo); + prop.UseHttps = true; + prop.NumberOfRows = 100; } bool? result = new ConnectionDialog(connectionInfo).ShowDialog(); @@ -84,8 +88,8 @@ public override IEnumerable GetAssembliesToAdd() { return new string[] { - "System.Data.Services.Client.dll", - "Microsoft.WindowsAzure.StorageClient.dll" + "Microsoft.WindowsAzure.Storage.dll", + "Microsoft.Data.Services.Client.dll" }; } @@ -97,9 +101,9 @@ public override IEnumerable GetNamespacesToAdd() { return new string[] { - "System.Data.Services.Client", "Microsoft.WindowsAzure", - "Microsoft.WindowsAzure.StorageClient" + "Microsoft.WindowsAzure.Storage", + "Microsoft.WindowsAzure.Storage.Table" }; } @@ -135,9 +139,7 @@ public override object[] GetContextConstructorArguments(IConnectionInfo connecti return new object[] { - storageAccount.TableEndpoint.ToString(), - storageAccount.Credentials, - storageAccount + storageAccount.CreateCloudTableClient() }; } @@ -150,34 +152,9 @@ public override object[] GetContextConstructorArguments(IConnectionInfo connecti public override ParameterDescriptor[] GetContextConstructorParameters(IConnectionInfo connectionInfo) { return new[] - { - new ParameterDescriptor("baseAddress", "System.String"), - new ParameterDescriptor("credentials", "Microsoft.WindowsAzure.StorageCredentials"), - new ParameterDescriptor("account", "Microsoft.WindowsAzure.CloudStorageAccount") + { + new ParameterDescriptor("client", "Microsoft.WindowsAzure.Storage.Table.CloudTableClient ") }; } - - /// - /// Initializes the data context. - /// - /// In this driver, initialization consists of listening to the - /// event in order to extract the requested - /// URI and display it in the SQL tab. - /// The connection info. - /// The context. - /// The execution manager. - public override void InitializeContext(IConnectionInfo connectionInfo, object context, QueryExecutionManager executionManager) - { - /* Write Azure HTTP reuests to SQL tab in LinqPAD - * Skip if SqlTranslationWriter is not available - */ - - var dsContext = context as DataServiceContext; - if (dsContext == null) return; - - if (executionManager.SqlTranslationWriter == null) return; - - dsContext.SendingRequest += (sender, e) => executionManager.SqlTranslationWriter.WriteLine(e.Request.RequestUri); - } } } diff --git a/Madd0.AzureStorageDriver/ConnectionDialog.xaml b/Madd0.AzureStorageDriver/ConnectionDialog.xaml index c3bd036..9de7b89 100644 --- a/Madd0.AzureStorageDriver/ConnectionDialog.xaml +++ b/Madd0.AzureStorageDriver/ConnectionDialog.xaml @@ -1,11 +1,15 @@  + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + Title="Azure Storage Account" + Width="400" + Background="{StaticResource {x:Static SystemColors.ControlBrushKey}}" + ResizeMode="NoResize" + SizeToContent="Height" + WindowStartupLocation="CenterScreen" + mc:Ignorable="d"> - + - + - + TabIndex="2" /> - - - - + + + + + + + + + + Number of lines to sample: + + + + + The number of lines that will be read in order to determine the schema of an Azure Table. + + + + + + + + + + - - + + - + diff --git a/Madd0.AzureStorageDriver/DataContextTemplate.cs b/Madd0.AzureStorageDriver/DataContextTemplate.cs index 9e379c6..f7930b2 100644 --- a/Madd0.AzureStorageDriver/DataContextTemplate.cs +++ b/Madd0.AzureStorageDriver/DataContextTemplate.cs @@ -1,7 +1,7 @@ // ------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version: 10.0.0.0 +// Runtime Version: 12.0.0.0 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -13,51 +13,59 @@ namespace Madd0.AzureStorageDriver using System.Collections; using System.Collections.Generic; + /// + /// Class to produce the template output + /// - #line 1 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" - [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "10.0.0.0")] + #line 1 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "12.0.0.0")] public partial class DataContextTemplate : DataContextTemplateBase { +#line hidden + /// + /// Create the template output + /// public virtual string TransformText() { this.Write("\r\nnamespace "); - #line 6 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 6 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" this.Write(this.ToStringHelper.ToStringWithCulture(this.Namespace)); #line default #line hidden - this.Write("\r\n{\r\n using System;\r\n using System.Data.Services.Client;\r\n using Microso" + - "ft.WindowsAzure;\r\n using Microsoft.WindowsAzure.StorageClient;\r\n\r\n public " + - "class "); + this.Write(@" +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + using Madd0.UserQuery; + using Microsoft.WindowsAzure; + using Microsoft.WindowsAzure.Storage; + using Microsoft.WindowsAzure.Storage.Auth; + using Microsoft.WindowsAzure.Storage.Table; + using Microsoft.WindowsAzure.Storage.Table.DataServices; + + public class "); - #line 13 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 19 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" this.Write(this.ToStringHelper.ToStringWithCulture(this.TypeName)); #line default #line hidden - this.Write(" : TableServiceContext\r\n {\r\n public "); + this.Write("\r\n {\r\n public "); - #line 15 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 21 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" this.Write(this.ToStringHelper.ToStringWithCulture(this.TypeName)); #line default #line hidden - this.Write(@"(string baseAddress, StorageCredentials credentials, CloudStorageAccount account) - : base(baseAddress, credentials) - { - this.TableClient = account.CreateCloudTableClient(); - } - - public CloudTableClient TableClient - { - get; - private set; - } - -"); + this.Write("(CloudTableClient client)\r\n {\r\n this.TableClient = client;\r\n " + + " }\r\n\r\n public CloudTableClient TableClient\r\n {\r\n g" + + "et;\r\n private set;\r\n }\r\n\r\n"); - #line 27 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 32 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" foreach (var table in this.Tables) { @@ -65,38 +73,38 @@ public CloudTableClient TableClient #line default #line hidden - this.Write(" public DataServiceQuery<"); + this.Write(" public ExtendedTableQuery<"); - #line 31 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 36 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" this.Write(this.ToStringHelper.ToStringWithCulture(table.Name)); #line default #line hidden this.Write("Entity> "); - #line 31 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 36 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" this.Write(this.ToStringHelper.ToStringWithCulture(table.Name)); #line default #line hidden - this.Write("\r\n {\r\n get\r\n {\r\n return this.CreateQu" + - "ery<"); + this.Write("\r\n {\r\n get\r\n {\r\n return new ExtendedT" + + "ableQuery<"); - #line 35 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 40 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" this.Write(this.ToStringHelper.ToStringWithCulture(table.Name)); #line default #line hidden - this.Write("Entity>(\""); + this.Write("Entity>(this.TableClient.GetTableReference(\""); - #line 35 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 40 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" this.Write(this.ToStringHelper.ToStringWithCulture(table.Name)); #line default #line hidden - this.Write("\");\r\n }\r\n }\r\n"); + this.Write("\"));\r\n }\r\n }\r\n"); - #line 38 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 43 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" } @@ -105,7 +113,7 @@ public CloudTableClient TableClient #line hidden this.Write(" }\r\n\r\n"); - #line 43 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 48 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" foreach (var table in this.Tables) { @@ -115,14 +123,14 @@ public CloudTableClient TableClient #line hidden this.Write(" public class "); - #line 47 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 52 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" this.Write(this.ToStringHelper.ToStringWithCulture(table.Name)); #line default #line hidden - this.Write("Entity : TableServiceEntity\r\n {\r\n "); + this.Write("Entity : TableEntity\r\n {\r\n "); - #line 49 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 54 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" foreach (var column in table.Columns) { @@ -134,21 +142,21 @@ public CloudTableClient TableClient #line hidden this.Write(" public "); - #line 55 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 60 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" this.Write(this.ToStringHelper.ToStringWithCulture(column.TypeName)); #line default #line hidden this.Write(" "); - #line 55 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 60 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" this.Write(this.ToStringHelper.ToStringWithCulture(column.Name)); #line default #line hidden this.Write("\r\n {\r\n get;\r\n set;\r\n }\r\n "); - #line 60 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 65 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" } } @@ -158,7 +166,7 @@ public CloudTableClient TableClient #line hidden this.Write(" }\r\n"); - #line 65 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 70 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" } @@ -169,9 +177,9 @@ public CloudTableClient TableClient return this.GenerationEnvironment.ToString(); } - #line 70 "C:\Users\madd0\Documents\Personal Projects\Madd0.AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" + #line 75 "C:\Projects\AzureStorageDriver\Madd0.AzureStorageDriver\DataContextTemplate.tt" -private readonly List DefaultProperties = new List { "PartitionKey", "RowKey", "Timestamp" }; +private readonly List DefaultProperties = new List { "PartitionKey", "RowKey", "Timestamp", "ETag" }; public string Namespace { get; set; } @@ -190,7 +198,7 @@ public CloudTableClient TableClient /// /// Base class for this transformation /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "10.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "12.0.0.0")] public class DataContextTemplateBase { #region Fields @@ -445,6 +453,9 @@ public string ToStringWithCulture(object objectToConvert) } } private ToStringInstanceHelper toStringHelperField = new ToStringInstanceHelper(); + /// + /// Helper to produce culture-oriented representation of an object as a string + /// public ToStringInstanceHelper ToStringHelper { get diff --git a/Madd0.AzureStorageDriver/DataContextTemplate.tt b/Madd0.AzureStorageDriver/DataContextTemplate.tt index 1bf623f..4fa8c03 100644 --- a/Madd0.AzureStorageDriver/DataContextTemplate.tt +++ b/Madd0.AzureStorageDriver/DataContextTemplate.tt @@ -6,33 +6,38 @@ namespace <#= this.Namespace #> { using System; - using System.Data.Services.Client; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + using Madd0.UserQuery; using Microsoft.WindowsAzure; - using Microsoft.WindowsAzure.StorageClient; + using Microsoft.WindowsAzure.Storage; + using Microsoft.WindowsAzure.Storage.Auth; + using Microsoft.WindowsAzure.Storage.Table; + using Microsoft.WindowsAzure.Storage.Table.DataServices; - public class <#= this.TypeName #> : TableServiceContext + public class <#= this.TypeName #> { - public <#= this.TypeName #>(string baseAddress, StorageCredentials credentials, CloudStorageAccount account) - : base(baseAddress, credentials) + public <#= this.TypeName #>(CloudTableClient client) { - this.TableClient = account.CreateCloudTableClient(); + this.TableClient = client; } - public CloudTableClient TableClient - { - get; - private set; - } + public CloudTableClient TableClient + { + get; + private set; + } <# foreach (var table in this.Tables) { #> - public DataServiceQuery<<#= table.Name #>Entity> <#= table.Name #> + public ExtendedTableQuery<<#= table.Name #>Entity> <#= table.Name #> { get { - return this.CreateQuery<<#= table.Name #>Entity>("<#= table.Name #>"); + return new ExtendedTableQuery<<#= table.Name #>Entity>(this.TableClient.GetTableReference("<#= table.Name #>")); } } <# @@ -44,7 +49,7 @@ foreach (var table in this.Tables) foreach (var table in this.Tables) { #> - public class <#= table.Name #>Entity : TableServiceEntity + public class <#= table.Name #>Entity : TableEntity { <# foreach (var column in table.Columns) @@ -68,7 +73,7 @@ foreach (var table in this.Tables) } <#+ -private readonly List DefaultProperties = new List { "PartitionKey", "RowKey", "Timestamp" }; +private readonly List DefaultProperties = new List { "PartitionKey", "RowKey", "Timestamp", "ETag" }; public string Namespace { get; set; } diff --git a/Madd0.AzureStorageDriver/DevDeploy.bat b/Madd0.AzureStorageDriver/DevDeploy.bat index 6c14fd6..3e84b1f 100644 --- a/Madd0.AzureStorageDriver/DevDeploy.bat +++ b/Madd0.AzureStorageDriver/DevDeploy.bat @@ -5,6 +5,6 @@ rem It copies the output .DLL (and .PDB) to LINQPad's drivers folder, so that L rem picks up the drivers immediately (without needing to click 'Add Driver'). rem -xcopy /i/y Madd0.AzureStorageDriver.dll "%AllUsersProfile%\LINQPad\Drivers\DataContext\4.0\Madd0.AzureStorageDriver (47842961fb3025d7)\" -xcopy /i/y Madd0.AzureStorageDriver.pdb "%AllUsersProfile%\LINQPad\Drivers\DataContext\4.0\Madd0.AzureStorageDriver (47842961fb3025d7)\" -xcopy /i/y Microsoft.WindowsAzure.StorageClient.dll "%AllUsersProfile%\LINQPad\Drivers\DataContext\4.0\Madd0.AzureStorageDriver (47842961fb3025d7)\" +xcopy /i/y *.dll "%AllUsersProfile%\LINQPad\Drivers\DataContext\4.0\Madd0.AzureStorageDriver (47842961fb3025d7)\" +xcopy /i/y *.pdb "%AllUsersProfile%\LINQPad\Drivers\DataContext\4.0\Madd0.AzureStorageDriver (47842961fb3025d7)\" +rem xcopy /i/y Microsoft.WindowsAzure.StorageClient.dll "%AllUsersProfile%\LINQPad\Drivers\DataContext\4.0\Madd0.AzureStorageDriver (47842961fb3025d7)\" diff --git a/Madd0.AzureStorageDriver/Madd0.AzureStorageDriver.csproj b/Madd0.AzureStorageDriver/Madd0.AzureStorageDriver.csproj index 17cabc8..93f08ee 100644 --- a/Madd0.AzureStorageDriver/Madd0.AzureStorageDriver.csproj +++ b/Madd0.AzureStorageDriver/Madd0.AzureStorageDriver.csproj @@ -44,23 +44,34 @@ ..\References\LINQPad.exe False - - False - ..\packages\Microsoft.WindowsAzure.ConfigurationManager.1.7.0.3\lib\net35-full\Microsoft.WindowsAzure.Configuration.dll + + ..\packages\Microsoft.Data.Edm.5.6.0\lib\net40\Microsoft.Data.Edm.dll - - ..\packages\WindowsAzure.Storage.1.7.0.0\lib\net35-full\Microsoft.WindowsAzure.StorageClient.dll - True + + ..\packages\Microsoft.Data.OData.5.6.0\lib\net40\Microsoft.Data.OData.dll + + + ..\packages\Microsoft.Data.Services.Client.5.6.0\lib\net40\Microsoft.Data.Services.Client.dll + + + ..\packages\Microsoft.WindowsAzure.ConfigurationManager.1.8.0.0\lib\net35-full\Microsoft.WindowsAzure.Configuration.dll + + + ..\packages\WindowsAzure.Storage.4.2.0\lib\net40\Microsoft.WindowsAzure.Storage.dll + + + ..\packages\Newtonsoft.Json.5.0.6\lib\net40\Newtonsoft.Json.dll - + + + ..\packages\System.Spatial.5.6.0\lib\net40\System.Spatial.dll + - - @@ -90,6 +101,7 @@ + diff --git a/Madd0.AzureStorageDriver/Model/GenericEntity.cs b/Madd0.AzureStorageDriver/Model/GenericEntity.cs index 3fb75a2..044b808 100644 --- a/Madd0.AzureStorageDriver/Model/GenericEntity.cs +++ b/Madd0.AzureStorageDriver/Model/GenericEntity.cs @@ -9,7 +9,7 @@ namespace Madd0.AzureStorageDriver { using System.Collections.Generic; - using Microsoft.WindowsAzure.StorageClient; + using Microsoft.WindowsAzure.Storage.Table; /// /// Represents a generic entity from table storage. @@ -21,7 +21,7 @@ namespace Madd0.AzureStorageDriver /// dictionary as string values, where the property name is the property in /// the dictionary. /// - public class GenericEntity : TableServiceEntity + public class GenericEntity : TableEntity { /// /// Holds the property data. diff --git a/Madd0.AzureStorageDriver/Model/StorageAccountProperties.cs b/Madd0.AzureStorageDriver/Model/StorageAccountProperties.cs index d81d32a..43d93cd 100644 --- a/Madd0.AzureStorageDriver/Model/StorageAccountProperties.cs +++ b/Madd0.AzureStorageDriver/Model/StorageAccountProperties.cs @@ -8,11 +8,11 @@ namespace Madd0.AzureStorageDriver { - using System; using System.Xml.Linq; using LINQPad.Extensibility.DataContext; using Madd0.AzureStorageDriver.Properties; - using Microsoft.WindowsAzure; + using Microsoft.WindowsAzure.Storage; + using Microsoft.WindowsAzure.Storage.Auth; /// /// Wrapper to expose typed properties over ConnectionInfo.DriverData. @@ -126,6 +126,15 @@ public string AccountKey } } + /// + /// Gets or sets the number of rows to sample to determine a table's schema. + /// + public int NumberOfRows + { + get { return (int?)this._driverData.Element("NumberOfRows") ?? 1; } + set { this._driverData.SetElementValue("NumberOfRows", value); } + } + /// /// Gets a instace for the current connection. /// @@ -139,7 +148,7 @@ public CloudStorageAccount GetStorageAccount() } else { - return new CloudStorageAccount(new StorageCredentialsAccountAndKey(this.AccountName, this.AccountKey), this.UseHttps); + return new CloudStorageAccount(new StorageCredentials(this.AccountName, this.AccountKey), this.UseHttps); } } diff --git a/Madd0.AzureStorageDriver/SchemaBuilder.cs b/Madd0.AzureStorageDriver/SchemaBuilder.cs index 9781ba7..b6ec952 100644 --- a/Madd0.AzureStorageDriver/SchemaBuilder.cs +++ b/Madd0.AzureStorageDriver/SchemaBuilder.cs @@ -10,15 +10,13 @@ namespace Madd0.AzureStorageDriver using System; using System.CodeDom.Compiler; using System.Collections.Generic; - using System.Data.Services.Client; using System.IO; using System.Linq; using System.Reflection; - using System.Xml.Linq; using LINQPad.Extensibility.DataContext; using Madd0.AzureStorageDriver.Properties; using Microsoft.CSharp; - using Microsoft.WindowsAzure.StorageClient; + using Microsoft.WindowsAzure.Storage.Table; /// /// Provides the methods necessary to determining the storage account's schema and to building @@ -26,11 +24,6 @@ namespace Madd0.AzureStorageDriver /// internal static class SchemaBuilder { - // XML namespaces - private static readonly XNamespace AtomNS = "http://www.w3.org/2005/Atom"; - private static readonly XNamespace dNS = "http://schemas.microsoft.com/ado/2007/08/dataservices"; - private static readonly XNamespace mNS = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"; - // Names of columns that should be marked as table keys. private static readonly List keyColumns = new List { "PartitionKey", "RowKey" }; @@ -71,46 +64,34 @@ private static IEnumerable GetModel(StorageAccountProperties propert { 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 + Name = tableName.Name }).ToList(); // Then go through them foreach (var table in model) { - // Read the first entity to determine the table's schema - var firstRow = dataContext.CreateQuery(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 + 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 { - // 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) - }; - } + 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; @@ -148,9 +129,11 @@ private static void BuildAssembly(AssemblyName name, string driverFolder, string var dependencies = new[] { "System.dll", - "System.Core.dll", - "System.Data.Services.Client.dll", - Path.Combine(driverFolder, "Microsoft.WindowsAzure.StorageClient.dll") + "System.Core.dll", + "System.Xml.dll", + Path.Combine(driverFolder, "Madd0.AzureStorageDriver.dll"), + Path.Combine(driverFolder, "Microsoft.WindowsAzure.Storage.dll"), + Path.Combine(driverFolder, "Microsoft.Data.Services.Client.dll") }; // Use the CSharpCodeProvider to compile. Since the driver is .NET 4.0, the typed assembly should be also @@ -192,62 +175,30 @@ private static List GetSchema(IEnumerable model) }).ToList(); } - /// - /// Called when the data services data context has finished trying to deserialize and entity - /// from table storage. - /// - /// The sender. - /// The instance containing the event data. - private static void OnReadingEntity(object sender, ReadingWritingEntityEventArgs e) - { - GenericEntity entity = e.Entity as GenericEntity; - - if (null == entity) - { - return; - } - - entity.TableName = e.Data.Element(AtomNS + "link").Attribute("title").Value; - - var q = from p in e.Data.Element(AtomNS + "content").Element(mNS + "properties").Elements() - select new - { - Name = p.Name.LocalName, - IsNull = string.Equals("true", p.Attribute(mNS + "null") == null ? null : p.Attribute(mNS + "null").Value, StringComparison.OrdinalIgnoreCase), - TypeName = p.Attribute(mNS + "type") == null ? "Edm.String" : p.Attribute(mNS + "type").Value, - p.Value - }; - - foreach (var dp in q) - { - entity[dp.Name] = dp.TypeName; - } - } - /// /// Gets the C# type equivalent of an entity data model (Edm) type. /// /// The Edm type. /// The C# type. - private static string GetType(string type) + private static string GetType(EdmType type) { switch (type) { - case "Edm.Binary": + case EdmType.Binary: return "byte[]"; - case "Edm.Boolean": + case EdmType.Boolean: return "bool?"; - case "Edm.DateTime": + case EdmType.DateTime: return "DateTime?"; - case "Edm.Double": + case EdmType.Double: return "double?"; - case "Edm.Guid": + case EdmType.Guid: return "Guid?"; - case "Edm.Int32": + case EdmType.Int32: return "int?"; - case "Edm.Int64": + case EdmType.Int64: return "long?"; - case "Edm.String": + case EdmType.String: return "string"; default: throw new NotSupportedException(string.Format(Exceptions.TypeNotSupported, type)); diff --git a/Madd0.AzureStorageDriver/UserQuery/ExtendedTableQuery.cs b/Madd0.AzureStorageDriver/UserQuery/ExtendedTableQuery.cs new file mode 100644 index 0000000..f974000 --- /dev/null +++ b/Madd0.AzureStorageDriver/UserQuery/ExtendedTableQuery.cs @@ -0,0 +1,172 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) 2014 Mauricio DIAZ ORLICH. +// Code licensed under the MIT X11 license. +// +// Mauricio DIAZ ORLICH +//----------------------------------------------------------------------- + +namespace Madd0.UserQuery +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Text; + using Microsoft.WindowsAzure.Storage; + using Microsoft.WindowsAzure.Storage.Table; + + public class ExtendedTableQuery + { + + public TextWriter QueryWriter + { + get; + set; + } + + } + public class ExtendedTableQuery : ExtendedTableQuery, IEnumerable, IEnumerable, IQueryable, IQueryable + where TElement : ITableEntity, new() + { + private CloudTable _table; + private TableQuery _query; + + public ExtendedTableQuery(CloudTable table) + { + _table = table; + _query = table.CreateQuery(); + } + + public ICancellableAsyncResult BeginExecuteSegmented(TableContinuationToken currentToken, TableRequestOptions requestOptions, OperationContext operationContext, System.AsyncCallback callback, object state) + { + return _query.BeginExecuteSegmented(currentToken, requestOptions, operationContext, callback, state); + } + + public ICancellableAsyncResult BeginExecuteSegmented(TableContinuationToken currentToken, System.AsyncCallback callback, object state) + { + return _query.BeginExecuteSegmented(currentToken, callback, state); + } + + public TableQuerySegment EndExecuteSegmented(System.IAsyncResult asyncResult) + { + return _query.EndExecuteSegmented(asyncResult); + } + + public System.Collections.Generic.IEnumerable Execute(TableRequestOptions requestOptions = null, OperationContext operationContext = null) + { + return _query.Execute(requestOptions, operationContext); + } + + public TableQuerySegment ExecuteSegmented(TableContinuationToken continuationToken, TableRequestOptions requestOptions = null, OperationContext operationContext = null) + { + return _query.ExecuteSegmented(continuationToken, requestOptions, operationContext); + } + + public System.Threading.Tasks.Task> ExecuteSegmentedAsync(TableContinuationToken currentToken, TableRequestOptions requestOptions, OperationContext operationContext, System.Threading.CancellationToken cancellationToken) + { + return _query.ExecuteSegmentedAsync(currentToken, requestOptions, operationContext, cancellationToken); + } + + public System.Threading.Tasks.Task> ExecuteSegmentedAsync(TableContinuationToken currentToken, TableRequestOptions requestOptions, OperationContext operationContext) + { + return _query.ExecuteSegmentedAsync(currentToken, requestOptions, operationContext); + } + + public System.Threading.Tasks.Task> ExecuteSegmentedAsync(TableContinuationToken currentToken, System.Threading.CancellationToken cancellationToken) + { + return _query.ExecuteSegmentedAsync(currentToken, cancellationToken); + } + + public System.Threading.Tasks.Task> ExecuteSegmentedAsync(TableContinuationToken currentToken) + { + return _query.ExecuteSegmentedAsync(currentToken); + } + + public System.Collections.Generic.IEnumerator GetEnumerator() + { + return _query.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + public TableQuery Select(System.Collections.Generic.IList columns) + { + return _query.Select(columns); + } + + public TableQuery Take(int? take) + { + return _query.Take(take); + } + + public TableQuery Where(string filter) + { + return _query.Where(filter); + } + + public System.Type ElementType + { + get + { + return _query.ElementType; + } + } + + public System.Linq.Expressions.Expression Expression + { + get + { + return _query.Expression; + } + } + + public string FilterString + { + set + { + _query.FilterString = value; + } + get + { + return _query.FilterString; + } + } + + public System.Linq.IQueryProvider Provider + { + get + { + return _query.Provider; + } + } + + public System.Collections.Generic.IList SelectColumns + { + set + { + _query.SelectColumns = value; + } + get + { + return _query.SelectColumns; + } + } + + public int? TakeCount + { + set + { + _query.TakeCount = value; + } + get + { + return _query.TakeCount; + } + } + } +} diff --git a/Madd0.AzureStorageDriver/packages.config b/Madd0.AzureStorageDriver/packages.config index 13d7127..afe0158 100644 --- a/Madd0.AzureStorageDriver/packages.config +++ b/Madd0.AzureStorageDriver/packages.config @@ -1,5 +1,10 @@  - - + + + + + + + \ No newline at end of file