Domanda

Sto lavorando con Windows Azure Storage Table ed avere un requisito semplice: aggiungere una nuova riga, sovrascrivendo qualsiasi riga esistente con quella PartitionKey / RowKey. Tuttavia, salvare le modifiche sempre genera un'eccezione, anche se mi passate l'opzione ReplaceOnUpdate:

tableServiceContext.AddObject(TableName, entity);
tableServiceContext.SaveChangesWithRetries(SaveChangesOptions.ReplaceOnUpdate);

Se l'entità esiste già getta:

System.Data.Services.Client.DataServiceRequestException: An error occurred while processing this request. ---> System.Data.Services.Client.DataServiceClientException: <?xml version="1.0" encoding="utf-8" standalone="yes"?>
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <code>EntityAlreadyExists</code>
  <message xml:lang="en-AU">The specified entity already exists.</message>
</error>

Devo davvero a interrogare manualmente per la riga esistente prima e call DeleteObject su di esso? Che sembra molto lento. Sicuramente c'è un modo migliore?

È stato utile?

Soluzione

Come hai trovato, non si può semplicemente aggiungere un altro elemento che ha la stessa chiave chiave di fila e la partizione, quindi sarà necessario eseguire una query per verificare se l'oggetto esiste già. In situazioni come questa lo trovo utile a guardare il Azure REST documentazione API per vedere cosa è disponibile per la libreria client di archiviazione. Vedrai che ci sono metodi distinti per inserimento e l'aggiornamento . Il ReplaceOnUpdate ha effetto solo quando si è l'aggiornamento, non inserendo .

Mentre si potrebbe eliminare l'elemento esistente e quindi aggiungere il nuovo, si può solo aggiornare quello esistente (risparmiando un andata e ritorno per lo stoccaggio). Il vostro codice potrebbe essere simile a questo:

var existsQuery = from e
                    in tableServiceContext.CreateQuery<MyEntity>(TableName)
                    where
                    e.PartitionKey == objectToUpsert.PartitionKey
                    && e.RowKey == objectToUpsert.RowKey
                    select e;

MyEntity existingObject = existsQuery.FirstOrDefault();

if (existingObject == null)
{
    tableServiceContext.AddObject(TableName, objectToUpsert);
}
else
{
    existingObject.Property1 = objectToUpsert.Property1;
    existingObject.Property2 = objectToUpsert.Property2;

    tableServiceContext.UpdateObject(existingObject);
}

tableServiceContext.SaveChangesWithRetries(SaveChangesOptions.ReplaceOnUpdate);

Modifica Mentre corrette al momento della scrittura, con il settembre 2011 aggiornamento di Microsoft hanno aggiornato la tabella API Azure per includere due upsert comandi, inserire o sostituire entità e Inserisci o Unisci entità

Altri suggerimenti

Al fine di operare su un oggetto esistente non gestiti dalla TableContext con eliminare o SaveChanges con opzioni ReplaceOnUpdate, è necessario chiamare AttachTo e allegare l'oggetto alla TableContext, invece di chiamare AddObject che istruisce TableContext per tentare di inserirla .

http: // MSDN. microsoft.com/en-us/library/system.data.services.client.dataservicecontext.attachto.aspx

nel mio caso non è stato permesso di rimuoverlo prima, quindi lo faccio in questo modo, questo si tradurrà in una transazione al server che prima rimuovere l'oggetto esistente e che aggiungere nuova, eliminando necessità di copiare i valori delle proprietà

       var existing = from e in _ServiceContext.AgentTable
                       where e.PartitionKey == item.PartitionKey
                             && e.RowKey == item.RowKey
                       select e;

        _ServiceContext.IgnoreResourceNotFoundException = true;
        var existingObject = existing.FirstOrDefault();

        if (existingObject != null)
        {
            _ServiceContext.DeleteObject(existingObject);
        }

        _ServiceContext.AddObject(AgentConfigTableServiceContext.AgetnConfigTableName, item);

        _ServiceContext.SaveChangesWithRetries();
        _ServiceContext.IgnoreResourceNotFoundException = false;

Inserisci / Merge o aggiornamento è stata aggiunta alle API nel settembre 2011. Ecco un esempio utilizzando lo Storage API 2.0 che è più facile da capire, allora il modo in cui viene fatto nella 1.7 api e precedenti.

public void InsertOrReplace(ITableEntity entity)
    {
        retryPolicy.ExecuteAction(
            () =>
            {
                try
                {
                    TableOperation operation = TableOperation.InsertOrReplace(entity);
                    cloudTable.Execute(operation);
                }
                catch (StorageException e)
                {
                    string message = "InsertOrReplace entity failed.";

                    if (e.RequestInformation.HttpStatusCode == 404)
                    {
                        message += " Make sure the table is created.";
                    }

                    // do something with message
                }
            });
    }

L'API di archiviazione non permette più di un'operazione per entità (delete + insert) in una transazione di gruppo:

Un'entità può apparire solo una volta nella transazione, e una sola operazione può essere eseguita contro di essa.

MSDN: realizzazione delle operazioni di entità del gruppo

Quindi, in realtà è necessario leggere prima e decidere di inserimento o aggiornamento.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top