Browse Source

Content fix for MongoDB

pull/221/head
Sebastian Stehle 8 years ago
parent
commit
cdca6a65a0
  1. 4
      src/Squidex.Domain.Apps.Entities.MongoDb/Apps/MongoAppEntity.cs
  2. 31
      src/Squidex.Domain.Apps.Entities.MongoDb/Apps/MongoAppRepository_SnapshotStore.cs
  3. 5
      src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetEntity.cs
  4. 29
      src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs
  5. 4
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentEntity.cs
  6. 28
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs
  7. 16
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs
  8. 1
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Visitors/FindExtensions.cs
  9. 4
      src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEntity.cs
  10. 30
      src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleRepository_SnapshotStore.cs
  11. 4
      src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaEntity.cs
  12. 30
      src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaRepository_SnapshotStore.cs
  13. 16
      src/Squidex.Infrastructure.MongoDb/MongoDb/IVersionedEntity.cs
  14. 60
      src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs
  15. 29
      src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs
  16. 2
      src/Squidex.Infrastructure.MongoDb/States/MongoState.cs

4
src/Squidex.Domain.Apps.Entities.MongoDb/Apps/MongoAppEntity.cs

@ -14,7 +14,7 @@ using Squidex.Infrastructure.MongoDb;
namespace Squidex.Domain.Apps.Entities.MongoDb.Apps namespace Squidex.Domain.Apps.Entities.MongoDb.Apps
{ {
public sealed class MongoAppEntity public sealed class MongoAppEntity : IVersionedEntity<Guid>
{ {
[BsonId] [BsonId]
[BsonElement] [BsonElement]
@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Apps
[BsonElement] [BsonElement]
[BsonRequired] [BsonRequired]
public int Version { get; set; } public long Version { get; set; }
[BsonElement] [BsonElement]
[BsonRequired] [BsonRequired]

31
src/Squidex.Domain.Apps.Entities.MongoDb/Apps/MongoAppRepository_SnapshotStore.cs

@ -12,6 +12,7 @@ using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
using Squidex.Domain.Apps.Entities.Apps.State; using Squidex.Domain.Apps.Entities.Apps.State;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.MongoDb;
using Squidex.Infrastructure.States; using Squidex.Infrastructure.States;
namespace Squidex.Domain.Apps.Entities.MongoDb.Apps namespace Squidex.Domain.Apps.Entities.MongoDb.Apps
@ -32,36 +33,12 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Apps
return (null, EtagVersion.NotFound); return (null, EtagVersion.NotFound);
} }
public async Task WriteAsync(Guid key, AppState value, long oldVersion, long newVersion) public Task WriteAsync(Guid key, AppState value, long oldVersion, long newVersion)
{ {
try return Collection.UpsertVersionedAsync(key, oldVersion, newVersion, u => u
{
await Collection.UpdateOneAsync(x => x.Id == key && x.Version == oldVersion,
Update
.Set(x => x.UserIds, value.Contributors.Keys.ToArray())
.Set(x => x.Name, value.Name) .Set(x => x.Name, value.Name)
.Set(x => x.State, value) .Set(x => x.State, value)
.Set(x => x.Version, newVersion), .Set(x => x.UserIds, value.Contributors.Keys.ToArray()));
Upsert);
}
catch (MongoWriteException ex)
{
if (ex.WriteError.Category == ServerErrorCategory.DuplicateKey)
{
var existingVersion =
await Collection.Find(x => x.Id == key)
.Project<MongoAppEntity>(Projection.Exclude(x => x.Id)).FirstOrDefaultAsync();
if (existingVersion != null)
{
throw new InconsistentStateException(existingVersion.Version, oldVersion, ex);
}
}
else
{
throw;
}
}
} }
} }
} }

5
src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetEntity.cs

@ -10,10 +10,11 @@ using System;
using MongoDB.Bson; using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using Squidex.Domain.Apps.Entities.Assets.State; using Squidex.Domain.Apps.Entities.Assets.State;
using Squidex.Infrastructure.MongoDb;
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{ {
public sealed class MongoAssetEntity public sealed class MongoAssetEntity : IVersionedEntity<Guid>
{ {
[BsonId] [BsonId]
[BsonElement] [BsonElement]
@ -26,6 +27,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
[BsonElement] [BsonElement]
[BsonRequired] [BsonRequired]
public int Version { get; set; } public long Version { get; set; }
} }
} }

29
src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs

@ -32,34 +32,9 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
return (null, EtagVersion.NotFound); return (null, EtagVersion.NotFound);
} }
public async Task WriteAsync(Guid key, AssetState value, long oldVersion, long newVersion) public Task WriteAsync(Guid key, AssetState value, long oldVersion, long newVersion)
{ {
try return Collection.UpsertVersionedAsync(key, oldVersion, newVersion, u => u.Set(x => x.State, value));
{
await Collection.UpdateOneAsync(x => x.Id == key && x.Version == oldVersion,
Update
.Set(x => x.State, value)
.Set(x => x.Version, newVersion),
Upsert);
}
catch (MongoWriteException ex)
{
if (ex.WriteError.Category == ServerErrorCategory.DuplicateKey)
{
var existingVersion =
await Collection.Find(x => x.Id == key).Only(x => x.Id, x => x.Version)
.FirstOrDefaultAsync();
if (existingVersion != null)
{
throw new InconsistentStateException(existingVersion["Version"].AsInt64, oldVersion, ex);
}
}
else
{
throw;
}
}
} }
} }
} }

4
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentEntity.cs

@ -87,10 +87,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
[BsonElement("mb")] [BsonElement("mb")]
public RefToken LastModifiedBy { get; set; } public RefToken LastModifiedBy { get; set; }
[BsonRequired]
[BsonElement("lt")]
public bool IsLatest { get; set; }
[BsonIgnore] [BsonIgnore]
public NamedContentData Data public NamedContentData Data
{ {

28
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs

@ -26,6 +26,12 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public partial class MongoContentRepository : MongoRepositoryBase<MongoContentEntity>, IContentRepository public partial class MongoContentRepository : MongoRepositoryBase<MongoContentEntity>, IContentRepository
{ {
private readonly IAppProvider appProvider; private readonly IAppProvider appProvider;
private readonly IMongoCollection<MongoContentEntity> archiveCollection;
protected IMongoCollection<MongoContentEntity> ArchiveCollection
{
get { return archiveCollection; }
}
public MongoContentRepository(IMongoDatabase database, IAppProvider appProvider) public MongoContentRepository(IMongoDatabase database, IAppProvider appProvider)
: base(database) : base(database)
@ -33,6 +39,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
Guard.NotNull(appProvider, nameof(appProvider)); Guard.NotNull(appProvider, nameof(appProvider));
this.appProvider = appProvider; this.appProvider = appProvider;
archiveCollection = database.GetCollection<MongoContentEntity>("States_Contents_Archive");
} }
protected override string CollectionName() protected override string CollectionName()
@ -42,25 +50,23 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
protected override async Task SetupCollectionAsync(IMongoCollection<MongoContentEntity> collection) protected override async Task SetupCollectionAsync(IMongoCollection<MongoContentEntity> collection)
{ {
await collection.Indexes.CreateOneAsync( await archiveCollection.Indexes.CreateOneAsync(
Index Index
.Ascending(x => x.Id) .Ascending(x => x.Id)
.Ascending(x => x.Version)); .Ascending(x => x.Version));
await collection.Indexes.CreateOneAsync( await collection.Indexes.CreateOneAsync(
Index Index
.Ascending(x => x.Id) .Ascending(x => x.SchemaId)
.Descending(x => x.Version)); .Ascending(x => x.Status)
.Text(x => x.DataText));
await collection.Indexes.CreateOneAsync( await collection.Indexes.CreateOneAsync(
Index Index
.Ascending(x => x.SchemaId) .Ascending(x => x.Id)
.Descending(x => x.IsLatest) .Ascending(x => x.Version));
.Descending(x => x.LastModified));
await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.ReferencedIds)); await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.ReferencedIds));
await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.Status));
await collection.Indexes.CreateOneAsync(Index.Text(x => x.DataText));
} }
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Status[] status, ODataUriParser odataQuery) public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Status[] status, ODataUriParser odataQuery)
@ -94,7 +100,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Status[] status, HashSet<Guid> ids) public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Status[] status, HashSet<Guid> ids)
{ {
var find = Collection.Find(x => ids.Contains(x.Id) && x.IsLatest); var find = Collection.Find(x => ids.Contains(x.Id));
var contentItems = find.ToListAsync(); var contentItems = find.ToListAsync();
var contentCount = find.CountAsync(); var contentCount = find.CountAsync();
@ -121,7 +127,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public async Task<IContentEntity> FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id, long version) public async Task<IContentEntity> FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id, long version)
{ {
var contentEntity = var contentEntity =
await Collection.Find(x => x.Id == id && x.Version >= version).SortBy(x => x.Version) await ArchiveCollection.Find(x => x.Id == id && x.Version >= version).SortBy(x => x.Version)
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();
contentEntity?.ParseData(schema.SchemaDef); contentEntity?.ParseData(schema.SchemaDef);
@ -132,7 +138,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public async Task<IContentEntity> FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id) public async Task<IContentEntity> FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id)
{ {
var contentEntity = var contentEntity =
await Collection.Find(x => x.Id == id && x.IsLatest) await Collection.Find(x => x.Id == id)
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();
contentEntity?.ParseData(schema.SchemaDef); contentEntity?.ParseData(schema.SchemaDef);

16
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs

@ -41,8 +41,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public async Task WriteAsync(Guid key, ContentState value, long oldVersion, long newVersion) public async Task WriteAsync(Guid key, ContentState value, long oldVersion, long newVersion)
{ {
var documentId = $"{key}_{newVersion}";
if (value.SchemaId == Guid.Empty) if (value.SchemaId == Guid.Empty)
{ {
return; return;
@ -52,12 +50,13 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
var idData = value.Data?.ToIdModel(schema.SchemaDef, true); var idData = value.Data?.ToIdModel(schema.SchemaDef, true);
var id = key.ToString();
var document = SimpleMapper.Map(value, new MongoContentEntity var document = SimpleMapper.Map(value, new MongoContentEntity
{ {
DocumentId = documentId, DocumentId = key.ToString(),
DataText = idData?.ToFullText(), DataText = idData?.ToFullText(),
DataByIds = idData, DataByIds = idData,
IsLatest = !value.IsDeleted,
ReferencedIds = idData?.ToReferencedIds(schema.SchemaDef), ReferencedIds = idData?.ToReferencedIds(schema.SchemaDef),
}); });
@ -65,15 +64,14 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
try try
{ {
await Collection.InsertOneAsync(document); await Collection.ReplaceOneAsync(x => x.DocumentId == id && x.Version == oldVersion, document, Upsert);
await Collection.UpdateManyAsync(x => x.Id == value.Id && x.Version < value.Version, Update.Set(x => x.IsLatest, false));
} }
catch (MongoWriteException ex) catch (MongoWriteException ex)
{ {
if (ex.WriteError.Category == ServerErrorCategory.DuplicateKey) if (ex.WriteError.Category == ServerErrorCategory.DuplicateKey)
{ {
var existingVersion = var existingVersion =
await Collection.Find(x => x.Id == value.Id && x.IsLatest).Only(x => x.Id, x => x.Version) await Collection.Find(x => x.DocumentId == id).Only(x => x.DocumentId, x => x.Version)
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();
if (existingVersion != null) if (existingVersion != null)
@ -86,6 +84,10 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
throw; throw;
} }
} }
document.DocumentId = $"{key}_{newVersion}";
await ArchiveCollection.ReplaceOneAsync(x => x.DocumentId == document.DocumentId, document, Upsert);
} }
private async Task<ISchemaEntity> GetSchemaAsync(Guid appId, Guid schemaId) private async Task<ISchemaEntity> GetSchemaAsync(Guid appId, Guid schemaId)

1
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Visitors/FindExtensions.cs

@ -68,7 +68,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Visitors
var filters = new List<FilterDefinition<MongoContentEntity>> var filters = new List<FilterDefinition<MongoContentEntity>>
{ {
Filter.Eq(x => x.SchemaId, schemaId), Filter.Eq(x => x.SchemaId, schemaId),
Filter.Eq(x => x.IsLatest, true),
Filter.In(x => x.Status, status) Filter.In(x => x.Status, status)
}; };

4
src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEntity.cs

@ -14,7 +14,7 @@ using Squidex.Infrastructure.MongoDb;
namespace Squidex.Domain.Apps.Entities.MongoDb.Rules namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
{ {
public sealed class MongoRuleEntity public sealed class MongoRuleEntity : IVersionedEntity<Guid>
{ {
[BsonId] [BsonId]
[BsonElement] [BsonElement]
@ -33,7 +33,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
[BsonElement] [BsonElement]
[BsonRequired] [BsonRequired]
public int Version { get; set; } public long Version { get; set; }
[BsonElement] [BsonElement]
[BsonRequired] [BsonRequired]

30
src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleRepository_SnapshotStore.cs

@ -32,36 +32,12 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
return (null, EtagVersion.NotFound); return (null, EtagVersion.NotFound);
} }
public async Task WriteAsync(Guid key, RuleState value, long oldVersion, long newVersion) public Task WriteAsync(Guid key, RuleState value, long oldVersion, long newVersion)
{ {
try return Collection.UpsertVersionedAsync(key, oldVersion, newVersion, u => u
{
await Collection.UpdateOneAsync(x => x.Id == key && x.Version == oldVersion,
Update
.Set(x => x.State, value) .Set(x => x.State, value)
.Set(x => x.AppId, value.AppId) .Set(x => x.AppId, value.AppId)
.Set(x => x.IsDeleted, value.IsDeleted) .Set(x => x.IsDeleted, value.IsDeleted));
.Set(x => x.Version, newVersion),
Upsert);
}
catch (MongoWriteException ex)
{
if (ex.WriteError.Category == ServerErrorCategory.DuplicateKey)
{
var existingVersion =
await Collection.Find(x => x.Id == key).Only(x => x.Id, x => x.Version)
.FirstOrDefaultAsync();
if (existingVersion != null)
{
throw new InconsistentStateException(existingVersion["Version"].AsInt64, oldVersion, ex);
}
}
else
{
throw;
}
}
} }
} }
} }

4
src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaEntity.cs

@ -14,7 +14,7 @@ using Squidex.Infrastructure.MongoDb;
namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas
{ {
public sealed class MongoSchemaEntity public sealed class MongoSchemaEntity : IVersionedEntity<Guid>
{ {
[BsonId] [BsonId]
[BsonElement] [BsonElement]
@ -37,7 +37,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas
[BsonElement] [BsonElement]
[BsonRequired] [BsonRequired]
public int Version { get; set; } public long Version { get; set; }
[BsonElement] [BsonElement]
[BsonRequired] [BsonRequired]

30
src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaRepository_SnapshotStore.cs

@ -32,37 +32,13 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas
return (null, EtagVersion.NotFound); return (null, EtagVersion.NotFound);
} }
public async Task WriteAsync(Guid key, SchemaState value, long oldVersion, long newVersion) public Task WriteAsync(Guid key, SchemaState value, long oldVersion, long newVersion)
{ {
try return Collection.UpsertVersionedAsync(key, oldVersion, newVersion, u => u
{
await Collection.UpdateOneAsync(x => x.Id == key && x.Version == oldVersion,
Update
.Set(x => x.State, value) .Set(x => x.State, value)
.Set(x => x.AppId, value.AppId) .Set(x => x.AppId, value.AppId)
.Set(x => x.Name, value.Name) .Set(x => x.Name, value.Name)
.Set(x => x.Version, newVersion) .Set(x => x.IsDeleted, value.IsDeleted));
.Set(x => x.IsDeleted, value.IsDeleted),
Upsert);
}
catch (MongoWriteException ex)
{
if (ex.WriteError.Category == ServerErrorCategory.DuplicateKey)
{
var existingVersion =
await Collection.Find(x => x.Id == key).Only(x => x.Version)
.FirstOrDefaultAsync();
if (existingVersion != null)
{
throw new InconsistentStateException(existingVersion["Version"].AsInt64, oldVersion, ex);
}
}
else
{
throw;
}
}
} }
} }
} }

16
src/Squidex.Infrastructure.MongoDb/MongoDb/IVersionedEntity.cs

@ -0,0 +1,16 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Infrastructure.MongoDb
{
public interface IVersionedEntity<T>
{
T Id { get; set; }
long Version { get; set; }
}
}

60
src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs

@ -11,11 +11,14 @@ using System.Linq.Expressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Bson; using MongoDB.Bson;
using MongoDB.Driver; using MongoDB.Driver;
using Squidex.Infrastructure.States;
namespace Squidex.Infrastructure.MongoDb namespace Squidex.Infrastructure.MongoDb
{ {
public static class MongoExtensions public static class MongoExtensions
{ {
private static readonly UpdateOptions Upsert = new UpdateOptions { IsUpsert = true };
public static async Task<bool> InsertOneIfNotExistsAsync<T>(this IMongoCollection<T> collection, T document) public static async Task<bool> InsertOneIfNotExistsAsync<T>(this IMongoCollection<T> collection, T document)
{ {
try try
@ -55,5 +58,62 @@ namespace Squidex.Infrastructure.MongoDb
{ {
return find.Project<BsonDocument>(Builders<TDocument>.Projection.Include(include1).Include(include2).Include(include3)); return find.Project<BsonDocument>(Builders<TDocument>.Projection.Include(include1).Include(include2).Include(include3));
} }
public static async Task UpsertVersionedAsync<T, TKey>(this IMongoCollection<T> collection, TKey key, long oldVersion, long newVersion, Func<UpdateDefinition<T>, UpdateDefinition<T>> updater) where T : IVersionedEntity<TKey>
{
try
{
var update = updater(Builders<T>.Update.Set(x => x.Version, newVersion));
await collection.UpdateOneAsync(x => x.Id.Equals(key) && x.Version == oldVersion,
update
.Set(x => x.Version, newVersion),
Upsert);
}
catch (MongoWriteException ex)
{
if (ex.WriteError.Category == ServerErrorCategory.DuplicateKey)
{
var existingVersion =
await collection.Find(x => x.Id.Equals(key)).Only(x => x.Id, x => x.Version)
.FirstOrDefaultAsync();
if (existingVersion != null)
{
throw new InconsistentStateException(existingVersion[nameof(IVersionedEntity<TKey>.Version)].AsInt64, oldVersion, ex);
}
}
else
{
throw;
}
}
}
public static async Task UpsertVersionedAsync<T, TKey>(this IMongoCollection<T> collection, TKey key, long oldVersion, long newVersion, T doc) where T : IVersionedEntity<TKey>
{
try
{
await collection.ReplaceOneAsync(x => x.Id.Equals(key) && x.Version == oldVersion, doc, Upsert);
}
catch (MongoWriteException ex)
{
if (ex.WriteError.Category == ServerErrorCategory.DuplicateKey)
{
var existingVersion =
await collection.Find(x => x.Id.Equals(key)).Only(x => x.Id, x => x.Version)
.FirstOrDefaultAsync();
if (existingVersion != null)
{
throw new InconsistentStateException(existingVersion[nameof(IVersionedEntity<TKey>.Version)].AsInt64, oldVersion, ex);
}
}
else
{
throw;
}
}
}
} }
} }

29
src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs

@ -44,34 +44,9 @@ namespace Squidex.Infrastructure.States
return (default(T), EtagVersion.NotFound); return (default(T), EtagVersion.NotFound);
} }
public async Task WriteAsync(TKey key, T value, long oldVersion, long newVersion) public Task WriteAsync(TKey key, T value, long oldVersion, long newVersion)
{ {
try return Collection.UpsertVersionedAsync(key, oldVersion, newVersion, u => u.Set(x => x.Doc, value));
{
await Collection.UpdateOneAsync(x => Equals(x.Id, key) && x.Version == oldVersion,
Update
.Set(x => x.Doc, value)
.Set(x => x.Version, newVersion),
Upsert);
}
catch (MongoWriteException ex)
{
if (ex.WriteError.Category == ServerErrorCategory.DuplicateKey)
{
var existingVersion =
await Collection.Find(x => Equals(x.Id, key)).Only(x => x.Id, x => x.Version)
.FirstOrDefaultAsync();
if (existingVersion != null)
{
throw new InconsistentStateException(existingVersion["Version"].AsInt64, oldVersion, ex);
}
}
else
{
throw;
}
}
} }
} }
} }

2
src/Squidex.Infrastructure.MongoDb/States/MongoState.cs

@ -12,7 +12,7 @@ using Squidex.Infrastructure.MongoDb;
namespace Squidex.Infrastructure.States namespace Squidex.Infrastructure.States
{ {
public sealed class MongoState<T, TKey> public sealed class MongoState<T, TKey> : IVersionedEntity<TKey>
{ {
[BsonId] [BsonId]
[BsonElement] [BsonElement]

Loading…
Cancel
Save