Reputation: 6146
I have a number of different Azure Tables I'd like to write to that have some core attributes and some varying ones. I'd like to be write in batches to minimise costs, but I'm struggling to get the types right in the processor function to facilitate this.
What types or additional code should be used to make this function handle the exemplar classes?
using System;
using System.Collections.Generic;
using Microsoft.WindowsAzure.Storage.Table;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
}
static void BatchInsertOrReplace<ITableEntity>(List<ITableEntity> items, CloudTable table)
{
// setup
List<ITableEntity> batch = new List<T>();
TableBatchOperation batchOperation = new TableBatchOperation();
// n-1 batches
foreach (var item in items)
{
batch.Add(item);
batchOperation.InsertOrReplace(item);
if (batch.Count == 100)
{
table.ExecuteBatch(batchOperation);
batchOperation.Clear();
batch.Clear();
}
}
// nth batch
if (batch.Any())
{
table.ExecuteBatch(batchOperation);
}
}
// things I want to be able to push to table storage
public class exampleClass : TableEntity
{
public DateTime rawDate { get; set; }
}
public class exampleClass_deriv1 : exampleClass
{
public string User { get; set; }
public string Device { get; set; }
}
public class exampleClass_deriv2 : exampleClass
{
public string Person { get; set; }
public string Machine { get; set; }
}
}
The code where I'm retrieving entities from Azure Table storage and transforming them currently:
IEnumerable<exampleClass> recs = (from r in mytable
where r.rawDate >= DateTime.Now
select r);
var recsaccount = recs
.Select(r => new exampleClass_deriv1
{
PartitionKey = r.PartitionKey,
RowKey = r.RowKey,
rawDate = r.rawDate,
epochDate = i.epochDate,
User = "Jim",
Device = "Palmpilot"
});
// Desired execution (which errors)
BatchInsertOrReplace(recsaccount.ToList(), mytable);
Simple coercions like (List<ITableEntity>)recsaccount.ToList()
don't work
run.csx(63,30): error CS0030: Cannot convert type 'System.Collections.Generic.List<exampleClass_deriv2>' to 'System.Collections.Generic.List<ITableEntity>'
Making a new List and putting items into it first:
List<ITableEntity> ins = new List<ITableEntity>();
foreach (var blah in recs.ToList())
{
ITableEntity newOne = (ITableEntity)blah;
ins.Add(newOne);
}
BatchInsertOrReplace(ins, mytable);
Results in errors like:
error CS0411: The type arguments for method 'BatchInsertOrReplace<T>(List<ITableEntity>, CloudTable)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
Trying with type prefixes did not alter the situation.
<T>
If I use <T>
in the function definition like
static void BatchInsertOrReplace<T>(List<T> items, CloudTable table)
{
List<T> batch = new List<T>(); // Alt of List<ITableEntity> batch = new List<ITableEntity>();
TableBatchOperation batchOperation = new TableBatchOperation();
foreach (var item in items)
{
batch.Add(item);
batchOperation.InsertOrReplace(item);
if (batch.Count == 100)
{
table.ExecuteBatch(batchOperation);
batchOperation.Clear();
batch.Clear();
}
}
// Process last batch
if (batch.Any())
{
table.ExecuteBatch(batchOperation);
}
}
And then using the function like
BatchInsertOrReplace<exampleClass_deriv2>( recsaccount.ToList(), webhitsAggAccount);
result in messages about batch.Add
and batchOperation.InsertOrReplace
run.csx(128,19): error CS1503: Argument 1: cannot convert from 'T' to 'Microsoft.WindowsAzure.Storage.Table.ITableEntity'
run.csx(129,40): error CS1503: Argument 1: cannot convert from 'T' to 'Microsoft.WindowsAzure.Storage.Table.ITableEntity'
This happens irrespective of whether batch
is constructed as List<ITableEntity>
or List<T>
.
Upvotes: 0
Views: 232
Reputation: 3384
You should make sure the function definition allows a variable type by making its signature use T
but state that T
inherits ITableEntity
. This can be done with a where clause as part of the the first declaration of the function. Your batch function would become:
static void BatchInsertOrReplace<T>(List<T> items, CloudTable table) where T : ITableEntity
{
List<ITableEntity> batch = new List<ITableEntity>();
TableBatchOperation batchOperation = new TableBatchOperation();
foreach (var item in items)
{
batch.Add(item);
batchOperation.InsertOrReplace(item);
if (batch.Count == 100)
{
table.ExecuteBatch(batchOperation);
batchOperation.Clear();
batch.Clear();
}
}
// Process last batch
if (batch.Any())
{
table.ExecuteBatch(batchOperation);
}
}
Upvotes: 1