Entity Group Transactions and Development Storage

Have you gotten the error: InvalidInput One of the request inputs is not valid when performing an Entity Group Transaction against Development Storage?  If so, read on.

Recently, I’ve been working on a Windows Azure project, and it’s wonderful that Azure Table Storage now includes support for “Entity Group Transactions”.

Here's the MSDN Documentation Page that explains how the feature works.  Steve Marx's Blog Posting is a good read, too.

Essentially, this allows one to batch up to 100 insert, update, merge, and delete transactions into a single batch that will either completely succeed or fail.  (All the entities in the the transaction must be in the same partition of the same table, and the payload of the transaction cannot exceed 4MB.)

If you want to use Entity Group Transactions with disparate entity types against Development Storage, there is a problem that you will need to workaround.

Given:

     public class XEntity : TableServiceEntity
    {
        public XEntity(string p, string r)
            : base(p, r) { }
    }

    public class YEntity : TableServiceEntity
    {
        public YEntity(string p, string r)
            : base(p, r) {}
    }

The following Entity Group Transaction will succeed:

     tableServiceContext.AddObject(EntitySetName, new XEntity("Partition1", "Row1"));
    tableServiceContext.AddObject(EntitySetName, new XEntity("Partition1", "Row2"));
    tableServiceContext.SaveChangesWithRetries(SaveChangesOptions.Batch);

However, if the entities include distinct properties (XProp and YProp in this example):

     public class XEntity : TableServiceEntity
    {
        public XEntity(string p, string r)
            : base(p, r) { }

        public string XProp { get; set; }
    }

    public class YEntity : TableServiceEntity
    {
        public YEntity(string p, string r)
            : base(p, r) {}

        public string YProp { get; set; }
    }

The following Entity Group Transaction will fail:

     tableServiceContext.AddObject(EntitySetName, new XEntity("Partition1", "Row1"));
    tableServiceContext.AddObject(EntitySetName, new YEntity("Partition1", "Row2"));
    tableServiceContext.SaveChangesWithRetries(SaveChangesOptions.Batch);

The error will be:

 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
<error xmlns="https://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
    <code>InvalidInput</code>
    <message xml:lang="en-US">0:One of the request inputs is not valid.</message>
</error>

I contacted the Azure team about this issue, and they confirmed that it is a limitation that exists, and will be fixed.

The workaround is simple:

You must store one instance of each entity type appearing in an Entity Group Transaction in the table.  So, do this:

     tableServiceContext.AddObject(EntitySetName, new XEntity("Dummy", "DummyX"));
    tableServiceContext.SaveChangesWithRetries();
    tableServiceContext.AddObject(EntitySetName, new YEntity("Dummy", "DummyY"));
    tableServiceContext.SaveChangesWithRetries();

Whenever your table is empty, and then the above example will work.

Best,

Brian