C# 是否通过记录对象的新实例更新TableServiceContext中的记录?
我已将azure表记录对象定义为C# 是否通过记录对象的新实例更新TableServiceContext中的记录?,c#,azure,wcf-data-services,azure-table-storage,tableservicescontext,C#,Azure,Wcf Data Services,Azure Table Storage,Tableservicescontext,我已将azure表记录对象定义为 [DataServiceKey("PartitionKey", "RowKey")] public class TableRecord { public string PartitionKey { get; set; } public string RowKey { get; set; } public DateTime Timestamp { get; set; } public string Data { get; set;
[DataServiceKey("PartitionKey", "RowKey")]
public class TableRecord
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public DateTime Timestamp { get; set; }
public string Data { get; set; }
}
记录用作存储库基础结构的一部分,存储库基础结构接受业务逻辑级别的数据对象,并在将代码保存到表存储之前将其序列化到数据属性中,以及在返回到客户端之前对其进行反序列化,因此,业务逻辑不知道有关记录以及PartitionKey和RowKey的任何信息
下面是存储库方法
public TEntity RegisterSave<TEntity>(TEntity entity, bool createNew)
{
var storeRec = _strategy.GetStoreRecord(entity);
if (createNew)
_context.AddObject(storeRec.TableName, storeRec.Record);
else
{
try
{
_context.AttachTo(storeRec.TableName, storeRec.Record, "*");
}
catch (InvalidOperationException)
{
// AttachTo can throw an exception if the entity is already being tracked.
// Ignore
}
_context.UpdateObject(storeRec.Record);
}
return entity;
}
看看SDK v1.6中引入的Upsert功能 解决方案是,如果存在现有实体,则需要将其()分离,并将附件()分离到新实体。然后做你想做的更新 我写了一些代码来实现这一点。它还避免了抛出异常,尽管我不确定哪种方法更快
/// <summary>
/// Detach any existing rows with the same keys (if necessary), then attach to this object using the "*" ETag
/// </summary>
/// <param name="newEntity"></param>
protected virtual void SafeAttach(TableServiceEntity newEntity)
{
TableServiceEntity entity = GetExistingRow(newEntity.PartitionKey, newEntity.RowKey);
if(entity != null)
{
base.Detach(entity);
}
base.AttachTo("MY_TABLE_NAME_GOES_HERE", newEntity, "*");
}
private TableServiceEntity GetExistingRow(string partitionKey, string rowKey)
{
var query = (from e in base.Entities
where e.Entity is TableServiceEntity
&& ((TableServiceEntity)e.Entity).RowKey == rowKey
&& ((TableServiceEntity)e.Entity).PartitionKey == partitionKey
select (TableServiceEntity)e.Entity);
RetrierFunctionResult<TableServiceEntity> r = StorageOperationRetrier.Execute(() =>
{
return query.FirstOrDefault();
});
return r.Result;
}
//
///使用相同的键拆离任何现有行(如有必要),然后使用“*”ETag附加到此对象
///
///
受保护的虚拟void SafeAttach(表服务实体newEntity)
{
TableServiceEntity实体=GetExistingRow(newEntity.PartitionKey,newEntity.RowKey);
如果(实体!=null)
{
基础。分离(实体);
}
base.AttachTo(“我的表名在这里”,newEntity,“*”);
}
私有表服务实体GetExistingRow(string partitionKey,string rowKey)
{
var query=(来自base.Entities中的e)
其中e.Entity是表服务实体
&&((TableServiceEntity)e.Entity).RowKey==RowKey
&&((TableServiceEntity)e.Entity).PartitionKey==PartitionKey
选择(表服务实体)e.Entity);
RetrierFunctionResult=StorageOperationRetrier.Execute(()=>
{
返回query.FirstOrDefault();
});
返回r.Result;
}
要使用它,您需要调用SafeAttach(storeRec)
来替换try/catch块
请注意,这种方法会破坏表存储的内置并发检查。你基本上得到了最后一次写赢的行为。这可能是可以接受的,也可能是不可以接受的,这取决于你的情况
此外,如果这是您计划继续工作的方式,您可能需要设置。不管怎样,您基本上是在模拟这种行为,禁用实体跟踪有一些性能优势 谢谢你的链接。不幸的是,这没有帮助-我仍然得到相同的错误-它们甚至在发出任何请求之前就被抛出。我只使用MergeOption.NotTracking,更简单的方法在我的方法中,表有一个负载字段数据,并且序列化了对象的最新版本。所以最后一次写赢的行为是我真正想要的。但看起来我错过了NoTracking选项背后的想法——它最适合这种情况。
/// <summary>
/// Detach any existing rows with the same keys (if necessary), then attach to this object using the "*" ETag
/// </summary>
/// <param name="newEntity"></param>
protected virtual void SafeAttach(TableServiceEntity newEntity)
{
TableServiceEntity entity = GetExistingRow(newEntity.PartitionKey, newEntity.RowKey);
if(entity != null)
{
base.Detach(entity);
}
base.AttachTo("MY_TABLE_NAME_GOES_HERE", newEntity, "*");
}
private TableServiceEntity GetExistingRow(string partitionKey, string rowKey)
{
var query = (from e in base.Entities
where e.Entity is TableServiceEntity
&& ((TableServiceEntity)e.Entity).RowKey == rowKey
&& ((TableServiceEntity)e.Entity).PartitionKey == partitionKey
select (TableServiceEntity)e.Entity);
RetrierFunctionResult<TableServiceEntity> r = StorageOperationRetrier.Execute(() =>
{
return query.FirstOrDefault();
});
return r.Result;
}