Migrated database concerns from KeyValueService to new repository.
This commit is contained in:
14
src/Umbraco.Abstractions/Models/IKeyValue.cs
Normal file
14
src/Umbraco.Abstractions/Models/IKeyValue.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IKeyValue : IEntity
|
||||
{
|
||||
string Identifier { get; set; }
|
||||
|
||||
string Value { get; set; }
|
||||
|
||||
DateTime UpdateDate { get; set; }
|
||||
}
|
||||
}
|
||||
39
src/Umbraco.Abstractions/Models/KeyValue.cs
Normal file
39
src/Umbraco.Abstractions/Models/KeyValue.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements <see cref="IKeyValue"/>.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class KeyValue : EntityBase, IKeyValue
|
||||
{
|
||||
private string _identifier;
|
||||
private string _value;
|
||||
private DateTime _updateDate;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Identifier
|
||||
{
|
||||
get => _identifier;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _identifier, nameof(Identifier));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Value
|
||||
{
|
||||
get => _value;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _value, nameof(Value));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime UpdateDate
|
||||
{
|
||||
get => _updateDate;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _updateDate, nameof(UpdateDate));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Umbraco.Infrastructure.Persistence.Repositories
|
||||
{
|
||||
public interface IKeyValueRepository
|
||||
{
|
||||
void Initialize();
|
||||
|
||||
string GetValue(string key);
|
||||
|
||||
void SetValue(string key, string value);
|
||||
|
||||
bool TrySetValue(string key, string originalValue, string newValue);
|
||||
}
|
||||
}
|
||||
@@ -344,7 +344,7 @@ namespace Umbraco.Core.Migrations.Install
|
||||
var stateValueKey = upgrader.StateValueKey;
|
||||
var finalState = upgrader.Plan.FinalState;
|
||||
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.KeyValue, "key", false, new KeyValueDto { Key = stateValueKey, Value = finalState, Updated = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.KeyValue, "key", false, new KeyValueDto { Key = stateValueKey, Value = finalState, UpdateDate = DateTime.Now });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,6 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
|
||||
[Column("updated")]
|
||||
[Constraint(Default = SystemMethods.CurrentDateTime)]
|
||||
public DateTime Updated { get; set; }
|
||||
public DateTime UpdateDate { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Migrations;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Infrastructure.Persistence.Repositories;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
internal class KeyValueRepository : NPocoRepositoryBase<string, IKeyValue>, IKeyValueRepository
|
||||
{
|
||||
public KeyValueRepository(IScopeAccessor scopeAccessor, ILogger logger)
|
||||
: base(scopeAccessor, AppCaches.NoCache, logger)
|
||||
{ }
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
var context = new MigrationContext(Database, Logger);
|
||||
var initMigration = new InitialMigration(context);
|
||||
initMigration.Migrate();
|
||||
}
|
||||
|
||||
public string GetValue(string key)
|
||||
{
|
||||
return GetDtoByKey(key)?.Value;
|
||||
}
|
||||
|
||||
public void SetValue(string key, string value)
|
||||
{
|
||||
var dto = GetDtoByKey(key);
|
||||
if (dto == null)
|
||||
{
|
||||
dto = new KeyValueDto
|
||||
{
|
||||
Key = key,
|
||||
Value = value,
|
||||
UpdateDate = DateTime.Now
|
||||
};
|
||||
|
||||
Database.Insert(dto);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateDtoValue(dto, value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TrySetValue(string key, string originalValue, string newValue)
|
||||
{
|
||||
var dto = GetDtoByKey(key);
|
||||
|
||||
if (dto == null || dto.Value != originalValue)
|
||||
return false;
|
||||
|
||||
UpdateDtoValue(dto, newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateDtoValue(KeyValueDto dto, string value)
|
||||
{
|
||||
dto.Value = value;
|
||||
dto.UpdateDate = DateTime.Now;
|
||||
Database.Update(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value directly from the database, no scope, nothing.
|
||||
/// </summary>
|
||||
/// <remarks>Used by <see cref="Runtime.CoreRuntime"/> to determine the runtime state.</remarks>
|
||||
internal static string GetValue(IUmbracoDatabase database, string key)
|
||||
{
|
||||
if (database is null) return null;
|
||||
|
||||
var sql = database.SqlContext.Sql()
|
||||
.Select<KeyValueDto>()
|
||||
.From<KeyValueDto>()
|
||||
.Where<KeyValueDto>(x => x.Key == key);
|
||||
return database.FirstOrDefault<KeyValueDto>(sql)?.Value;
|
||||
}
|
||||
|
||||
#region Overrides of NPocoRepositoryBase<string, IKeyValue>
|
||||
|
||||
protected override Guid NodeObjectTypeId => throw new NotImplementedException();
|
||||
|
||||
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
|
||||
{
|
||||
var sql = SqlContext.Sql();
|
||||
|
||||
sql = isCount
|
||||
? sql.SelectCount()
|
||||
: sql.Select<KeyValueDto>();
|
||||
|
||||
sql
|
||||
.From<KeyValueDto>();
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
{
|
||||
return Constants.DatabaseSchema.Tables.KeyValue + ".key = @id";
|
||||
}
|
||||
|
||||
protected override IEnumerable<string> GetDeleteClauses()
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
protected override IKeyValue PerformGet(string id)
|
||||
{
|
||||
var dto = GetDtoByKey(id);
|
||||
return dto == null ? null : Map(dto);
|
||||
}
|
||||
|
||||
private KeyValueDto GetDtoByKey(string key)
|
||||
{
|
||||
var sql = GetBaseQuery(false).Where<KeyValueDto>(x => x.Key == key);
|
||||
return Database.Fetch<KeyValueDto>(sql).FirstOrDefault();
|
||||
}
|
||||
|
||||
protected override IEnumerable<IKeyValue> PerformGetAll(params string[] ids)
|
||||
{
|
||||
var sql = GetBaseQuery(false).WhereIn<KeyValueDto>(x => x.Key, ids);
|
||||
var dtos = Database.Fetch<KeyValueDto>(sql);
|
||||
return dtos.WhereNotNull().Select(Map);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IKeyValue> PerformGetByQuery(IQuery<IKeyValue> query)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void PersistNewItem(IKeyValue entity)
|
||||
{
|
||||
var dto = Map(entity);
|
||||
Database.Insert(dto);
|
||||
}
|
||||
|
||||
protected override void PersistUpdatedItem(IKeyValue entity)
|
||||
{
|
||||
var dto = Map(entity);
|
||||
Database.Update(dto);
|
||||
}
|
||||
|
||||
private static KeyValueDto Map(IKeyValue keyValue)
|
||||
{
|
||||
if (keyValue == null) return null;
|
||||
|
||||
return new KeyValueDto
|
||||
{
|
||||
Key = keyValue.Identifier,
|
||||
Value = keyValue.Value,
|
||||
UpdateDate = keyValue.UpdateDate,
|
||||
};
|
||||
}
|
||||
|
||||
private static IKeyValue Map(KeyValueDto dto)
|
||||
{
|
||||
if (dto == null) return null;
|
||||
|
||||
return new KeyValue
|
||||
{
|
||||
Identifier = dto.Key,
|
||||
Value = dto.Value,
|
||||
UpdateDate = dto.UpdateDate,
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A custom migration that executes standalone during the Initialize phase of the KeyValueService.
|
||||
/// </summary>
|
||||
internal class InitialMigration : MigrationBase
|
||||
{
|
||||
public InitialMigration(IMigrationContext context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
// as long as we are still running 7 this migration will be invoked,
|
||||
// but due to multiple restarts during upgrades, maybe the table
|
||||
// exists already
|
||||
if (TableExists(Constants.DatabaseSchema.Tables.KeyValue))
|
||||
return;
|
||||
|
||||
Logger.Info<KeyValueRepository>("Creating KeyValue structure.");
|
||||
|
||||
// the locks table was initially created with an identity (auto-increment) primary key,
|
||||
// but we don't want this, especially as we are about to insert a new row into the table,
|
||||
// so here we drop that identity
|
||||
DropLockTableIdentity();
|
||||
|
||||
// insert the lock object for key/value
|
||||
Insert.IntoTable(Constants.DatabaseSchema.Tables.Lock).Row(new { id = Constants.Locks.KeyValues, name = "KeyValues", value = 1 }).Do();
|
||||
|
||||
// create the key-value table
|
||||
Create.Table<KeyValueDto>().Do();
|
||||
}
|
||||
|
||||
private void DropLockTableIdentity()
|
||||
{
|
||||
// one cannot simply drop an identity, that requires a bit of work
|
||||
|
||||
// create a temp. id column and copy values
|
||||
Alter.Table(Constants.DatabaseSchema.Tables.Lock).AddColumn("nid").AsInt32().Nullable().Do();
|
||||
Execute.Sql("update umbracoLock set nid = id").Do();
|
||||
|
||||
// drop the id column entirely (cannot just drop identity)
|
||||
Delete.PrimaryKey("PK_umbracoLock").FromTable(Constants.DatabaseSchema.Tables.Lock).Do();
|
||||
Delete.Column("id").FromTable(Constants.DatabaseSchema.Tables.Lock).Do();
|
||||
|
||||
// recreate the id column without identity and copy values
|
||||
Alter.Table(Constants.DatabaseSchema.Tables.Lock).AddColumn("id").AsInt32().Nullable().Do();
|
||||
Execute.Sql("update umbracoLock set id = nid").Do();
|
||||
|
||||
// drop the temp. id column
|
||||
Delete.Column("nid").FromTable(Constants.DatabaseSchema.Tables.Lock).Do();
|
||||
|
||||
// complete the primary key
|
||||
Alter.Table(Constants.DatabaseSchema.Tables.Lock).AlterColumn("id").AsInt32().NotNullable().PrimaryKey("PK_umbracoLock").Do();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -324,7 +324,7 @@ namespace Umbraco.Core.Runtime
|
||||
{
|
||||
Key = MainDomKey,
|
||||
Value = id,
|
||||
Updated = DateTime.Now
|
||||
UpdateDate = DateTime.Now
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Migrations.Upgrade;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.Sync;
|
||||
|
||||
namespace Umbraco.Core
|
||||
@@ -263,7 +263,7 @@ namespace Umbraco.Core
|
||||
// no scope, no service - just directly accessing the database
|
||||
using (var database = databaseFactory.CreateDatabase())
|
||||
{
|
||||
CurrentMigrationState = KeyValueService.GetValue(database, stateValueKey);
|
||||
CurrentMigrationState = KeyValueRepository.GetValue(database, stateValueKey);
|
||||
FinalMigrationState = upgrader.Plan.FinalState;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Migrations;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Infrastructure.Persistence.Repositories;
|
||||
|
||||
namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
@@ -14,13 +10,15 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
private readonly object _initialock = new object();
|
||||
private readonly IScopeProvider _scopeProvider;
|
||||
private readonly IKeyValueRepository _repository;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IUmbracoVersion _umbracoVersion;
|
||||
private bool _initialized;
|
||||
|
||||
public KeyValueService(IScopeProvider scopeProvider, ILogger logger, IUmbracoVersion umbracoVersion)
|
||||
public KeyValueService(IScopeProvider scopeProvider, IKeyValueRepository repository, ILogger logger, IUmbracoVersion umbracoVersion)
|
||||
{
|
||||
_scopeProvider = scopeProvider;
|
||||
_repository = repository;
|
||||
_logger = logger;
|
||||
_umbracoVersion = umbracoVersion;
|
||||
}
|
||||
@@ -53,71 +51,14 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
using (var scope = _scopeProvider.CreateScope())
|
||||
{
|
||||
var context = new MigrationContext(scope.Database, _logger);
|
||||
var initMigration = new InitializeMigration(context);
|
||||
initMigration.Migrate();
|
||||
_repository.Initialize();
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
// but don't assume we are initializing
|
||||
// we are upgrading from v7 and if anything goes wrong,
|
||||
// the table and everything will be rolled back
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A custom migration that executes standalone during the Initialize phase of this service.
|
||||
/// </summary>
|
||||
internal class InitializeMigration : MigrationBase
|
||||
{
|
||||
public InitializeMigration(IMigrationContext context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
// as long as we are still running 7 this migration will be invoked,
|
||||
// but due to multiple restarts during upgrades, maybe the table
|
||||
// exists already
|
||||
if (TableExists(Constants.DatabaseSchema.Tables.KeyValue))
|
||||
return;
|
||||
|
||||
Logger.Info<KeyValueService>("Creating KeyValue structure.");
|
||||
|
||||
// the locks table was initially created with an identity (auto-increment) primary key,
|
||||
// but we don't want this, especially as we are about to insert a new row into the table,
|
||||
// so here we drop that identity
|
||||
DropLockTableIdentity();
|
||||
|
||||
// insert the lock object for key/value
|
||||
Insert.IntoTable(Constants.DatabaseSchema.Tables.Lock).Row(new {id = Constants.Locks.KeyValues, name = "KeyValues", value = 1}).Do();
|
||||
|
||||
// create the key-value table
|
||||
Create.Table<KeyValueDto>().Do();
|
||||
}
|
||||
|
||||
private void DropLockTableIdentity()
|
||||
{
|
||||
// one cannot simply drop an identity, that requires a bit of work
|
||||
|
||||
// create a temp. id column and copy values
|
||||
Alter.Table(Constants.DatabaseSchema.Tables.Lock).AddColumn("nid").AsInt32().Nullable().Do();
|
||||
Execute.Sql("update umbracoLock set nid = id").Do();
|
||||
|
||||
// drop the id column entirely (cannot just drop identity)
|
||||
Delete.PrimaryKey("PK_umbracoLock").FromTable(Constants.DatabaseSchema.Tables.Lock).Do();
|
||||
Delete.Column("id").FromTable(Constants.DatabaseSchema.Tables.Lock).Do();
|
||||
|
||||
// recreate the id column without identity and copy values
|
||||
Alter.Table(Constants.DatabaseSchema.Tables.Lock).AddColumn("id").AsInt32().Nullable().Do();
|
||||
Execute.Sql("update umbracoLock set id = nid").Do();
|
||||
|
||||
// drop the temp. id column
|
||||
Delete.Column("nid").FromTable(Constants.DatabaseSchema.Tables.Lock).Do();
|
||||
|
||||
// complete the primary key
|
||||
Alter.Table(Constants.DatabaseSchema.Tables.Lock).AlterColumn("id").AsInt32().NotNullable().PrimaryKey("PK_umbracoLock").Do();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetValue(string key)
|
||||
@@ -126,10 +67,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
using (var scope = _scopeProvider.CreateScope())
|
||||
{
|
||||
var sql = scope.SqlContext.Sql().Select<KeyValueDto>().From<KeyValueDto>().Where<KeyValueDto>(x => x.Key == key);
|
||||
var dto = scope.Database.Fetch<KeyValueDto>(sql).FirstOrDefault();
|
||||
scope.Complete();
|
||||
return dto?.Value;
|
||||
return _repository.GetValue(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,26 +80,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
scope.WriteLock(Constants.Locks.KeyValues);
|
||||
|
||||
var sql = scope.SqlContext.Sql().Select<KeyValueDto>().From<KeyValueDto>().Where<KeyValueDto>(x => x.Key == key);
|
||||
var dto = scope.Database.Fetch<KeyValueDto>(sql).FirstOrDefault();
|
||||
|
||||
if (dto == null)
|
||||
{
|
||||
dto = new KeyValueDto
|
||||
{
|
||||
Key = key,
|
||||
Value = value,
|
||||
Updated = DateTime.Now
|
||||
};
|
||||
|
||||
scope.Database.Insert(dto);
|
||||
}
|
||||
else
|
||||
{
|
||||
dto.Value = value;
|
||||
dto.Updated = DateTime.Now;
|
||||
scope.Database.Update(dto);
|
||||
}
|
||||
_repository.SetValue(key, value);
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
@@ -175,7 +94,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TrySetValue(string key, string originValue, string newValue)
|
||||
public bool TrySetValue(string key, string originalValue, string newValue)
|
||||
{
|
||||
EnsureInitialized();
|
||||
|
||||
@@ -183,35 +102,15 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
scope.WriteLock(Constants.Locks.KeyValues);
|
||||
|
||||
var sql = scope.SqlContext.Sql().Select<KeyValueDto>().From<KeyValueDto>().Where<KeyValueDto>(x => x.Key == key);
|
||||
var dto = scope.Database.Fetch<KeyValueDto>(sql).FirstOrDefault();
|
||||
|
||||
if (dto == null || dto.Value != originValue)
|
||||
if (!_repository.TrySetValue(key, originalValue, newValue))
|
||||
{
|
||||
return false;
|
||||
|
||||
dto.Value = newValue;
|
||||
dto.Updated = DateTime.Now;
|
||||
scope.Database.Update(dto);
|
||||
}
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value directly from the database, no scope, nothing.
|
||||
/// </summary>
|
||||
/// <remarks>Used by <see cref="Runtime.CoreRuntime"/> to determine the runtime state.</remarks>
|
||||
internal static string GetValue(IUmbracoDatabase database, string key)
|
||||
{
|
||||
if (database is null) return null;
|
||||
|
||||
var sql = database.SqlContext.Sql()
|
||||
.Select<KeyValueDto>()
|
||||
.From<KeyValueDto>()
|
||||
.Where<KeyValueDto>(x => x.Key == key);
|
||||
return database.FirstOrDefault<KeyValueDto>(sql)?.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user