Merge pull request #7669 from AndyButland/netcore/7668-remove-repository-concerns-from-services
.NetCore: Remove direct database queries from services
This commit is contained in:
12
src/Umbraco.Core/Models/IKeyValue.cs
Normal file
12
src/Umbraco.Core/Models/IKeyValue.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IKeyValue : IEntity
|
||||
{
|
||||
string Identifier { get; set; }
|
||||
|
||||
string Value { get; set; }
|
||||
}
|
||||
}
|
||||
33
src/Umbraco.Core/Models/KeyValue.cs
Normal file
33
src/Umbraco.Core/Models/KeyValue.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
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, IEntity
|
||||
{
|
||||
private string _identifier;
|
||||
private string _value;
|
||||
|
||||
/// <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));
|
||||
}
|
||||
|
||||
bool IEntity.HasIdentity => !string.IsNullOrEmpty(Identifier);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IKeyValueRepository : IReadRepository<string, IKeyValue>, IWriteRepository<IKeyValue>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,24 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("This method will be removed in future versions. Please use ExistsByUserName instead.")]
|
||||
bool Exists(string username);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a user with the username exists
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <returns></returns>
|
||||
bool ExistsByUserName(string username);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a user with the login exists
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <returns></returns>
|
||||
bool ExistsByLogin(string login);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="IUser"/> objects associated with a given group
|
||||
/// </summary>
|
||||
|
||||
@@ -32,12 +32,13 @@ namespace Umbraco.Core.Services
|
||||
private readonly Lazy<IExternalLoginService> _externalLoginService;
|
||||
private readonly Lazy<IRedirectUrlService> _redirectUrlService;
|
||||
private readonly Lazy<IConsentService> _consentService;
|
||||
private readonly Lazy<IKeyValueService> _keyValueService;
|
||||
private readonly Lazy<IContentTypeBaseServiceProvider> _contentTypeBaseServiceProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ServiceContext"/> class with lazy services.
|
||||
/// </summary>
|
||||
public ServiceContext(Lazy<IPublicAccessService> publicAccessService, Lazy<IDomainService> domainService, Lazy<IAuditService> auditService, Lazy<ILocalizedTextService> localizedTextService, Lazy<ITagService> tagService, Lazy<IContentService> contentService, Lazy<IUserService> userService, Lazy<IMemberService> memberService, Lazy<IMediaService> mediaService, Lazy<IContentTypeService> contentTypeService, Lazy<IMediaTypeService> mediaTypeService, Lazy<IDataTypeService> dataTypeService, Lazy<IFileService> fileService, Lazy<ILocalizationService> localizationService, Lazy<IPackagingService> packagingService, Lazy<IServerRegistrationService> serverRegistrationService, Lazy<IEntityService> entityService, Lazy<IRelationService> relationService, Lazy<IMacroService> macroService, Lazy<IMemberTypeService> memberTypeService, Lazy<IMemberGroupService> memberGroupService, Lazy<INotificationService> notificationService, Lazy<IExternalLoginService> externalLoginService, Lazy<IRedirectUrlService> redirectUrlService, Lazy<IConsentService> consentService, Lazy<IContentTypeBaseServiceProvider> contentTypeBaseServiceProvider)
|
||||
public ServiceContext(Lazy<IPublicAccessService> publicAccessService, Lazy<IDomainService> domainService, Lazy<IAuditService> auditService, Lazy<ILocalizedTextService> localizedTextService, Lazy<ITagService> tagService, Lazy<IContentService> contentService, Lazy<IUserService> userService, Lazy<IMemberService> memberService, Lazy<IMediaService> mediaService, Lazy<IContentTypeService> contentTypeService, Lazy<IMediaTypeService> mediaTypeService, Lazy<IDataTypeService> dataTypeService, Lazy<IFileService> fileService, Lazy<ILocalizationService> localizationService, Lazy<IPackagingService> packagingService, Lazy<IServerRegistrationService> serverRegistrationService, Lazy<IEntityService> entityService, Lazy<IRelationService> relationService, Lazy<IMacroService> macroService, Lazy<IMemberTypeService> memberTypeService, Lazy<IMemberGroupService> memberGroupService, Lazy<INotificationService> notificationService, Lazy<IExternalLoginService> externalLoginService, Lazy<IRedirectUrlService> redirectUrlService, Lazy<IConsentService> consentService, Lazy<IKeyValueService> keyValueService, Lazy<IContentTypeBaseServiceProvider> contentTypeBaseServiceProvider)
|
||||
{
|
||||
_publicAccessService = publicAccessService;
|
||||
_domainService = domainService;
|
||||
@@ -64,6 +65,7 @@ namespace Umbraco.Core.Services
|
||||
_externalLoginService = externalLoginService;
|
||||
_redirectUrlService = redirectUrlService;
|
||||
_consentService = consentService;
|
||||
_keyValueService = keyValueService;
|
||||
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
|
||||
}
|
||||
|
||||
@@ -99,6 +101,7 @@ namespace Umbraco.Core.Services
|
||||
IServerRegistrationService serverRegistrationService = null,
|
||||
IRedirectUrlService redirectUrlService = null,
|
||||
IConsentService consentService = null,
|
||||
IKeyValueService keyValueService = null,
|
||||
IContentTypeBaseServiceProvider contentTypeBaseServiceProvider = null)
|
||||
{
|
||||
Lazy<T> Lazy<T>(T service) => service == null ? null : new Lazy<T>(() => service);
|
||||
@@ -129,6 +132,7 @@ namespace Umbraco.Core.Services
|
||||
Lazy(externalLoginService),
|
||||
Lazy(redirectUrlService),
|
||||
Lazy(consentService),
|
||||
Lazy(keyValueService),
|
||||
Lazy(contentTypeBaseServiceProvider)
|
||||
);
|
||||
}
|
||||
@@ -258,6 +262,11 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public IConsentService ConsentService => _consentService.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the KeyValueService.
|
||||
/// </summary>
|
||||
public IKeyValueService KeyValueService => _keyValueService.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ContentTypeServiceBaseFactory.
|
||||
/// </summary>
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
composition.RegisterUnique<IScriptRepository, ScriptRepository>();
|
||||
composition.RegisterUnique<IStylesheetRepository, StylesheetRepository>();
|
||||
composition.RegisterUnique<IContentTypeCommonRepository, ContentTypeCommonRepository>();
|
||||
composition.RegisterUnique<IKeyValueRepository, KeyValueRepository>();
|
||||
composition.RegisterUnique<IInstallationRepository, InstallationRepository>();
|
||||
composition.RegisterUnique<IUpgradeCheckRepository, UpgradeCheckRepository>();
|
||||
|
||||
|
||||
@@ -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,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
internal class KeyValueRepository : NPocoRepositoryBase<string, IKeyValue>, IKeyValueRepository
|
||||
{
|
||||
public KeyValueRepository(IScopeAccessor scopeAccessor, ILogger logger)
|
||||
: base(scopeAccessor, AppCaches.NoCache, logger)
|
||||
{ }
|
||||
|
||||
#region Overrides of IReadWriteQueryRepository<string, IKeyValue>
|
||||
|
||||
public override void Save(IKeyValue entity)
|
||||
{
|
||||
if (Get(entity.Identifier) == null)
|
||||
PersistNewItem(entity);
|
||||
else
|
||||
PersistUpdatedItem(entity);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides of NPocoRepositoryBase<string, IKeyValue>
|
||||
|
||||
protected override Guid NodeObjectTypeId => throw new NotSupportedException();
|
||||
|
||||
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 Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
protected override IKeyValue PerformGet(string id)
|
||||
{
|
||||
var sql = GetBaseQuery(false).Where<KeyValueDto>(x => x.Key == id);
|
||||
var dto = Database.Fetch<KeyValueDto>(sql).FirstOrDefault();
|
||||
return dto == null ? null : Map(dto);
|
||||
}
|
||||
|
||||
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 NotSupportedException();
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -132,7 +132,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
/// </summary>
|
||||
/// <remarks>This method is backed by an <see cref="IAppPolicyCache"/> cache</remarks>
|
||||
/// <param name="entity"></param>
|
||||
public void Save(TEntity entity)
|
||||
public virtual void Save(TEntity entity)
|
||||
{
|
||||
if (entity.HasIdentity == false)
|
||||
CachePolicy.Create(entity, PersistNewItem);
|
||||
|
||||
@@ -636,6 +636,11 @@ ORDER BY colName";
|
||||
}
|
||||
|
||||
public bool Exists(string username)
|
||||
{
|
||||
return ExistsByUserName(username);
|
||||
}
|
||||
|
||||
public bool ExistsByUserName(string username)
|
||||
{
|
||||
var sql = SqlContext.Sql()
|
||||
.SelectCount()
|
||||
@@ -645,6 +650,16 @@ ORDER BY colName";
|
||||
return Database.ExecuteScalar<int>(sql) > 0;
|
||||
}
|
||||
|
||||
public bool ExistsByLogin(string login)
|
||||
{
|
||||
var sql = SqlContext.Sql()
|
||||
.SelectCount()
|
||||
.From<UserDto>()
|
||||
.Where<UserDto>(x => x.Login == login);
|
||||
|
||||
return Database.ExecuteScalar<int>(sql) > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="IUser"/> objects associated with a given group
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
@@ -10,5 +11,20 @@ namespace Umbraco.Core.Persistence
|
||||
if (asDatabase == null) throw new Exception("oops: database.");
|
||||
return asDatabase;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a key/value directly from the database, no scope, nothing.
|
||||
/// </summary>
|
||||
/// <remarks>Used by <see cref="Runtime.CoreRuntime"/> to determine the runtime state.</remarks>
|
||||
public static string GetFromKeyValueTable(this 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Composing.CompositionExtensions;
|
||||
@@ -7,9 +6,8 @@ using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.Grid;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Dashboards;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.Migrations;
|
||||
@@ -25,14 +23,14 @@ using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Web.Models.PublishedContent;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Migrations.PostMigrations;
|
||||
using Umbraco.Web.Install;
|
||||
using Umbraco.Web.Trees;
|
||||
using Umbraco.Web.Migrations.PostMigrations;
|
||||
using Umbraco.Web.Models.PublishedContent;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Services;
|
||||
using Umbraco.Web.Trees;
|
||||
using IntegerValidator = Umbraco.Core.PropertyEditors.Validators.IntegerValidator;
|
||||
|
||||
namespace Umbraco.Core.Runtime
|
||||
|
||||
@@ -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
|
||||
@@ -225,7 +225,7 @@ namespace Umbraco.Core
|
||||
// no scope, no service - just directly accessing the database
|
||||
using (var database = databaseFactory.CreateDatabase())
|
||||
{
|
||||
CurrentMigrationState = KeyValueService.GetValue(database, stateValueKey);
|
||||
CurrentMigrationState = database.GetFromKeyValueTable(stateValueKey);
|
||||
FinalMigrationState = upgrader.Plan.FinalState;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,168 +1,55 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Migrations;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
internal class KeyValueService : IKeyValueService
|
||||
{
|
||||
private readonly object _initialock = new object();
|
||||
private readonly IScopeProvider _scopeProvider;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IUmbracoVersion _umbracoVersion;
|
||||
private bool _initialized;
|
||||
private readonly IKeyValueRepository _repository;
|
||||
|
||||
public KeyValueService(IScopeProvider scopeProvider, ILogger logger, IUmbracoVersion umbracoVersion)
|
||||
public KeyValueService(IScopeProvider scopeProvider, IKeyValueRepository repository)
|
||||
{
|
||||
_scopeProvider = scopeProvider;
|
||||
_logger = logger;
|
||||
_umbracoVersion = umbracoVersion;
|
||||
}
|
||||
|
||||
private void EnsureInitialized()
|
||||
{
|
||||
lock (_initialock)
|
||||
{
|
||||
if (_initialized) return;
|
||||
Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
// the key/value service is entirely self-managed, because it is used by the
|
||||
// upgrader and anything we might change need to happen before everything else
|
||||
|
||||
// if already running 8, either following an upgrade or an install,
|
||||
// then everything should be ok (the table should exist, etc)
|
||||
|
||||
if (_umbracoVersion.LocalVersion != null && _umbracoVersion.LocalVersion.Major >= 8)
|
||||
{
|
||||
_initialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// else we are upgrading from 7, we can assume that the locks table
|
||||
// exists, but we need to create everything for key/value
|
||||
|
||||
using (var scope = _scopeProvider.CreateScope())
|
||||
{
|
||||
var context = new MigrationContext(scope.Database, _logger);
|
||||
var initMigration = new InitializeMigration(context);
|
||||
initMigration.Migrate();
|
||||
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();
|
||||
}
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetValue(string key)
|
||||
{
|
||||
EnsureInitialized();
|
||||
|
||||
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.Get(key)?.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetValue(string key, string value)
|
||||
{
|
||||
EnsureInitialized();
|
||||
|
||||
using (var scope = _scopeProvider.CreateScope())
|
||||
{
|
||||
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)
|
||||
var keyValue = _repository.Get(key);
|
||||
if (keyValue == null)
|
||||
{
|
||||
dto = new KeyValueDto
|
||||
keyValue = new KeyValue
|
||||
{
|
||||
Key = key,
|
||||
Identifier = key,
|
||||
Value = value,
|
||||
Updated = DateTime.Now
|
||||
UpdateDate = DateTime.Now,
|
||||
};
|
||||
|
||||
scope.Database.Insert(dto);
|
||||
}
|
||||
else
|
||||
{
|
||||
dto.Value = value;
|
||||
dto.Updated = DateTime.Now;
|
||||
scope.Database.Update(dto);
|
||||
keyValue.Value = value;
|
||||
keyValue.UpdateDate = DateTime.Now;
|
||||
}
|
||||
|
||||
_repository.Save(keyValue);
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
}
|
||||
@@ -175,43 +62,26 @@ 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();
|
||||
|
||||
using (var scope = _scopeProvider.CreateScope())
|
||||
{
|
||||
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)
|
||||
var keyValue = _repository.Get(key);
|
||||
if (keyValue == null || keyValue.Value != originalValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
dto.Value = newValue;
|
||||
dto.Updated = DateTime.Now;
|
||||
scope.Database.Update(dto);
|
||||
keyValue.Value = newValue;
|
||||
keyValue.UpdateDate = DateTime.Now;
|
||||
_repository.Save(keyValue);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,7 +756,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
throw new ArgumentOutOfRangeException(nameof(matchType)); // causes rollback // causes rollback
|
||||
}
|
||||
|
||||
// TODO: Since this is by property value, we need a GetByPropertyQuery on the repo!
|
||||
// TODO: Since this is by property value, we need a GetByPropertyQuery on the repo!
|
||||
return _memberRepository.Get(query);
|
||||
}
|
||||
@@ -1196,7 +1195,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
scope.WriteLock(Constants.Locks.MemberTree);
|
||||
|
||||
// TODO: What about content that has the contenttype as part of its composition?
|
||||
// TODO: What about content that has the contenttype as part of its composition?
|
||||
var query = Query<IMember>().Where(x => x.ContentTypeId == memberTypeId);
|
||||
|
||||
|
||||
@@ -124,7 +124,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
else
|
||||
{
|
||||
//If they are both the same already then there's nothing to update, exit
|
||||
//If they are both the same already then there's nothing to update, exit
|
||||
return OperationResult.Attempt.Succeed(evtMsgs, entry);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
_serverRegistrationRepository.Save(server);
|
||||
_serverRegistrationRepository.DeactiveStaleServers(staleTimeout); // triggers a cache reload
|
||||
|
||||
// reload - cheap, cached
|
||||
// reload - cheap, cached
|
||||
|
||||
// default role is single server, but if registrations contain more
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
return _userRepository.Exists(username);
|
||||
return _userRepository.ExistsByUserName(username);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,9 +109,9 @@ namespace Umbraco.Core.Services.Implement
|
||||
User user;
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var loginExists = scope.Database.ExecuteScalar<int>("SELECT COUNT(id) FROM umbracoUser WHERE userLogin = @Login", new { Login = username }) != 0;
|
||||
var loginExists = _userRepository.ExistsByLogin(username);
|
||||
if (loginExists)
|
||||
throw new ArgumentException("Login already exists"); // causes rollback // causes rollback
|
||||
throw new ArgumentException("Login already exists"); // causes rollback
|
||||
|
||||
user = new User(_globalSettings)
|
||||
{
|
||||
@@ -340,7 +340,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
_userRepository.Save(user);
|
||||
|
||||
//Now we have to check for backwards compat hacks
|
||||
//Now we have to check for backwards compat hacks
|
||||
var explicitUser = user as User;
|
||||
if (explicitUser != null && explicitUser.GroupsToSave.Count > 0)
|
||||
@@ -358,7 +357,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
scope.Events.Dispatch(SavedUser, this, saveEventArgs);
|
||||
}
|
||||
|
||||
//commit the whole lot in one go
|
||||
//commit the whole lot in one go
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.Testing;
|
||||
|
||||
namespace Umbraco.Tests.Persistence.Repositories
|
||||
{
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class KeyValueRepositoryTests : TestWithDatabaseBase
|
||||
{
|
||||
[Test]
|
||||
public void CanSetAndGet()
|
||||
{
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
|
||||
// Insert new key/value
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var keyValue = new KeyValue
|
||||
{
|
||||
Identifier = "foo",
|
||||
Value = "bar",
|
||||
UpdateDate = DateTime.Now,
|
||||
};
|
||||
var repo = CreateRepository(provider);
|
||||
repo.Save(keyValue);
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
// Retrieve key/value
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var repo = CreateRepository(provider);
|
||||
var keyValue = repo.Get("foo");
|
||||
scope.Complete();
|
||||
|
||||
Assert.AreEqual("bar", keyValue.Value);
|
||||
}
|
||||
|
||||
// Update value
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var repo = CreateRepository(provider);
|
||||
var keyValue = repo.Get("foo");
|
||||
keyValue.Value = "buzz";
|
||||
keyValue.UpdateDate = DateTime.Now;
|
||||
repo.Save(keyValue);
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
// Retrieve key/value again
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var repo = CreateRepository(provider);
|
||||
var keyValue = repo.Get("foo");
|
||||
scope.Complete();
|
||||
|
||||
Assert.AreEqual("buzz", keyValue.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private IKeyValueRepository CreateRepository(IScopeProvider provider)
|
||||
{
|
||||
return new KeyValueRepository((IScopeAccessor) provider, Logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
93
src/Umbraco.Tests/Services/KeyValueServiceTests.cs
Normal file
93
src/Umbraco.Tests/Services/KeyValueServiceTests.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Internal;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.Testing;
|
||||
|
||||
namespace Umbraco.Tests.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests covering methods in the KeyValueService class.
|
||||
/// This is more of an integration test as it involves multiple layers
|
||||
/// as well as configuration.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class KeyValueServiceTests : TestWithSomeContentBase
|
||||
{
|
||||
[Test]
|
||||
public void GetValue_ForMissingKey_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
var keyValueService = ServiceContext.KeyValueService;
|
||||
|
||||
// Act
|
||||
var value = keyValueService.GetValue("foo");
|
||||
|
||||
// Assert
|
||||
Assert.IsNull(value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_ForExistingKey_ReturnsValue()
|
||||
{
|
||||
// Arrange
|
||||
var keyValueService = ServiceContext.KeyValueService;
|
||||
keyValueService.SetValue("foo", "bar");
|
||||
|
||||
// Act
|
||||
var value = keyValueService.GetValue("foo");
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("bar", value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SetValue_ForExistingKey_SavesValue()
|
||||
{
|
||||
// Arrange
|
||||
var keyValueService = ServiceContext.KeyValueService;
|
||||
keyValueService.SetValue("foo", "bar");
|
||||
|
||||
// Act
|
||||
keyValueService.SetValue("foo", "buzz");
|
||||
var value = keyValueService.GetValue("foo");
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("buzz", value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TrySetValue_ForExistingKeyWithProvidedValue_ReturnsTrueAndSetsValue()
|
||||
{
|
||||
// Arrange
|
||||
var keyValueService = ServiceContext.KeyValueService;
|
||||
keyValueService.SetValue("foo", "bar");
|
||||
|
||||
// Act
|
||||
var result = keyValueService.TrySetValue("foo", "bar", "buzz");
|
||||
var value = keyValueService.GetValue("foo");
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(result);
|
||||
Assert.AreEqual("buzz", value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TrySetValue_ForExistingKeyWithoutProvidedValue_ReturnsFalseAndDoesNotSetValue()
|
||||
{
|
||||
// Arrange
|
||||
var keyValueService = ServiceContext.KeyValueService;
|
||||
keyValueService.SetValue("foo", "bar");
|
||||
|
||||
// Act
|
||||
var result = keyValueService.TrySetValue("foo", "bang", "buzz");
|
||||
var value = keyValueService.GetValue("foo");
|
||||
|
||||
// Assert
|
||||
Assert.IsFalse(result);
|
||||
Assert.AreEqual("bar", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,6 +193,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
var tagService = GetLazyService<ITagService>(factory, c => new TagService(scopeProvider, logger, eventMessagesFactory, GetRepo<ITagRepository>(c)));
|
||||
var redirectUrlService = GetLazyService<IRedirectUrlService>(factory, c => new RedirectUrlService(scopeProvider, logger, eventMessagesFactory, GetRepo<IRedirectUrlRepository>(c)));
|
||||
var consentService = GetLazyService<IConsentService>(factory, c => new ConsentService(scopeProvider, logger, eventMessagesFactory, GetRepo<IConsentRepository>(c)));
|
||||
var keyValueService = GetLazyService<IKeyValueService>(factory, c => new KeyValueService(scopeProvider, GetRepo<IKeyValueRepository>(c)));
|
||||
var contentTypeServiceBaseFactory = GetLazyService<IContentTypeBaseServiceProvider>(factory, c => new ContentTypeBaseServiceProvider(factory.GetInstance<IContentTypeService>(),factory.GetInstance<IMediaTypeService>(),factory.GetInstance<IMemberTypeService>()));
|
||||
|
||||
return new ServiceContext(
|
||||
@@ -221,6 +222,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
externalLoginService,
|
||||
redirectUrlService,
|
||||
consentService,
|
||||
keyValueService,
|
||||
contentTypeServiceBaseFactory);
|
||||
}
|
||||
|
||||
|
||||
@@ -148,6 +148,8 @@
|
||||
<Compile Include="Persistence\Mappers\MapperTestBase.cs" />
|
||||
<Compile Include="Persistence\Repositories\DocumentRepositoryTest.cs" />
|
||||
<Compile Include="Persistence\Repositories\EntityRepositoryTest.cs" />
|
||||
<Compile Include="Persistence\Repositories\KeyValueRepositoryTests.cs" />
|
||||
<Compile Include="Services\KeyValueServiceTests.cs" />
|
||||
<Compile Include="Persistence\Repositories\UserRepositoryTest.cs" />
|
||||
<Compile Include="UmbracoExamine\ExamineExtensions.cs" />
|
||||
<Compile Include="PropertyEditors\DataValueReferenceFactoryCollectionTests.cs" />
|
||||
|
||||
Reference in New Issue
Block a user