dtretyakov/WindowsAzure

PartitionKey and RowKey can't be same property

Closed this issue · 7 comments

It's not unusual for us to have the same value for PartitionKey and RowKey. In our EntityMap we provide the same property for ParititionKey and RowKey. This throws an exception.

Could you briefly describe what would you plan to reach when using same property as PK & RK?

We have a lot of unique entities, which each have just a single row in TableStorage. Instead of relying on a fixed partitionkey like "AllCompanies" or something and have thousands and thousands of rows in a single partition, we'd like Azure to possibly partition all keys over unique partitions.

We just specify a single property in our model and specify it as both PartitionKey and RowKey.

Ok, in this case just use a PartitionKeyAttribute without RowKeyAttribute.

This also works with EntityTypeMap ?

No, EntityTypeMap seems to throw an exception when either PartitionKey or RowKey is not set.

Setup:

public class KeyOnly
{
    public string Key { get; set; }
    public string Data { get; set; }
}

public class KeyOnlyMap : EntityTypeMap<KeyOnly>
{
    public KeyOnlyMap()
    {
        PartitionKey(o => o.Key);
    }
}

Test:

[TestFixture]
public class ASETests
{
    [Test]
    public void CanUseKeyOnly()
    {
        EntityTypeMap.RegisterAssembly(GetType().Assembly);
        var storageAccount = CloudStorageAccount.DevelopmentStorageAccount;
        var tableClient = storageAccount.CreateCloudTableClient();
        var keyOnlyTable = new TableSet<KeyOnly>(tableClient);

        keyOnlyTable.CreateIfNotExists();

        var newEntity = new KeyOnly()
        {
            Key = "1",
            Data = "SomeData"
        };

        keyOnlyTable.Add(newEntity);
    }
}

Error:
System.InvalidOperationException : PartitionKey or RowKey attribute should be defined for type 'AzureStorageExtensionsTesting.KeyOnly'.

The issue seems to be from this method in the EntityTypeMap class:

    private void CheckEntityMap()
    {
        // Check whether entity's composite key completely defined
        if (!_nameChanges.ContainsKey(PartitionKeyPropertyName) && !_nameChanges.ContainsValue(RowKeyPropertyName))
        {
            string message = string.Format(Resources.EntityTypeDataMissingKey, _entityType);
            throw new InvalidOperationException(message);
        }
    }

Which I'm not really understanding entirely (shouldn't it be ContainsValue in both cases? and || rather than &&?), but this seems to be by design, as there is a unit test to make sure an InvalidOperation is thrown for entities without a composite key:

    [Fact]
    public void CreateEntityTypeDataWithoutCompositeKey()
    {
        // Arrange
        EntityTypeData<EntityWithoutCompositeKey> typeData = null;

        // Act
        Assert.Throws<InvalidOperationException>(() => { typeData = new EntityTypeData<EntityWithoutCompositeKey>(); });

        // Assert
        Assert.Null(typeData);
    }

However you can just the attribute based mapping without a RowKey and it works just fine.

But actually it's a bug which should be fixed.

It was fixed in version 1.0.2