Azure / azure-cosmos-table-dotnet

.NET SDK for Azure Cosmos Table API
14 stars 5 forks source link

TableEntityAdapter exception when entity object property contains _ #19

Open dgoranov opened 4 years ago

dgoranov commented 4 years ago

The following code generates "Microsoft.Azure.Cosmos.Table: Property delimiter: _ exists in property name" exception when using TableEntityAdapter.

public class TestEntity
{
    public Int32 Count_Current_Panels { get; set; }
    public Int32 Set_Current_Panels { get; set; }
    public Int32 Count_Calibrations { get; set; }
}

TableEntityAdapter entity = new TableEntityAdapter(testEntityInstance, partitionKey, rowKey);

        var table = await EnsureTable(tableName).ConfigureAwait(false);

        TableOperation insertOrReplaceOperation = TableOperation.InsertOrReplace(entity);

        TableResult result = await table.ExecuteAsync(insertOrReplaceOperation).ConfigureAwait(false);

If the TestEntity inherits TableEntity

public class TestEntity : TableEntity  
{
  ...
 }

ExecuteAsync() completes with no exception and there are no issues with Count_Current_Panels property name.

The issue exists only when TestEntity uses TableEntityAdapter and does not inherits TableEntity.

I have tried both Microsoft.Azure.Cosmos.Table.Client, Version=2.0.0.0 and Version 1.0.5

ghost commented 4 years ago

TableEntityAdapter also inherits from TableEntity and wraps your class object inside itself to present a TableEntity. You can see the code for it in this archive here:

https://github.com/Azure/azure-storage-net/blob/v9.3.2/Lib/Common/Table/TableEntityAdapter.cs

I am guessing that's the root of your problems.

EntityAdam commented 4 years ago

Late to the party, but I saw this trying to solve my own problems. TableEntityAdapter uses the _ underscore as a delimiter. You should potentially be able to solve this issue by specifying EntityPropertyConverterOptions and asking it to use a different delimiter, but the property names must adhere to C# Identifier names. The only special character really allowed is _ ... but interestingly enough it actually takes in a string. So the following is horrible, but actually works.

The POCO

    public class MyClass
    {
        public Guid Id { get; set; }
        public string The_Name { get; set; }
        public NestedClass NestedClass { get; set; } = new NestedClass();
    }
    public class NestedClass
    {
        public string NestedName { get; set; } = "Hello, World";
    }

The Adapter

    public class MyClassAdapter : TableEntity
    {
        public MyClass OriginalEntity { get; set; }

        public override void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
        {
            EntityPropertyConverter.ConvertBack<MyClass>(properties, new EntityPropertyConverterOptions() { PropertyNameDelimiter = "_x_" }, operationContext);
        }

        public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
        {
            return EntityPropertyConverter.Flatten(OriginalEntity, new EntityPropertyConverterOptions() { PropertyNameDelimiter = "_x_" }, operationContext);
        }
    }

The result

image

PaulCheng commented 3 years ago

We'll start to deprecate TableEntityAdapter in the future releases.

jhorgan commented 3 years ago

Hi @PaulCheng what should consider in the future if TableEntityAdapter is being deprecated? We currently use it to keep our entities agnostics from any persistence concerns - POCOs.

Thanks.

PaulCheng commented 3 years ago

One has to implement an Adapter like class on his own if he really doesn't want to extend the Entity model from TableEntity. We should document a sample or publish a sample app when we deprecate Adapter.