diff --git a/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs index 919320ec34..24b4637055 100644 --- a/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Core.Cache /// The repository PerformGetAll method. /// The entity with the specified identifier, if it exits, else null. /// First considers the cache then the repository. - TEntity? Get(TId id, Func performGet, Func> performGetAll); + TEntity? Get(TId? id, Func performGet, Func?> performGetAll); /// /// Gets an entity from the cache. @@ -33,7 +33,7 @@ namespace Umbraco.Cms.Core.Cache /// The repository PerformGetAll method. /// A value indicating whether an entity with the specified identifier exists. /// First considers the cache then the repository. - bool Exists(TId id, Func performExists, Func> performGetAll); + bool Exists(TId id, Func performExists, Func?> performGetAll); /// /// Creates an entity. @@ -66,7 +66,7 @@ namespace Umbraco.Cms.Core.Cache /// The repository PerformGetAll method. /// If is empty, all entities, else the entities with the specified identifiers. /// Get all the entities. Either from the cache or the repository depending on the implementation. - TEntity?[] GetAll(TId[] ids, Func> performGetAll); + TEntity[]? GetAll(TId[]? ids, Func?> performGetAll); /// /// Clears the entire cache. diff --git a/src/Umbraco.Core/Enum.cs b/src/Umbraco.Core/Enum.cs index 787d157254..9ca1111a30 100644 --- a/src/Umbraco.Core/Enum.cs +++ b/src/Umbraco.Core/Enum.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace Umbraco.Cms.Core diff --git a/src/Umbraco.Core/Extensions/StringExtensions.cs b/src/Umbraco.Core/Extensions/StringExtensions.cs index cd629288e6..a2be76e109 100644 --- a/src/Umbraco.Core/Extensions/StringExtensions.cs +++ b/src/Umbraco.Core/Extensions/StringExtensions.cs @@ -548,7 +548,7 @@ namespace Umbraco.Extensions /// The compare. /// The compare to. /// - public static bool InvariantEquals(this string compare, string? compareTo) + public static bool InvariantEquals(this string? compare, string? compareTo) { return String.Equals(compare, compareTo, StringComparison.InvariantCultureIgnoreCase); } diff --git a/src/Umbraco.Core/IO/IFileSystem.cs b/src/Umbraco.Core/IO/IFileSystem.cs index 232827300c..853b91f663 100644 --- a/src/Umbraco.Core/IO/IFileSystem.cs +++ b/src/Umbraco.Core/IO/IFileSystem.cs @@ -97,7 +97,7 @@ namespace Umbraco.Cms.Core.IO /// /// True if the file exists and the user has permission to view it; otherwise false. /// - bool FileExists(string path); + bool FileExists(string? path); /// /// Returns the application relative path to the file. diff --git a/src/Umbraco.Core/Mapping/IUmbracoMapper.cs b/src/Umbraco.Core/Mapping/IUmbracoMapper.cs index 5c3e980ac3..3b5b3f2ad3 100644 --- a/src/Umbraco.Core/Mapping/IUmbracoMapper.cs +++ b/src/Umbraco.Core/Mapping/IUmbracoMapper.cs @@ -131,7 +131,7 @@ namespace Umbraco.Cms.Core.Mapping /// The type of the target objects. /// The source objects. /// A list containing the target objects. - List MapEnumerable(IEnumerable source); + List MapEnumerable(IEnumerable source); /// /// Maps an enumerable of source objects to a new list of target objects. @@ -141,7 +141,7 @@ namespace Umbraco.Cms.Core.Mapping /// The source objects. /// A mapper context preparation method. /// A list containing the target objects. - List MapEnumerable(IEnumerable source, Action f); + List MapEnumerable(IEnumerable source, Action f); /// /// Maps an enumerable of source objects to a new list of target objects. @@ -151,6 +151,6 @@ namespace Umbraco.Cms.Core.Mapping /// The source objects. /// A mapper context. /// A list containing the target objects. - List MapEnumerable(IEnumerable source, MapperContext context); + List MapEnumerable(IEnumerable source, MapperContext context); } } diff --git a/src/Umbraco.Core/Models/ContentEditing/RollbackVersion.cs b/src/Umbraco.Core/Models/ContentEditing/RollbackVersion.cs index 762c806dc9..ca0e3ff9af 100644 --- a/src/Umbraco.Core/Models/ContentEditing/RollbackVersion.cs +++ b/src/Umbraco.Core/Models/ContentEditing/RollbackVersion.cs @@ -10,7 +10,7 @@ namespace Umbraco.Cms.Core.Models.ContentEditing public int VersionId { get; set; } [DataMember(Name = "versionDate")] - public DateTime VersionDate { get; set; } + public DateTime? VersionDate { get; set; } [DataMember(Name = "versionAuthorId")] public int VersionAuthorId { get; set; } diff --git a/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs b/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs index 8001da7db8..5fec2930b5 100644 --- a/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs +++ b/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs @@ -10,7 +10,7 @@ namespace Umbraco.Extensions /// public static class ContentRepositoryExtensions { - public static void SetCultureInfo(this IContentBase content, string culture, string? name, DateTime date) + public static void SetCultureInfo(this IContentBase content, string? culture, string? name, DateTime date) { if (name == null) throw new ArgumentNullException(nameof(name)); if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name)); @@ -203,7 +203,7 @@ namespace Umbraco.Extensions } } - public static void SetPublishInfo(this IContent content, string? culture, string name, DateTime date) + public static void SetPublishInfo(this IContent content, string? culture, string? name, DateTime date) { if (name == null) throw new ArgumentNullException(nameof(name)); if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name)); @@ -215,13 +215,13 @@ namespace Umbraco.Extensions } // sets the edited cultures on the content - public static void SetCultureEdited(this IContent content, IEnumerable cultures) + public static void SetCultureEdited(this IContent content, IEnumerable cultures) { if (cultures == null) content.EditedCultures = null; else { - var editedCultures = new HashSet(cultures.Where(x => !x.IsNullOrWhiteSpace()), StringComparer.OrdinalIgnoreCase); + var editedCultures = new HashSet(cultures.Where(x => !x.IsNullOrWhiteSpace())!, StringComparer.OrdinalIgnoreCase); content.EditedCultures = editedCultures.Count > 0 ? editedCultures : null; } } diff --git a/src/Umbraco.Core/Models/DictionaryItem.cs b/src/Umbraco.Core/Models/DictionaryItem.cs index 79f922ecb7..359d6de01c 100644 --- a/src/Umbraco.Core/Models/DictionaryItem.cs +++ b/src/Umbraco.Core/Models/DictionaryItem.cs @@ -17,7 +17,7 @@ namespace Umbraco.Cms.Core.Models public Func? GetLanguage { get; set; } private Guid? _parentId; private string _itemKey; - private IEnumerable? _translations; + private IEnumerable _translations; public DictionaryItem(string itemKey) : this(null, itemKey) @@ -60,7 +60,7 @@ namespace Umbraco.Cms.Core.Models /// Gets or sets a list of translations for the Dictionary Item /// [DataMember] - public IEnumerable? Translations + public IEnumerable Translations { get { return _translations; } set diff --git a/src/Umbraco.Core/Models/Entities/EntityBase.cs b/src/Umbraco.Core/Models/Entities/EntityBase.cs index 57b9eeae1f..9461fc1651 100644 --- a/src/Umbraco.Core/Models/Entities/EntityBase.cs +++ b/src/Umbraco.Core/Models/Entities/EntityBase.cs @@ -19,8 +19,8 @@ namespace Umbraco.Cms.Core.Models.Entities private bool _hasIdentity; private int _id; private Guid _key; - private DateTime _createDate; - private DateTime _updateDate; + private DateTime? _createDate; + private DateTime? _updateDate; /// [DataMember] @@ -50,7 +50,7 @@ namespace Umbraco.Cms.Core.Models.Entities /// [DataMember] - public DateTime CreateDate + public DateTime? CreateDate { get => _createDate; set => SetPropertyValueAndDetectChanges(value, ref _createDate, nameof(CreateDate)); @@ -58,7 +58,7 @@ namespace Umbraco.Cms.Core.Models.Entities /// [DataMember] - public DateTime UpdateDate + public DateTime? UpdateDate { get => _updateDate; set => SetPropertyValueAndDetectChanges(value, ref _updateDate, nameof(UpdateDate)); diff --git a/src/Umbraco.Core/Models/EntityContainer.cs b/src/Umbraco.Core/Models/EntityContainer.cs index 31a72356db..114d78605c 100644 --- a/src/Umbraco.Core/Models/EntityContainer.cs +++ b/src/Umbraco.Core/Models/EntityContainer.cs @@ -37,7 +37,7 @@ namespace Umbraco.Cms.Core.Models /// /// Initializes a new instance of an class. /// - public EntityContainer(int id, Guid uniqueId, int parentId, string path, int level, int sortOrder, Guid containedObjectType, string name, int userId) + public EntityContainer(int id, Guid uniqueId, int parentId, string path, int level, int sortOrder, Guid containedObjectType, string? name, int userId) : this(containedObjectType) { Id = id; diff --git a/src/Umbraco.Core/Models/File.cs b/src/Umbraco.Core/Models/File.cs index ec493ad937..3865d4eee7 100644 --- a/src/Umbraco.Core/Models/File.cs +++ b/src/Umbraco.Core/Models/File.cs @@ -19,9 +19,9 @@ namespace Umbraco.Cms.Core.Models // cannot simply use HasIdentity as some classes (eg Script) override it // in a weird way. private string? _content; - public Func? GetFileContent { get; set; } + public Func? GetFileContent { get; set; } - protected File(string path, Func? getFileContent = null) + protected File(string path, Func? getFileContent = null) { _path = SanitizePath(path); _originalPath = _path; diff --git a/src/Umbraco.Core/Models/IDictionaryItem.cs b/src/Umbraco.Core/Models/IDictionaryItem.cs index 5b0d868f83..f299ce2ac5 100644 --- a/src/Umbraco.Core/Models/IDictionaryItem.cs +++ b/src/Umbraco.Core/Models/IDictionaryItem.cs @@ -23,6 +23,6 @@ namespace Umbraco.Cms.Core.Models /// Gets or sets a list of translations for the Dictionary Item /// [DataMember] - IEnumerable? Translations { get; set; } + IEnumerable Translations { get; set; } } } diff --git a/src/Umbraco.Core/Models/IRedirectUrl.cs b/src/Umbraco.Core/Models/IRedirectUrl.cs index f2e4e131a7..18498837b4 100644 --- a/src/Umbraco.Core/Models/IRedirectUrl.cs +++ b/src/Umbraco.Core/Models/IRedirectUrl.cs @@ -38,7 +38,7 @@ namespace Umbraco.Cms.Core.Models /// /// Is a proper Umbraco route eg /path/to/foo or 123/path/tofoo. [DataMember] - string? Url { get; set; } + string Url { get; set; } } } diff --git a/src/Umbraco.Core/Models/ITag.cs b/src/Umbraco.Core/Models/ITag.cs index fdef14fec0..79840481bb 100644 --- a/src/Umbraco.Core/Models/ITag.cs +++ b/src/Umbraco.Core/Models/ITag.cs @@ -12,13 +12,13 @@ namespace Umbraco.Cms.Core.Models /// Gets or sets the tag group. /// [DataMember] - string? Group { get; set; } + string Group { get; set; } /// /// Gets or sets the tag text. /// [DataMember] - string? Text { get; set; } + string Text { get; set; } /// /// Gets or sets the tag language. diff --git a/src/Umbraco.Core/Models/ITwoFactorLogin.cs b/src/Umbraco.Core/Models/ITwoFactorLogin.cs index 92b798fe0d..ca005309b2 100644 --- a/src/Umbraco.Core/Models/ITwoFactorLogin.cs +++ b/src/Umbraco.Core/Models/ITwoFactorLogin.cs @@ -5,8 +5,8 @@ namespace Umbraco.Cms.Core.Models { public interface ITwoFactorLogin: IEntity, IRememberBeingDirty { - string? ProviderName { get; } - string? Secret { get; } + string ProviderName { get; } + string Secret { get; } Guid UserOrMemberKey { get; } } } diff --git a/src/Umbraco.Core/Models/LogViewerQuery.cs b/src/Umbraco.Core/Models/LogViewerQuery.cs index 05009733ae..e9c0dc3180 100644 --- a/src/Umbraco.Core/Models/LogViewerQuery.cs +++ b/src/Umbraco.Core/Models/LogViewerQuery.cs @@ -11,7 +11,7 @@ namespace Umbraco.Cms.Core.Models private string? _name; private string? _query; - public LogViewerQuery(string name, string query) + public LogViewerQuery(string? name, string? query) { Name = name; _query = query; diff --git a/src/Umbraco.Core/Models/Media.cs b/src/Umbraco.Core/Models/Media.cs index 60542d78cb..926fe2ef09 100644 --- a/src/Umbraco.Core/Models/Media.cs +++ b/src/Umbraco.Core/Models/Media.cs @@ -37,7 +37,7 @@ namespace Umbraco.Cms.Core.Models /// name of the Media object /// Id of the Parent IMedia /// MediaType for the current Media object - public Media(string? name, int parentId, IMediaType mediaType) + public Media(string? name, int parentId, IMediaType? mediaType) : this(name, parentId, mediaType, new PropertyCollection()) { } @@ -48,7 +48,7 @@ namespace Umbraco.Cms.Core.Models /// Id of the Parent IMedia /// MediaType for the current Media object /// Collection of properties - public Media(string? name, int parentId, IMediaType mediaType, IPropertyCollection properties) + public Media(string? name, int parentId, IMediaType? mediaType, IPropertyCollection properties) : base(name, parentId, mediaType, properties) { } diff --git a/src/Umbraco.Core/Models/Member.cs b/src/Umbraco.Core/Models/Member.cs index c4eca5d2d1..00d1fe93fe 100644 --- a/src/Umbraco.Core/Models/Member.cs +++ b/src/Umbraco.Core/Models/Member.cs @@ -131,7 +131,7 @@ namespace Umbraco.Cms.Core.Models /// The password value passed in to this parameter should be the encoded/encrypted/hashed format of the member's password /// /// - public Member(string? name, string email, string username, string rawPasswordValue, IMemberType contentType) + public Member(string? name, string email, string username, string? rawPasswordValue, IMemberType? contentType) : base(name, -1, contentType, new PropertyCollection()) { _email = email; @@ -362,7 +362,7 @@ namespace Umbraco.Cms.Core.Models /// Part of the standard properties collection. /// [DataMember] - public DateTime LastLoginDate + public DateTime? LastLoginDate { get { @@ -398,7 +398,7 @@ namespace Umbraco.Cms.Core.Models /// Part of the standard properties collection. /// [DataMember] - public DateTime LastPasswordChangeDate + public DateTime? LastPasswordChangeDate { get { diff --git a/src/Umbraco.Core/Models/Membership/IUser.cs b/src/Umbraco.Core/Models/Membership/IUser.cs index c7c68dabda..ca41d892e7 100644 --- a/src/Umbraco.Core/Models/Membership/IUser.cs +++ b/src/Umbraco.Core/Models/Membership/IUser.cs @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Core.Models.Membership { UserState UserState { get; } - string? Name { get; set; } + string Name { get; set; } int SessionTimeout { get; set; } int[]? StartContentIds { get; set; } int[]? StartMediaIds { get; set; } diff --git a/src/Umbraco.Core/Models/Notification.cs b/src/Umbraco.Core/Models/Notification.cs index b65064f266..95091efe1f 100644 --- a/src/Umbraco.Core/Models/Notification.cs +++ b/src/Umbraco.Core/Models/Notification.cs @@ -4,7 +4,7 @@ namespace Umbraco.Cms.Core.Models { public class Notification { - public Notification(int entityId, int userId, string action, Guid entityType) + public Notification(int entityId, int userId, string action, Guid? entityType) { EntityId = entityId; UserId = userId; @@ -15,6 +15,6 @@ namespace Umbraco.Cms.Core.Models public int EntityId { get; private set; } public int UserId { get; private set; } public string Action { get; private set; } - public Guid EntityType { get; private set; } + public Guid? EntityType { get; private set; } } } diff --git a/src/Umbraco.Core/Models/PartialView.cs b/src/Umbraco.Core/Models/PartialView.cs index d78a6603bb..ffa9412c51 100644 --- a/src/Umbraco.Core/Models/PartialView.cs +++ b/src/Umbraco.Core/Models/PartialView.cs @@ -14,7 +14,7 @@ namespace Umbraco.Cms.Core.Models : this(viewType, path, null) { } - public PartialView(PartialViewType viewType, string path, Func? getFileContent) + public PartialView(PartialViewType viewType, string path, Func? getFileContent) : base(path, getFileContent) { ViewType = viewType; diff --git a/src/Umbraco.Core/Models/Property.cs b/src/Umbraco.Core/Models/Property.cs index 1fd52add4b..6633aecb6d 100644 --- a/src/Umbraco.Core/Models/Property.cs +++ b/src/Umbraco.Core/Models/Property.cs @@ -76,7 +76,7 @@ namespace Umbraco.Cms.Core.Models /// public class InitialPropertyValue { - public InitialPropertyValue(string culture, string? segment, bool published, object? value) + public InitialPropertyValue(string? culture, string? segment, bool published, object? value) { Culture = culture; Segment = segment; @@ -84,7 +84,7 @@ namespace Umbraco.Cms.Core.Models Value = value; } - public string Culture { get; } + public string? Culture { get; } public string? Segment { get; } public bool Published { get; } public object? Value { get; } diff --git a/src/Umbraco.Core/Models/Relation.cs b/src/Umbraco.Core/Models/Relation.cs index 54227db910..7cb447ccc3 100644 --- a/src/Umbraco.Core/Models/Relation.cs +++ b/src/Umbraco.Core/Models/Relation.cs @@ -14,7 +14,7 @@ namespace Umbraco.Cms.Core.Models //NOTE: The datetime column from umbracoRelation is set on CreateDate on the Entity private int _parentId; private int _childId; - private IRelationType _relationType; + private IRelationType? _relationType; private string? _comment; /// @@ -38,7 +38,7 @@ namespace Umbraco.Cms.Core.Models /// /// /// - public Relation(int parentId, int childId, Guid parentObjectType, Guid childObjectType, IRelationType relationType) + public Relation(int parentId, int childId, Guid parentObjectType, Guid childObjectType, IRelationType? relationType) { _parentId = parentId; _childId = childId; diff --git a/src/Umbraco.Core/Models/Script.cs b/src/Umbraco.Core/Models/Script.cs index 9f1bad9e99..0d121368f8 100644 --- a/src/Umbraco.Core/Models/Script.cs +++ b/src/Umbraco.Core/Models/Script.cs @@ -14,7 +14,7 @@ namespace Umbraco.Cms.Core.Models : this(path, (Func?) null) { } - public Script(string path, Func? getFileContent) + public Script(string path, Func? getFileContent) : base(path, getFileContent) { } diff --git a/src/Umbraco.Core/Models/ServerRegistration.cs b/src/Umbraco.Core/Models/ServerRegistration.cs index 553460eb5b..cc86ee6bdd 100644 --- a/src/Umbraco.Core/Models/ServerRegistration.cs +++ b/src/Umbraco.Core/Models/ServerRegistration.cs @@ -31,7 +31,7 @@ namespace Umbraco.Cms.Core.Models /// The date and time the registration was last accessed. /// A value indicating whether the registration is active. /// A value indicating whether the registration is master. - public ServerRegistration(int id, string? serverAddress, string? serverIdentity, DateTime registered, DateTime accessed, bool isActive, bool isSchedulingPublisher) + public ServerRegistration(int id, string? serverAddress, string? serverIdentity, DateTime? registered, DateTime? accessed, bool isActive, bool isSchedulingPublisher) { UpdateDate = accessed; CreateDate = registered; diff --git a/src/Umbraco.Core/Models/Stylesheet.cs b/src/Umbraco.Core/Models/Stylesheet.cs index 18f9420d75..7b1d971434 100644 --- a/src/Umbraco.Core/Models/Stylesheet.cs +++ b/src/Umbraco.Core/Models/Stylesheet.cs @@ -20,7 +20,7 @@ namespace Umbraco.Cms.Core.Models : this(path, null) { } - public Stylesheet(string path, Func? getFileContent) + public Stylesheet(string path, Func? getFileContent) : base(string.IsNullOrEmpty(path) ? path : path.EnsureEndsWith(".css"), getFileContent) { InitializeProperties(); diff --git a/src/Umbraco.Core/Models/TaggedProperty.cs b/src/Umbraco.Core/Models/TaggedProperty.cs index d2c5dc0b23..24ef9ccc45 100644 --- a/src/Umbraco.Core/Models/TaggedProperty.cs +++ b/src/Umbraco.Core/Models/TaggedProperty.cs @@ -10,7 +10,7 @@ namespace Umbraco.Cms.Core.Models /// /// Initializes a new instance of the class. /// - public TaggedProperty(int propertyTypeId, string propertyTypeAlias, IEnumerable tags) + public TaggedProperty(int propertyTypeId, string? propertyTypeAlias, IEnumerable tags) { PropertyTypeId = propertyTypeId; PropertyTypeAlias = propertyTypeAlias; @@ -25,7 +25,7 @@ namespace Umbraco.Cms.Core.Models /// /// Gets the alias of the property type. /// - public string PropertyTypeAlias { get; } + public string? PropertyTypeAlias { get; } /// /// Gets the tags. diff --git a/src/Umbraco.Core/Models/Template.cs b/src/Umbraco.Core/Models/Template.cs index d2029fa801..b2e3f16de9 100644 --- a/src/Umbraco.Core/Models/Template.cs +++ b/src/Umbraco.Core/Models/Template.cs @@ -22,7 +22,7 @@ namespace Umbraco.Cms.Core.Models : this(shortStringHelper, name, alias, null) { } - public Template(IShortStringHelper shortStringHelper, string? name, string alias, Func? getFileContent) + public Template(IShortStringHelper shortStringHelper, string? name, string alias, Func? getFileContent) : base(string.Empty, getFileContent) { _shortStringHelper = shortStringHelper; diff --git a/src/Umbraco.Core/Models/TwoFactorLogin.cs b/src/Umbraco.Core/Models/TwoFactorLogin.cs index 350a5f2f1a..c38105626c 100644 --- a/src/Umbraco.Core/Models/TwoFactorLogin.cs +++ b/src/Umbraco.Core/Models/TwoFactorLogin.cs @@ -5,8 +5,8 @@ namespace Umbraco.Cms.Core.Models { public class TwoFactorLogin : EntityBase, ITwoFactorLogin { - public string? ProviderName { get; set; } - public string? Secret { get; set; } + public string ProviderName { get; set; } = null!; + public string Secret { get; set; } = null!; public Guid UserOrMemberKey { get; set; } public bool Confirmed { get; set; } } diff --git a/src/Umbraco.Core/Persistence/IQueryRepository.cs b/src/Umbraco.Core/Persistence/IQueryRepository.cs index 9513573908..6623fbf0fc 100644 --- a/src/Umbraco.Core/Persistence/IQueryRepository.cs +++ b/src/Umbraco.Core/Persistence/IQueryRepository.cs @@ -11,7 +11,7 @@ namespace Umbraco.Cms.Core.Persistence /// /// Gets entities. /// - IEnumerable Get(IQuery query); + IEnumerable? Get(IQuery query); /// /// Counts entities. diff --git a/src/Umbraco.Core/Persistence/IReadRepository.cs b/src/Umbraco.Core/Persistence/IReadRepository.cs index 3e495f7e36..57a25f3f81 100644 --- a/src/Umbraco.Core/Persistence/IReadRepository.cs +++ b/src/Umbraco.Core/Persistence/IReadRepository.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Core.Persistence /// /// Gets entities. /// - IEnumerable GetMany(params TId?[] ids); + IEnumerable? GetMany(params TId[]? ids); /// /// Gets a value indicating whether an entity exists. diff --git a/src/Umbraco.Core/Persistence/Querying/IQuery.cs b/src/Umbraco.Core/Persistence/Querying/IQuery.cs index c55d14001d..d2a3b0830f 100644 --- a/src/Umbraco.Core/Persistence/Querying/IQuery.cs +++ b/src/Umbraco.Core/Persistence/Querying/IQuery.cs @@ -30,7 +30,7 @@ namespace Umbraco.Cms.Core.Persistence.Querying /// /// /// This instance so calls to this method are chainable - IQuery WhereIn(Expression> fieldSelector, IEnumerable values); + IQuery WhereIn(Expression> fieldSelector, IEnumerable? values); /// /// Adds a set of OR-ed where clauses to the query. diff --git a/src/Umbraco.Core/Persistence/Repositories/IContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IContentRepository.cs index be12da3203..b753d35544 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IContentRepository.cs @@ -34,7 +34,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// /// Gets a version. /// - TEntity GetVersion(int versionId); + TEntity? GetVersion(int versionId); /// /// Deletes a version. @@ -54,7 +54,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// /// Gets the recycle bin content. /// - IEnumerable GetRecycleBin(); + IEnumerable? GetRecycleBin(); /// /// Gets the count of content items of a given content type. diff --git a/src/Umbraco.Core/Persistence/Repositories/IContentTypeCommonRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IContentTypeCommonRepository.cs index 955ad47a72..7bdfa294c8 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IContentTypeCommonRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IContentTypeCommonRepository.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// /// Gets and cache all types. /// - IEnumerable GetAllTypes(); + IEnumerable? GetAllTypes(); /// /// Clears the cache. diff --git a/src/Umbraco.Core/Persistence/Repositories/IDictionaryRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IDictionaryRepository.cs index c448b39ce9..555624b1a0 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IDictionaryRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IDictionaryRepository.cs @@ -6,8 +6,8 @@ namespace Umbraco.Cms.Core.Persistence.Repositories { public interface IDictionaryRepository : IReadWriteQueryRepository { - IDictionaryItem Get(Guid uniqueId); - IDictionaryItem Get(string key); + IDictionaryItem? Get(Guid uniqueId); + IDictionaryItem? Get(string key); IEnumerable GetDictionaryItemDescendants(Guid? parentId); Dictionary GetDictionaryItemKeyMap(); } diff --git a/src/Umbraco.Core/Persistence/Repositories/IDocumentVersionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IDocumentVersionRepository.cs index 38f425d5a1..ee46db3690 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IDocumentVersionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IDocumentVersionRepository.cs @@ -8,17 +8,17 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// /// Gets a list of all historic content versions. /// - public IReadOnlyCollection GetDocumentVersionsEligibleForCleanup(); + public IReadOnlyCollection? GetDocumentVersionsEligibleForCleanup(); /// /// Gets cleanup policy override settings per content type. /// - public IReadOnlyCollection GetCleanupPolicies(); + public IReadOnlyCollection? GetCleanupPolicies(); /// /// Gets paginated content versions for given content id paginated. /// - public IEnumerable GetPagedItemsByContentId(int contentId, long pageIndex, int pageSize, out long totalRecords, int? languageId = null); + public IEnumerable? GetPagedItemsByContentId(int contentId, long pageIndex, int pageSize, out long totalRecords, int? languageId = null); /// /// Deletes multiple content versions by ID. @@ -33,6 +33,6 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// /// Gets the content version metadata for a specific version. /// - ContentVersionMeta Get(int versionId); + ContentVersionMeta? Get(int versionId); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/IDomainRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IDomainRepository.cs index a0827f95c1..007c2928a4 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IDomainRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IDomainRepository.cs @@ -5,9 +5,9 @@ namespace Umbraco.Cms.Core.Persistence.Repositories { public interface IDomainRepository : IReadWriteQueryRepository { - IDomain GetByName(string domainName); + IDomain? GetByName(string domainName); bool Exists(string domainName); - IEnumerable GetAll(bool includeWildcards); - IEnumerable GetAssignedDomains(int contentId, bool includeWildcards); + IEnumerable? GetAll(bool includeWildcards); + IEnumerable? GetAssignedDomains(int contentId, bool includeWildcards); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/IEntityContainerRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IEntityContainerRepository.cs index 36a07c2fe9..6b8ece1bfd 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IEntityContainerRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IEntityContainerRepository.cs @@ -6,7 +6,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories { public interface IEntityContainerRepository : IReadRepository, IWriteRepository { - EntityContainer Get(Guid id); + EntityContainer? Get(Guid id); IEnumerable Get(string name, int level); } diff --git a/src/Umbraco.Core/Persistence/Repositories/IEntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IEntityRepository.cs index 30efd080d9..8eeab0b834 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IEntityRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IEntityRepository.cs @@ -9,10 +9,10 @@ namespace Umbraco.Cms.Core.Persistence.Repositories { public interface IEntityRepository : IRepository { - IEntitySlim Get(int id); - IEntitySlim Get(Guid key); - IEntitySlim Get(int id, Guid objectTypeId); - IEntitySlim Get(Guid key, Guid objectTypeId); + IEntitySlim? Get(int id); + IEntitySlim? Get(Guid key); + IEntitySlim? Get(int id, Guid objectTypeId); + IEntitySlim? Get(Guid key, Guid objectTypeId); IEnumerable GetAll(Guid objectType, params int[] ids); IEnumerable GetAll(Guid objectType, params Guid[] keys); diff --git a/src/Umbraco.Core/Persistence/Repositories/IFileRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IFileRepository.cs index ce76086ed2..0ecff83bf8 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IFileRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IFileRepository.cs @@ -4,7 +4,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories { public interface IFileRepository { - Stream GetFileContentStream(string filepath); + Stream? GetFileContentStream(string filepath); void SetFileContent(string filepath, Stream content); diff --git a/src/Umbraco.Core/Persistence/Repositories/IKeyValueRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IKeyValueRepository.cs index 0b0f9193fa..94001609d6 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IKeyValueRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IKeyValueRepository.cs @@ -10,6 +10,6 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// /// /// - IReadOnlyDictionary FindByKeyPrefix(string keyPrefix); + IReadOnlyDictionary? FindByKeyPrefix(string keyPrefix); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/ILanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ILanguageRepository.cs index eeaeed82bb..1be32de989 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ILanguageRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ILanguageRepository.cs @@ -4,7 +4,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories { public interface ILanguageRepository : IReadWriteQueryRepository { - ILanguage GetByIsoCode(string isoCode); + ILanguage? GetByIsoCode(string isoCode); /// /// Gets a language identifier from its ISO code. @@ -20,7 +20,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// /// This can be optimized and bypass all deep cloning. /// - string GetIsoCodeById(int? id, bool throwOnNotFound = true); + string? GetIsoCodeById(int? id, bool throwOnNotFound = true); /// /// Gets the default language ISO code. diff --git a/src/Umbraco.Core/Persistence/Repositories/ILogViewerQueryRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ILogViewerQueryRepository.cs index d21cd2aa1e..8e3d779b9d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ILogViewerQueryRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ILogViewerQueryRepository.cs @@ -4,6 +4,6 @@ namespace Umbraco.Cms.Core.Persistence.Repositories { public interface ILogViewerQueryRepository : IReadWriteQueryRepository { - ILogViewerQuery GetByName(string name); + ILogViewerQuery? GetByName(string name); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/IMediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IMediaRepository.cs index d07f2a68c7..ad268c6292 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IMediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IMediaRepository.cs @@ -5,7 +5,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories { public interface IMediaRepository : IContentRepository, IReadRepository { - IMedia GetMediaByPath(string mediaPath); + IMedia? GetMediaByPath(string mediaPath); bool RecycleBinSmells(); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/IMemberGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IMemberGroupRepository.cs index 2c80106aab..2307ff2b8b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IMemberGroupRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IMemberGroupRepository.cs @@ -11,20 +11,20 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// /// /// - IMemberGroup Get(Guid uniqueId); + IMemberGroup? Get(Guid uniqueId); /// /// Gets a member group by it's name /// /// /// - IMemberGroup GetByName(string name); + IMemberGroup? GetByName(string name); /// /// Creates the new member group if it doesn't already exist /// /// - IMemberGroup CreateIfNotExists(string roleName); + IMemberGroup? CreateIfNotExists(string roleName); /// /// Returns the member groups for a given member diff --git a/src/Umbraco.Core/Persistence/Repositories/IMemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IMemberRepository.cs index 9b24d60a9f..f6cf00c5bf 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IMemberRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IMemberRepository.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories { int[] GetMemberIds(string[] names); - IMember GetByUsername(string username); + IMember? GetByUsername(string username); /// /// Finds members in a given role diff --git a/src/Umbraco.Core/Persistence/Repositories/INotificationsRepository.cs b/src/Umbraco.Core/Persistence/Repositories/INotificationsRepository.cs index 18585b06a0..be1a00a130 100644 --- a/src/Umbraco.Core/Persistence/Repositories/INotificationsRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/INotificationsRepository.cs @@ -12,9 +12,9 @@ namespace Umbraco.Cms.Core.Persistence.Repositories int DeleteNotifications(IUser user); int DeleteNotifications(IEntity entity); int DeleteNotifications(IUser user, IEntity entity); - IEnumerable GetEntityNotifications(IEntity entity); - IEnumerable GetUserNotifications(IUser user); - IEnumerable GetUsersNotifications(IEnumerable userIds, string? action, IEnumerable nodeIds, Guid objectType); + IEnumerable? GetEntityNotifications(IEntity entity); + IEnumerable? GetUserNotifications(IUser user); + IEnumerable? GetUsersNotifications(IEnumerable userIds, string? action, IEnumerable nodeIds, Guid objectType); IEnumerable SetNotifications(IUser user, IEntity entity, string[] actions); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/IRedirectUrlRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IRedirectUrlRepository.cs index d02fe72bc8..17be5b3856 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IRedirectUrlRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IRedirectUrlRepository.cs @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// The content unique key. /// The culture. /// - IRedirectUrl Get(string url, Guid contentKey, string? culture); + IRedirectUrl? Get(string url, Guid contentKey, string? culture); /// /// Deletes a redirect URL. @@ -40,7 +40,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// /// The Umbraco redirect URL route. /// The most recent redirect URL corresponding to the route. - IRedirectUrl GetMostRecentUrl(string url); + IRedirectUrl? GetMostRecentUrl(string url); /// /// Gets the most recent redirect URL corresponding to an Umbraco redirect URL route. @@ -48,7 +48,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// The Umbraco redirect URL route. /// The culture the domain is associated with /// The most recent redirect URL corresponding to the route. - IRedirectUrl GetMostRecentUrl(string url, string culture); + IRedirectUrl? GetMostRecentUrl(string url, string culture); /// /// Gets all redirect URLs for a content item. diff --git a/src/Umbraco.Core/Persistence/Repositories/ITagRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ITagRepository.cs index d9794ed1bd..e2fa2e4406 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ITagRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ITagRepository.cs @@ -50,12 +50,12 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// /// Gets a tagged entity. /// - TaggedEntity GetTaggedEntityByKey(Guid key); + TaggedEntity? GetTaggedEntityByKey(Guid key); /// /// Gets a tagged entity. /// - TaggedEntity GetTaggedEntityById(int id); + TaggedEntity? GetTaggedEntityById(int id); /// Gets all entities of a type, tagged with any tag in the specified group. IEnumerable GetTaggedEntitiesByTagGroup(TaggableObjectTypes objectType, string group, string? culture = null); diff --git a/src/Umbraco.Core/Persistence/Repositories/ITemplateRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ITemplateRepository.cs index 34b061a50e..fd206d5aff 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ITemplateRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ITemplateRepository.cs @@ -5,11 +5,11 @@ namespace Umbraco.Cms.Core.Persistence.Repositories { public interface ITemplateRepository : IReadWriteQueryRepository, IFileRepository { - ITemplate Get(string? alias); + ITemplate? Get(string? alias); - IEnumerable GetAll(params string[] aliases); + IEnumerable? GetAll(params string[] aliases); - IEnumerable GetChildren(int masterTemplateId); + IEnumerable? GetChildren(int masterTemplateId); IEnumerable GetDescendants(int masterTemplateId); } diff --git a/src/Umbraco.Core/Persistence/Repositories/IUserGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IUserGroupRepository.cs index 6f2cd75bdb..f90596b1f8 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IUserGroupRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IUserGroupRepository.cs @@ -10,7 +10,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// /// /// - IUserGroup Get(string alias); + IUserGroup? Get(string alias); /// /// This is useful when an entire section is removed from config diff --git a/src/Umbraco.Core/Persistence/Repositories/IUserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IUserRepository.cs index 1c74f8430e..f5649526d9 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IUserRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IUserRepository.cs @@ -83,7 +83,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// /// A non cached instance /// - IUser GetByUsername(string username, bool includeSecurityData); + IUser? GetByUsername(string username, bool includeSecurityData); /// /// Returns a user by id @@ -95,10 +95,10 @@ namespace Umbraco.Cms.Core.Persistence.Repositories /// /// A non cached instance /// - IUser Get(int? id, bool includeSecurityData); + IUser? Get(int? id, bool includeSecurityData); - IProfile GetProfile(string username); - IProfile GetProfile(int id); + IProfile? GetProfile(string username); + IProfile? GetProfile(int id); IDictionary GetUserStates(); Guid CreateLoginSession(int? userId, string requestingIpAddress, bool cleanStaleSessions = true); diff --git a/src/Umbraco.Core/Persistence/SqlExtensionsStatics.cs b/src/Umbraco.Core/Persistence/SqlExtensionsStatics.cs index ef20e93282..cec65de33f 100644 --- a/src/Umbraco.Core/Persistence/SqlExtensionsStatics.cs +++ b/src/Umbraco.Core/Persistence/SqlExtensionsStatics.cs @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Core.Persistence /// /// The field to alias. /// The alias. - public static object Alias(object field, string alias) => field; + public static object Alias(object? field, string alias) => field; /// /// Produces Sql text. diff --git a/src/Umbraco.Core/Scoping/IScopeProvider.cs b/src/Umbraco.Core/Scoping/IScopeProvider.cs index c9c30662b4..d4bfee3886 100644 --- a/src/Umbraco.Core/Scoping/IScopeProvider.cs +++ b/src/Umbraco.Core/Scoping/IScopeProvider.cs @@ -85,7 +85,7 @@ namespace Umbraco.Cms.Core.Scoping /// /// Creates an instance of /// - IQuery CreateQuery(); + IQuery? CreateQuery(); #if DEBUG_SCOPES diff --git a/src/Umbraco.Core/Security/IdentityUserLogin.cs b/src/Umbraco.Core/Security/IdentityUserLogin.cs index 402660ead9..efe0dcbf66 100644 --- a/src/Umbraco.Core/Security/IdentityUserLogin.cs +++ b/src/Umbraco.Core/Security/IdentityUserLogin.cs @@ -22,7 +22,7 @@ namespace Umbraco.Cms.Core.Security /// /// Initializes a new instance of the class. /// - public IdentityUserLogin(int id, string loginProvider, string providerKey, string userId, DateTime createDate) + public IdentityUserLogin(int id, string loginProvider, string providerKey, string userId, DateTime? createDate) { Id = id; LoginProvider = loginProvider; diff --git a/src/Umbraco.Core/Services/IAuditService.cs b/src/Umbraco.Core/Services/IAuditService.cs index 8af4058c12..cbc3db8239 100644 --- a/src/Umbraco.Core/Services/IAuditService.cs +++ b/src/Umbraco.Core/Services/IAuditService.cs @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Core.Services { void Add(AuditType type, int userId, int objectId, string? entityType, string comment, string? parameters = null); - IEnumerable GetLogs(int objectId); + IEnumerable? GetLogs(int objectId); IEnumerable GetUserLogs(int userId, AuditType type, DateTime? sinceDate = null); IEnumerable GetLogs(AuditType type, DateTime? sinceDate = null); void CleanLogs(int maximumAgeOfLogsInMinutes); diff --git a/src/Umbraco.Core/Services/IDataTypeService.cs b/src/Umbraco.Core/Services/IDataTypeService.cs index f7c222925c..56766bbe23 100644 --- a/src/Umbraco.Core/Services/IDataTypeService.cs +++ b/src/Umbraco.Core/Services/IDataTypeService.cs @@ -20,10 +20,10 @@ namespace Umbraco.Cms.Core.Services Attempt?> CreateContainer(int parentId, Guid key, string name, int userId = Constants.Security.SuperUserId); Attempt SaveContainer(EntityContainer container, int userId = Constants.Security.SuperUserId); EntityContainer? GetContainer(int containerId); - EntityContainer GetContainer(Guid containerId); + EntityContainer? GetContainer(Guid containerId); IEnumerable GetContainers(string folderName, int level); - IEnumerable GetContainers(IDataType dataType); - IEnumerable GetContainers(int[] containerIds); + IEnumerable? GetContainers(IDataType dataType); + IEnumerable? GetContainers(int[] containerIds); Attempt DeleteContainer(int containerId, int userId = Constants.Security.SuperUserId); Attempt?> RenameContainer(int id, string name, int userId = Constants.Security.SuperUserId); @@ -53,7 +53,7 @@ namespace Umbraco.Cms.Core.Services /// /// Optional array of Ids /// An enumerable list of objects - IEnumerable GetAll(params int[] ids); + IEnumerable? GetAll(params int[] ids); /// /// Saves an @@ -85,7 +85,7 @@ namespace Umbraco.Cms.Core.Services /// /// Alias of the property editor /// Collection of objects with a matching control id - IEnumerable GetByEditorAlias(string propertyEditorAlias); + IEnumerable? GetByEditorAlias(string propertyEditorAlias); Attempt?> Move(IDataType toMove, int parentId); } diff --git a/src/Umbraco.Core/Services/IServerRegistrationService.cs b/src/Umbraco.Core/Services/IServerRegistrationService.cs index d5cfd9f7a7..f9aaf7e33f 100644 --- a/src/Umbraco.Core/Services/IServerRegistrationService.cs +++ b/src/Umbraco.Core/Services/IServerRegistrationService.cs @@ -35,7 +35,7 @@ namespace Umbraco.Cms.Core.Services /// time the current server is touched, and the period depends on the configuration. Use the /// parameter to force a cache refresh and reload active servers /// from the database. - IEnumerable GetActiveServers(bool refresh = false); + IEnumerable? GetActiveServers(bool refresh = false); /// /// Gets the role of the current server. diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs index 5962638d57..21da2f797a 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs @@ -33,12 +33,12 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps var result = _databaseBuilder.CreateSchemaAndData(); - if (result.Success == false) + if (result?.Success == false) { throw new InstallException("The database failed to install. ERROR: " + result.Message); } - if (result.RequiresUpgrade == false) + if (result?.RequiresUpgrade == false) { return Task.FromResult(null); } diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseUpgradeStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseUpgradeStep.cs index d50624d0c2..693cd1cbde 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseUpgradeStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseUpgradeStep.cs @@ -84,7 +84,7 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps // a connection string was present, determine whether this is an install/upgrade // return true (upgrade) if there is an installed version, else false (install) var result = _databaseBuilder.ValidateSchema(); - return result.DetermineHasInstalledVersion(); + return result?.DetermineHasInstalledVersion() ?? false; } //no connection string configured, probably a fresh install diff --git a/src/Umbraco.Infrastructure/Install/UnattendedUpgrader.cs b/src/Umbraco.Infrastructure/Install/UnattendedUpgrader.cs index 5f5c8f16a8..312106ecca 100644 --- a/src/Umbraco.Infrastructure/Install/UnattendedUpgrader.cs +++ b/src/Umbraco.Infrastructure/Install/UnattendedUpgrader.cs @@ -56,8 +56,8 @@ namespace Umbraco.Cms.Infrastructure.Install "Starting unattended upgrade.", "Unattended upgrade completed.")) { - DatabaseBuilder.Result result = _databaseBuilder.UpgradeSchemaAndData(plan); - if (result.Success == false) + DatabaseBuilder.Result? result = _databaseBuilder.UpgradeSchemaAndData(plan); + if (result?.Success == false) { var innerException = new UnattendedInstallException("An error occurred while running the unattended upgrade.\n" + result.Message); _runtimeState.Configure(Core.RuntimeLevel.BootFailed, Core.RuntimeLevelReason.BootFailedOnException, innerException); diff --git a/src/Umbraco.Infrastructure/Mapping/UmbracoMapper.cs b/src/Umbraco.Infrastructure/Mapping/UmbracoMapper.cs index 249b01f60f..c0436838e0 100644 --- a/src/Umbraco.Infrastructure/Mapping/UmbracoMapper.cs +++ b/src/Umbraco.Infrastructure/Mapping/UmbracoMapper.cs @@ -107,7 +107,7 @@ namespace Umbraco.Cms.Core.Mapping var sourceCtors = DefineCtors(sourceType); if (ctor != null) - sourceCtors[targetType] = (source, context) => ctor((TSource)source, context); + sourceCtors[targetType] = (source, context) => ctor((TSource)source, context)!; var sourceMaps = DefineMaps(sourceType); sourceMaps[targetType] = (source, target, context) => map((TSource)source, (TTarget)target, context); @@ -221,13 +221,14 @@ namespace Umbraco.Cms.Core.Mapping var ienumerableOfT = typeof(IEnumerable<>); - bool IsIEnumerableOfT(Type type) => + bool IsIEnumerableOfT(Type? type) => + type is not null && type.IsGenericType && type.GenericTypeArguments.Length == 1 && type.GetGenericTypeDefinition() == ienumerableOfT; // try to get source as an IEnumerable - var sourceIEnumerable = IsIEnumerableOfT(sourceType) ? sourceType : sourceType.GetInterfaces().FirstOrDefault(IsIEnumerableOfT); + var sourceIEnumerable = IsIEnumerableOfT(sourceType) ? sourceType : sourceType?.GetInterfaces().FirstOrDefault(IsIEnumerableOfT); // if source is an IEnumerable and target is T[] or IEnumerable, we can create a map if (sourceIEnumerable != null && IsEnumerableOrArrayOfType(targetType)) @@ -340,8 +341,12 @@ namespace Umbraco.Cms.Core.Mapping throw new InvalidOperationException($"Don't know how to map {typeof(TSource).FullName} to {typeof(TTarget).FullName}."); } - private Func? GetCtor(Type sourceType, Type targetType) + private Func? GetCtor(Type? sourceType, Type targetType) { + if (sourceType is null) + { + return null; + } if (_ctors.TryGetValue(sourceType, out var sourceCtor) && sourceCtor.TryGetValue(targetType, out var ctor)) return ctor; @@ -357,7 +362,7 @@ namespace Umbraco.Cms.Core.Mapping break; } - if (ctor == null) return null; + if (ctor is null || sourceCtor is null) return null; _ctors.AddOrUpdate(sourceType, sourceCtor, (k, v) => { @@ -377,8 +382,12 @@ namespace Umbraco.Cms.Core.Mapping return ctor; } - private Action GetMap(Type sourceType, Type targetType) + private Action? GetMap(Type? sourceType, Type targetType) { + if (sourceType is null) + { + return null; + } if (_maps.TryGetValue(sourceType, out var sourceMap) && sourceMap.TryGetValue(targetType, out var map)) return map; @@ -396,7 +405,7 @@ namespace Umbraco.Cms.Core.Mapping break; } - if (map == null) return null; + if (map is null || sourceMap is null) return null; if (_maps.ContainsKey(sourceType)) { @@ -419,7 +428,7 @@ namespace Umbraco.Cms.Core.Mapping return false; } - private static Type GetEnumerableOrArrayTypeArgument(Type type) + private static Type? GetEnumerableOrArrayTypeArgument(Type type) { if (type.IsArray) return type.GetElementType(); if (type.IsGenericType) return type.GenericTypeArguments[0]; @@ -433,7 +442,7 @@ namespace Umbraco.Cms.Core.Mapping /// The type of the target objects. /// The source objects. /// A list containing the target objects. - public List MapEnumerable(IEnumerable source) + public List MapEnumerable(IEnumerable source) { return source.Select(Map).ToList(); } @@ -446,7 +455,7 @@ namespace Umbraco.Cms.Core.Mapping /// The source objects. /// A mapper context preparation method. /// A list containing the target objects. - public List MapEnumerable(IEnumerable source, Action f) + public List MapEnumerable(IEnumerable source, Action f) { var context = new MapperContext(this); f(context); @@ -461,7 +470,7 @@ namespace Umbraco.Cms.Core.Mapping /// The source objects. /// A mapper context. /// A list containing the target objects. - public List MapEnumerable(IEnumerable source, MapperContext context) + public List MapEnumerable(IEnumerable source, MapperContext context) { return source.Select(x => Map(x, context)).ToList(); } diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Expressions/CreateTableExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Expressions/CreateTableExpression.cs index 9d190b010f..e7ed2faf53 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Expressions/CreateTableExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Expressions/CreateTableExpression.cs @@ -11,8 +11,8 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Expressions Columns = new List(); } - public virtual string? SchemaName { get; set; } - public virtual string? TableName { get; set; } + public virtual string SchemaName { get; set; } = null!; + public virtual string TableName { get; set; } = null!; public virtual IList Columns { get; set; } protected override string GetSql() diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index 37231a9487..30c881511d 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -313,7 +313,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install #region Database Schema - public void CreateDatabase() => _dbProviderFactoryCreator.CreateDatabase(_databaseFactory.ProviderName, _databaseFactory.ConnectionString); + public void CreateDatabase() => _dbProviderFactoryCreator.CreateDatabase(_databaseFactory.ProviderName!, _databaseFactory.ConnectionString!); /// /// Validates the database schema. diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs index 6a8c7ea350..fc6f669f7d 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs @@ -455,14 +455,14 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install private void CreateLogViewerQueryData() { - var defaultData = MigrateLogViewerQueriesFromFileToDb.DefaultLogQueries.ToArray(); - - for (int i = 0; i < defaultData.Length; i++) - { - var dto = defaultData[i]; - dto.Id = i+1; - _database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.LogViewerQuery, "id", false, dto); - } + // var defaultData = MigrateLogViewerQueriesFromFileToDb.DefaultLogQueries.ToArray(); + // + // for (int i = 0; i < defaultData.Length; i++) + // { + // var dto = defaultData[i]; + // dto.Id = i+1; + // _database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.LogViewerQuery, "id", false, dto); + // } } } } diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationBase_Extra.cs b/src/Umbraco.Infrastructure/Migrations/MigrationBase_Extra.cs index b3ad73811e..1154d6151e 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationBase_Extra.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationBase_Extra.cs @@ -17,14 +17,14 @@ namespace Umbraco.Cms.Infrastructure.Migrations protected void AddColumn(string columnName) { var table = DefinitionFactory.GetTableDefinition(typeof(T), SqlSyntax); - AddColumn(table, table.Name, columnName); + AddColumn(table, table.Name!, columnName); } protected void AddColumnIfNotExists(IEnumerable columns, string columnName) { var table = DefinitionFactory.GetTableDefinition(typeof(T), SqlSyntax); if (columns.Any(x => x.TableName.InvariantEquals(table.Name) && !x.ColumnName.InvariantEquals(columnName))) - AddColumn(table, table.Name, columnName); + AddColumn(table, table.Name!, columnName); } protected void AddColumn(string tableName, string columnName) @@ -53,7 +53,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations protected void AddColumn(string columnName, out IEnumerable sqls) { var table = DefinitionFactory.GetTableDefinition(typeof(T), SqlSyntax); - AddColumn(table, table.Name, columnName, out sqls); + AddColumn(table, table.Name!, columnName, out sqls); } protected void AddColumn(string tableName, string columnName, out IEnumerable sqls) @@ -118,7 +118,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations return columns.Any(x => x.TableName.InvariantEquals(tableName) && x.ColumnName.InvariantEquals(columnName)); } - protected string ColumnType(string tableName, string columnName) + protected string? ColumnType(string tableName, string columnName) { var columns = SqlSyntax.GetColumnsInSchema(Context.Database).Distinct().ToArray(); var column = columns.FirstOrDefault(x => x.TableName.InvariantEquals(tableName) && x.ColumnName.InvariantEquals(columnName)); diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationContext.cs b/src/Umbraco.Infrastructure/Migrations/MigrationContext.cs index 89235292d2..975df9120d 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationContext.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationContext.cs @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations /// /// Initializes a new instance of the class. /// - public MigrationContext(MigrationPlan plan, IUmbracoDatabase database, ILogger logger) + public MigrationContext(MigrationPlan plan, IUmbracoDatabase? database, ILogger logger) { Plan = plan; Database = database ?? throw new ArgumentNullException(nameof(database)); diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationExpressionBase.cs b/src/Umbraco.Infrastructure/Migrations/MigrationExpressionBase.cs index 31aba3bb86..e89b91690f 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationExpressionBase.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationExpressionBase.cs @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations public abstract class MigrationExpressionBase : IMigrationExpression { private bool _executed; - private List _expressions; + private List? _expressions; protected MigrationExpressionBase(IMigrationContext context) { @@ -128,7 +128,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations /// This might be useful in the future if we add it to the interface, but for now it's used to hack the DeleteAppTables & DeleteForeignKeyExpression /// to ensure they are not executed twice. /// - internal string Name { get; set; } + internal string? Name { get; set; } protected string GetQuotedValue(object? val) { @@ -151,11 +151,11 @@ namespace Umbraco.Cms.Infrastructure.Migrations case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: - return val.ToString(); + return val.ToString()!; case TypeCode.DateTime: return SqlSyntax.GetQuotedValue(SqlSyntax.FormatDateTime((DateTime) val)); default: - return SqlSyntax.GetQuotedValue(val.ToString()); + return SqlSyntax.GetQuotedValue(val.ToString()!); } } } diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationPlan.cs b/src/Umbraco.Infrastructure/Migrations/MigrationPlan.cs index bdb5aeb780..091eebe496 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationPlan.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationPlan.cs @@ -12,11 +12,11 @@ namespace Umbraco.Cms.Infrastructure.Migrations /// public class MigrationPlan { - private readonly Dictionary _transitions = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + private readonly Dictionary _transitions = new Dictionary(StringComparer.InvariantCultureIgnoreCase); private readonly List _postMigrationTypes = new List(); - private string _prevState; - private string _finalState; + private string? _prevState; + private string? _finalState; /// /// Initializes a new instance of the class. @@ -46,7 +46,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations /// /// Gets the transitions. /// - public IReadOnlyDictionary Transitions => _transitions; + public IReadOnlyDictionary Transitions => _transitions; public IReadOnlyList PostMigrationTypes => _postMigrationTypes; @@ -56,7 +56,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations public string Name { get; } // adds a transition - private MigrationPlan Add(string sourceState, string targetState, Type migration) + private MigrationPlan Add(string? sourceState, string targetState, Type? migration) { if (sourceState == null) throw new ArgumentNullException(nameof(sourceState), $"{nameof(sourceState)} is null, {nameof(MigrationPlan)}.{nameof(MigrationPlan.From)} must not have been called."); @@ -118,7 +118,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations /// /// Adds a transition to a target state through a migration. /// - public MigrationPlan To(string targetState, Type migration) + public MigrationPlan To(string targetState, Type? migration) => Add(_prevState, targetState, migration); public MigrationPlan To(Guid targetState, Type migration) @@ -127,7 +127,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations /// /// Sets the starting state. /// - public MigrationPlan From(string sourceState) + public MigrationPlan From(string? sourceState) { _prevState = sourceState ?? throw new ArgumentNullException(nameof(sourceState)); return this; @@ -192,18 +192,18 @@ namespace Umbraco.Cms.Infrastructure.Migrations while (state != endState) { - if (visited.Contains(state)) + if (state is null || visited.Contains(state)) throw new InvalidOperationException("A loop was detected in the copied chain."); visited.Add(state); if (!_transitions.TryGetValue(state, out var transition)) throw new InvalidOperationException($"There is no transition from state \"{state}\"."); - var newTargetState = transition.TargetState == endState + var newTargetState = transition?.TargetState == endState ? targetState : CreateRandomState(); - To(newTargetState, transition.MigrationType); - state = transition.TargetState; + To(newTargetState, transition?.MigrationType); + state = transition?.TargetState; } return this; @@ -255,7 +255,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations if (_finalState == null) Validate(); - return _finalState; + return _finalState!; } } @@ -272,7 +272,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations // that is not null and does not match any source state. such a target state has // been registered as a source state with a null transition. so there should be only // one. - string finalState = null; + string? finalState = null; foreach (var kvp in _transitions.Where(x => x.Value == null)) { if (finalState == null) @@ -302,7 +302,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations verified.AddRange(visited); } - _finalState = finalState; + _finalState = finalState!; } /// @@ -317,9 +317,9 @@ namespace Umbraco.Cms.Infrastructure.Migrations /// Follows a path (for tests and debugging). /// /// Does the same thing Execute does, but does not actually execute migrations. - internal IReadOnlyList FollowPath(string fromState = null, string toState = null) + internal IReadOnlyList FollowPath(string? fromState = null, string? toState = null) { - toState = toState.NullOrWhiteSpaceAsNull(); + toState = toState?.NullOrWhiteSpaceAsNull(); Validate(); diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs b/src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs index 358d7d0281..8834c68191 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs @@ -52,7 +52,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations _logger.LogInformation("At {OrigState}", string.IsNullOrWhiteSpace(nextState) ? "origin" : nextState); - if (!plan.Transitions.TryGetValue(nextState, out MigrationPlan.Transition transition)) + if (!plan.Transitions.TryGetValue(nextState, out MigrationPlan.Transition? transition)) { plan.ThrowOnUnknownInitialState(nextState); } @@ -65,7 +65,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations // that packages notification handlers may explode because that package isn't fully installed yet. using (scope.Notifications.Suppress()) { - var context = new MigrationContext(plan, _scopeAccessor.AmbientScope.Database, _loggerFactory.CreateLogger()); + var context = new MigrationContext(plan, _scopeAccessor.AmbientScope?.Database, _loggerFactory.CreateLogger()); while (transition != null) { diff --git a/src/Umbraco.Infrastructure/Migrations/PostMigrations/DeleteLogViewerQueryFile.cs b/src/Umbraco.Infrastructure/Migrations/PostMigrations/DeleteLogViewerQueryFile.cs index ef4e3de38e..3531959dbb 100644 --- a/src/Umbraco.Infrastructure/Migrations/PostMigrations/DeleteLogViewerQueryFile.cs +++ b/src/Umbraco.Infrastructure/Migrations/PostMigrations/DeleteLogViewerQueryFile.cs @@ -1,6 +1,6 @@ using System.IO; using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_9_0_0; +// using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_9_0_0; namespace Umbraco.Cms.Infrastructure.Migrations.PostMigrations { diff --git a/src/Umbraco.Infrastructure/Models/PathValidationExtensions.cs b/src/Umbraco.Infrastructure/Models/PathValidationExtensions.cs index 61b14d15ab..e7286d683f 100644 --- a/src/Umbraco.Infrastructure/Models/PathValidationExtensions.cs +++ b/src/Umbraco.Infrastructure/Models/PathValidationExtensions.cs @@ -33,7 +33,7 @@ namespace Umbraco.Cms.Core.Models throw new InvalidDataException($"The content item {entity.NodeId} has an invalid path: {entity.Path} with parentID: {entity.ParentId}"); } - if (entity.ParentId != default(int) && pathParts[pathParts.Length - 2] != entity.ParentId?.ToInvariantString()) + if (entity.ParentId != default(int) && pathParts[pathParts.Length - 2] != entity.ParentId.ToInvariantString()) { //the 2nd last id in the path must be it's parent id throw new InvalidDataException($"The content item {entity.NodeId} has an invalid path: {entity.Path} with parentID: {entity.ParentId}"); diff --git a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs index 0af21b7eb2..bb9866e116 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs @@ -23,7 +23,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging _parser = parser ?? throw new ArgumentNullException(nameof(parser)); } - public CompiledPackage ReadPackage(XDocument packageXmlFile) + public CompiledPackage ReadPackage(XDocument? packageXmlFile) { if (packageXmlFile == null) throw new ArgumentNullException(nameof(packageXmlFile)); @@ -73,7 +73,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging packageDefinition.PartialViews.Add(x.Path); packageDefinition.ContentNodeId = installationSummary.ContentInstalled.FirstOrDefault()?.Id.ToInvariantString(); - + foreach (var x in installationSummary.MediaInstalled) packageDefinition.MediaUdis.Add(x.GetUdi()); diff --git a/src/Umbraco.Infrastructure/Packaging/PendingPackageMigrations.cs b/src/Umbraco.Infrastructure/Packaging/PendingPackageMigrations.cs index 2635287db0..efefcfcc7a 100644 --- a/src/Umbraco.Infrastructure/Packaging/PendingPackageMigrations.cs +++ b/src/Umbraco.Infrastructure/Packaging/PendingPackageMigrations.cs @@ -17,7 +17,7 @@ namespace Umbraco.Cms.Core.Packaging { _logger = logger; _packageMigrationPlans = packageMigrationPlans; - + } /// @@ -27,7 +27,7 @@ namespace Umbraco.Cms.Core.Packaging /// These are the key/value pairs from the keyvalue storage of migration names and their final values /// /// - public IReadOnlyList GetPendingPackageMigrations(IReadOnlyDictionary keyValues) + public IReadOnlyList GetPendingPackageMigrations(IReadOnlyDictionary? keyValues) { var packageMigrationPlans = _packageMigrationPlans.ToList(); @@ -35,9 +35,9 @@ namespace Umbraco.Cms.Core.Packaging foreach (PackageMigrationPlan plan in packageMigrationPlans) { - string currentMigrationState = null; + string? currentMigrationState = null; var planKeyValueKey = Constants.Conventions.Migrations.KeyValuePrefix + plan.Name; - if (keyValues.TryGetValue(planKeyValueKey, out var value)) + if (keyValues?.TryGetValue(planKeyValueKey, out var value) ?? false) { currentMigrationState = value; diff --git a/src/Umbraco.Infrastructure/Persistence/BulkDataReader.cs b/src/Umbraco.Infrastructure/Persistence/BulkDataReader.cs index 1957e17655..f03b60d778 100644 --- a/src/Umbraco.Infrastructure/Persistence/BulkDataReader.cs +++ b/src/Umbraco.Infrastructure/Persistence/BulkDataReader.cs @@ -40,12 +40,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// The containing the input row set's schema information /// requires to function correctly. /// - private DataTable _schemaTable = new DataTable(); + private DataTable? _schemaTable = new DataTable(); /// /// The mapping from the row set input to the target table's columns. /// - private List _columnMappings = new List(); + private List? _columnMappings = new List(); #endregion @@ -61,7 +61,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence { get { - if (this._columnMappings.Count == 0) + if (this._columnMappings?.Count == 0) { // Need to add the column definitions and mappings. AddSchemaTableRows(); @@ -71,10 +71,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence throw new InvalidOperationException("AddSchemaTableRows did not add rows."); } - Debug.Assert(this._schemaTable.Rows.Count == FieldCount); + Debug.Assert(this._schemaTable?.Rows.Count == FieldCount); } - return new ReadOnlyCollection(_columnMappings); + return new ReadOnlyCollection(_columnMappings!); } } @@ -213,11 +213,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence bool isKey, bool allowDbNull, SqlDbType providerType, - string udtSchema, - string udtType, - string xmlSchemaCollectionDatabase, - string xmlSchemaCollectionOwningSchema, - string xmlSchemaCollectionName) + string? udtSchema, + string? udtType, + string? xmlSchemaCollectionDatabase, + string? xmlSchemaCollectionOwningSchema, + string? xmlSchemaCollectionName) { if (string.IsNullOrEmpty(columnName)) { @@ -236,7 +236,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence throw new ArgumentOutOfRangeException("columnSize"); } - List allowedOptionalColumnList; + List? allowedOptionalColumnList; if (BulkDataReader.AllowedOptionalColumnCombinations.TryGetValue(providerType, out allowedOptionalColumnList)) { @@ -629,7 +629,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence } - this._schemaTable.Rows.Add(columnName, + this._schemaTable?.Rows.Add(columnName, _schemaTable.Rows.Count, columnSize, numericPrecision, @@ -658,7 +658,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence xmlSchemaCollectionOwningSchema, xmlSchemaCollectionName); - this._columnMappings.Add(new SqlBulkCopyColumnMapping(columnName, columnName)); + this._columnMappings?.Add(new SqlBulkCopyColumnMapping(columnName, columnName)); } #endregion @@ -910,8 +910,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence object data = GetValue(i); char? dataAsChar = data as char?; - char[] dataAsCharArray = data as char[]; - string dataAsString = data as string; + char[]? dataAsCharArray = data as char[]; + string? dataAsString = data as string; if (dataAsChar.HasValue) { @@ -1015,7 +1015,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence throw new ArgumentOutOfRangeException("i"); } - return null; + return null!; } /// @@ -1306,7 +1306,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence throw new InvalidOperationException("The IDataReader is closed."); } - if (_schemaTable.Rows.Count == 0) + if (_schemaTable?.Rows.Count == 0) { // Need to add the column definitions and mappings _schemaTable.TableName = TableName; @@ -1316,7 +1316,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence Debug.Assert(_schemaTable.Rows.Count == FieldCount); } - return _schemaTable; + return _schemaTable!; } /// diff --git a/src/Umbraco.Infrastructure/Persistence/DatabaseAnnotations/IndexAttribute.cs b/src/Umbraco.Infrastructure/Persistence/DatabaseAnnotations/IndexAttribute.cs index 6d1db2dc5f..053e5b825d 100644 --- a/src/Umbraco.Infrastructure/Persistence/DatabaseAnnotations/IndexAttribute.cs +++ b/src/Umbraco.Infrastructure/Persistence/DatabaseAnnotations/IndexAttribute.cs @@ -20,7 +20,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations /// Overrides default naming of indexes: /// IX_tableName /// - public string Name { get; set; }//Overrides default naming of indexes: IX_tableName + public string? Name { get; set; }//Overrides default naming of indexes: IX_tableName /// /// Gets or sets the type of index to create @@ -30,11 +30,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations /// /// Gets or sets the column name(s) for the current index /// - public string ForColumns { get; set; } + public string? ForColumns { get; set; } /// /// Gets or sets the column name(s) for the columns to include in the index /// - public string IncludeColumns { get; set; } + public string? IncludeColumns { get; set; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/TableDefinition.cs b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/TableDefinition.cs index 092a06a57c..4ab479b8fd 100644 --- a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/TableDefinition.cs +++ b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/TableDefinition.cs @@ -11,8 +11,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions Indexes = new List(); } - public virtual string? Name { get; set; } - public virtual string? SchemaName { get; set; } + public virtual string Name { get; set; } = null!; + public virtual string SchemaName { get; set; } = null!; public virtual ICollection Columns { get; set; } public virtual ICollection ForeignKeys { get; set; } public virtual ICollection Indexes { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs index e54c1f5fbc..f3f0902456 100644 --- a/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs +++ b/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs @@ -29,7 +29,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence _providerSpecificMapperFactories = providerSpecificMapperFactories.ToDictionary(x => x.ProviderName); } - public DbProviderFactory CreateFactory(string providerName) + public DbProviderFactory? CreateFactory(string? providerName) { if (string.IsNullOrEmpty(providerName)) return null; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/AccessDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/AccessDto.cs index cc826bc3c2..ead7948191 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/AccessDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/AccessDto.cs @@ -30,14 +30,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("createDate")] [Constraint(Default = SystemMethods.CurrentDateTime)] - public DateTime CreateDate { get; set; } + public DateTime? CreateDate { get; set; } [Column("updateDate")] [Constraint(Default = SystemMethods.CurrentDateTime)] - public DateTime UpdateDate { get; set; } + public DateTime? UpdateDate { get; set; } [ResultColumn] [Reference(ReferenceType.Many, ReferenceMemberName = "AccessId")] - public List Rules { get; set; } + public List Rules { get; set; } = null!; } } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/AccessRuleDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/AccessRuleDto.cs index 307f91337b..a730fe97f6 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/AccessRuleDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/AccessRuleDto.cs @@ -27,10 +27,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("createDate")] [Constraint(Default = SystemMethods.CurrentDateTime)] - public DateTime CreateDate { get; set; } + public DateTime? CreateDate { get; set; } [Column("updateDate")] [Constraint(Default = SystemMethods.CurrentDateTime)] - public DateTime UpdateDate { get; set; } + public DateTime? UpdateDate { get; set; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCultureVariationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCultureVariationDto.cs index 4d0c8b2e6e..32307efb2b 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCultureVariationDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCultureVariationDto.cs @@ -28,10 +28,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos // this is convenient to carry the culture around, but has no db counterpart [Ignore] - public string Culture { get; set; } + public string? Culture { get; set; } [Column("name")] - public string Name { get; set; } + public string? Name { get; set; } [Column("date")] // TODO: db rename to 'updateDate' public DateTime UpdateDate { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionDto.cs index 63f2802af6..a000811c55 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionDto.cs @@ -44,11 +44,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("text")] [NullSetting(NullSetting = NullSettings.Null)] - public string Text { get; set; } + public string? Text { get; set; } [ResultColumn] [Reference(ReferenceType.OneToOne, ColumnName = "NodeId", ReferenceMemberName = "NodeId")] - public ContentDto ContentDto { get; set; } + public ContentDto? ContentDto { get; set; } [Column("preventCleanup")] [Constraint(Default = "0")] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentCultureVariationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentCultureVariationDto.cs index 3a494718b1..e13d19ae34 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentCultureVariationDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentCultureVariationDto.cs @@ -26,7 +26,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos // this is convenient to carry the culture around, but has no db counterpart [Ignore] - public string Culture { get; set; } + public string? Culture { get; set; } // authority on whether a culture has been edited [Column("edited")] @@ -47,6 +47,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos // (otherwise, it's the published one, 'cos we need to have one) [Column("name")] [NullSetting(NullSetting = NullSettings.Null)] - public string Name { get; set; } + public string? Name { get; set; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/KeyValueDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/KeyValueDto.cs index 415721811d..b23f9a6c04 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/KeyValueDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/KeyValueDto.cs @@ -13,14 +13,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("key")] [Length(256)] [PrimaryKeyColumn(AutoIncrement = false, Clustered = true)] - public string Key { get; set; } + public string? Key { get; set; } [Column("value")] [NullSetting(NullSetting = NullSettings.Null)] - public string Value { get; set; } + public string? Value { get; set; } [Column("updated")] [Constraint(Default = SystemMethods.CurrentDateTime)] - public DateTime UpdateDate { get; set; } + public DateTime? UpdateDate { get; set; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/LogDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/LogDto.cs index 2174fb6303..3b2009f3da 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/LogDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/LogDto.cs @@ -33,7 +33,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("entityType")] [Length(50)] [NullSetting(NullSetting = NullSettings.Null)] - public string EntityType { get; set; } + public string? EntityType { get; set; } // TODO: Should we have an index on this since we allow searching on it? [Column("Datestamp")] @@ -43,12 +43,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos // TODO: Should we have an index on this since we allow searching on it? [Column("logHeader")] [Length(50)] - public string Header { get; set; } + public string Header { get; set; } = null!; [Column("logComment")] [NullSetting(NullSetting = NullSettings.Null)] [Length(4000)] - public string Comment { get; set; } + public string? Comment { get; set; } /// /// Used to store additional data parameters for the log @@ -56,6 +56,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("parameters")] [NullSetting(NullSetting = NullSettings.Null)] [Length(500)] - public string Parameters { get; set; } + public string? Parameters { get; set; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/LogViewerQueryDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/LogViewerQueryDto.cs index 71642c8b73..66b4a1902c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/LogViewerQueryDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/LogViewerQueryDto.cs @@ -14,9 +14,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("name")] [Index(IndexTypes.UniqueNonClustered, Name = "IX_LogViewerQuery_name")] - public string Name { get; set; } + public string? Name { get; set; } [Column("query")] - public string Query { get; set; } + public string? Query { get; set; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/MemberDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/MemberDto.cs index 959a6c5f6a..538510c417 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/MemberDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/MemberDto.cs @@ -19,18 +19,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("Email")] [Length(1000)] [Constraint(Default = "''")] - public string Email { get; set; } + public string Email { get; set; } = null!; [Column("LoginName")] [Length(1000)] [Constraint(Default = "''")] [Index(IndexTypes.NonClustered, Name = "IX_cmsMember_LoginName")] - public string LoginName { get; set; } + public string LoginName { get; set; } = null!; [Column("Password")] [Length(1000)] [Constraint(Default = "''")] - public string Password { get; set; } + public string? Password { get; set; } /// /// This will represent a JSON structure of how the password has been created (i.e hash algorithm, iterations) @@ -53,10 +53,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [ResultColumn] [Reference(ReferenceType.OneToOne, ReferenceMemberName = "NodeId")] - public ContentDto ContentDto { get; set; } + public ContentDto ContentDto { get; set; } = null!; [ResultColumn] [Reference(ReferenceType.OneToOne, ReferenceMemberName = "NodeId")] - public ContentVersionDto ContentVersionDto { get; set; } + public ContentVersionDto ContentVersionDto { get; set; } = null!; } } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/NodeDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/NodeDto.cs index b5b1d42b49..bd41a2a297 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/NodeDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/NodeDto.cs @@ -27,7 +27,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("parentId")] [ForeignKey(typeof(NodeDto))] [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_ParentId")] - public int? ParentId { get; set; } + public int ParentId { get; set; } // NOTE: This index is primarily for the nucache data lookup, see https://github.com/umbraco/Umbraco-CMS/pull/8365#issuecomment-673404177 [Column("level")] @@ -37,7 +37,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("path")] [Length(150)] [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_Path")] - public string Path { get; set; } + public string Path { get; set; } = null!; [Column("sortOrder")] public int SortOrder { get; set; } @@ -63,6 +63,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("createDate")] [Constraint(Default = SystemMethods.CurrentDateTime)] - public DateTime CreateDate { get; set; } + public DateTime? CreateDate { get; set; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/RedirectUrlDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/RedirectUrlDto.cs index 211a52a8a1..435e072307 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/RedirectUrlDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/RedirectUrlDto.cs @@ -43,7 +43,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("culture")] [NullSetting(NullSetting = NullSettings.Null)] - public string Culture { get; set; } = null!; + public string? Culture { get; set; } [Column("urlHash")] [NullSetting(NullSetting = NullSettings.NotNull)] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/RelationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/RelationDto.cs index 8929238665..d872801163 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/RelationDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/RelationDto.cs @@ -29,11 +29,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("datetime")] [Constraint(Default = SystemMethods.CurrentDateTime)] - public DateTime Datetime { get; set; } + public DateTime? Datetime { get; set; } [Column("comment")] [Length(1000)] - public string Comment { get; set; } + public string? Comment { get; set; } [ResultColumn] [Column("parentObjectType")] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs index 89ef0039ab..b50d3ca3d2 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs @@ -25,10 +25,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("registeredDate")] [Constraint(Default = SystemMethods.CurrentDateTime)] - public DateTime DateRegistered { get; set; } + public DateTime? DateRegistered { get; set; } [Column("lastNotifiedDate")] - public DateTime DateAccessed { get; set; } + public DateTime? DateAccessed { get; set; } [Column("isActive")] [Index(IndexTypes.NonClustered)] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/TwoFactorLoginDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/TwoFactorLoginDto.cs index 1202fe2a19..09f6647bfe 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/TwoFactorLoginDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/TwoFactorLoginDto.cs @@ -22,12 +22,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("providerName")] [Length(400)] [NullSetting(NullSetting = NullSettings.NotNull)] - [Index(IndexTypes.UniqueNonClustered, ForColumns = "providerName,userOrMemberKey", Name = "IX_" + TableName + "_ProviderName")] - public string ProviderName { get; set; } + [Index(IndexTypes.UniqueNonClustered, ForColumns = "providerName,userOrMemberKey", + Name = "IX_" + TableName + "_ProviderName")] + public string ProviderName { get; set; } = null!; [Column("secret")] [Length(400)] [NullSetting(NullSetting = NullSettings.NotNull)] - public string Secret { get; set; } + public string Secret { get; set; } = null!; } } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/UserDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/UserDto.cs index 3c313794e0..d3e687aee5 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/UserDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/UserDto.cs @@ -34,7 +34,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos public bool NoConsole { get; set; } [Column("userName")] - public string? UserName { get; set; } + public string UserName { get; set; } = null!; [Column("userLogin")] [Length(125)] @@ -93,12 +93,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos [Column("createDate")] [NullSetting(NullSetting = NullSettings.NotNull)] [Constraint(Default = SystemMethods.CurrentDateTime)] - public DateTime CreateDate { get; set; } + public DateTime CreateDate { get; set; } = DateTime.Now; [Column("updateDate")] [NullSetting(NullSetting = NullSettings.NotNull)] [Constraint(Default = SystemMethods.CurrentDateTime)] - public DateTime UpdateDate { get; set; } + public DateTime UpdateDate { get; set; } = DateTime.Now; /// /// Will hold the media file system relative path of the users custom avatar if they uploaded one diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/ContentBaseFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/ContentBaseFactory.cs index fb3e866272..ea2c01ea92 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/ContentBaseFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/ContentBaseFactory.cs @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories /// /// Builds an IContent item from a dto and content type. /// - public static Content BuildEntity(DocumentDto dto, IContentType contentType) + public static Content BuildEntity(DocumentDto dto, IContentType? contentType) { var contentDto = dto.ContentDto; var nodeDto = contentDto.NodeDto; @@ -72,7 +72,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories /// /// Builds an IMedia item from a dto and content type. /// - public static Core.Models.Media BuildEntity(ContentDto dto, IMediaType contentType) + public static Core.Models.Media BuildEntity(ContentDto dto, IMediaType? contentType) { var nodeDto = dto.NodeDto; var contentVersionDto = dto.ContentVersionDto; @@ -113,7 +113,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories /// /// Builds an IMedia item from a dto and content type. /// - public static Member BuildEntity(MemberDto dto, IMemberType contentType) + public static Member BuildEntity(MemberDto dto, IMemberType? contentType) { var nodeDto = dto.ContentDto.NodeDto; var contentVersionDto = dto.ContentVersionDto; diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/PropertyFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/PropertyFactory.cs index f0f3249318..1b8708c640 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/PropertyFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/PropertyFactory.cs @@ -11,11 +11,15 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories { internal static class PropertyFactory { - public static IEnumerable BuildEntities(IPropertyType[] propertyTypes, IReadOnlyCollection dtos, int publishedVersionId, ILanguageRepository languageRepository) + public static IEnumerable BuildEntities(IPropertyType[]? propertyTypes, IReadOnlyCollection dtos, int publishedVersionId, ILanguageRepository languageRepository) { var properties = new List(); var xdtos = dtos.GroupBy(x => x.PropertyTypeId).ToDictionary(x => x.Key, x => (IEnumerable)x); + if (propertyTypes is null) + { + return properties; + } foreach (var propertyType in propertyTypes) { var values = new List(); diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/RelationFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/RelationFactory.cs index 63d3292160..dbe0c0af78 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/RelationFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/RelationFactory.cs @@ -5,7 +5,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories { internal static class RelationFactory { - public static IRelation BuildEntity(RelationDto dto, IRelationType relationType) + public static IRelation BuildEntity(RelationDto dto, IRelationType? relationType) { var entity = new Relation(dto.ParentId, dto.ChildId, dto.ParentObjectType, dto.ChildObjectType, relationType); diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/TemplateFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/TemplateFactory.cs index b50d013198..ba129257c7 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/TemplateFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/TemplateFactory.cs @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories #region Implementation of IEntityFactory - public static Template BuildEntity(IShortStringHelper shortStringHelper, TemplateDto dto, IEnumerable childDefinitions, Func getFileContent) + public static Template BuildEntity(IShortStringHelper shortStringHelper, TemplateDto dto, IEnumerable childDefinitions, Func getFileContent) { var template = new Template(shortStringHelper, dto.NodeDto.Text, dto.Alias, getFileContent); @@ -29,7 +29,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories template.IsMasterTemplate = childDefinitions.Any(x => x.ParentId == dto.NodeId); if (dto.NodeDto.ParentId > 0) - template.MasterTemplateId = new Lazy(() => dto.NodeDto.ParentId.Value); + template.MasterTemplateId = new Lazy(() => dto.NodeDto.ParentId); // reset dirty initial properties (U4-1946) template.ResetDirtyProperties(false); @@ -73,7 +73,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories NodeId = entity.Id, Level = 1, NodeObjectType = nodeObjectTypeId, - ParentId = entity.MasterTemplateId?.Value, + ParentId = entity.MasterTemplateId?.Value ?? 0, Path = entity.Path, Text = entity.Name, Trashed = false, diff --git a/src/Umbraco.Infrastructure/Persistence/FaultHandling/RetryDbConnection.cs b/src/Umbraco.Infrastructure/Persistence/FaultHandling/RetryDbConnection.cs index cfd078b81c..bd03c44c7a 100644 --- a/src/Umbraco.Infrastructure/Persistence/FaultHandling/RetryDbConnection.cs +++ b/src/Umbraco.Infrastructure/Persistence/FaultHandling/RetryDbConnection.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using System.Diagnostics.CodeAnalysis; using Transaction = System.Transactions.Transaction; namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling @@ -9,9 +10,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling { private DbConnection _inner; private readonly RetryPolicy _conRetryPolicy; - private readonly RetryPolicy _cmdRetryPolicy; + private readonly RetryPolicy? _cmdRetryPolicy; - public RetryDbConnection(DbConnection connection, RetryPolicy conRetryPolicy, RetryPolicy cmdRetryPolicy) + public RetryDbConnection(DbConnection connection, RetryPolicy? conRetryPolicy, RetryPolicy? cmdRetryPolicy) { _inner = connection; _inner.StateChange += StateChangeHandler; @@ -22,6 +23,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling public DbConnection Inner { get { return _inner; } } + [AllowNull] public override string ConnectionString { get { return _inner.ConnectionString; } set { _inner.ConnectionString = value; } } protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) @@ -71,11 +73,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling _inner.StateChange -= StateChangeHandler; _inner.Dispose(); } - _inner = null; base.Dispose(disposing); } - public override void EnlistTransaction(Transaction transaction) + public override void EnlistTransaction(Transaction? transaction) { _inner.EnlistTransaction(transaction); } @@ -90,7 +91,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling return _inner.GetSchema(collectionName); } - public override DataTable GetSchema(string collectionName, string[] restrictionValues) + public override DataTable GetSchema(string collectionName, string?[] restrictionValues) { return _inner.GetSchema(collectionName, restrictionValues); } @@ -130,7 +131,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling private DbCommand _inner; private readonly RetryPolicy _cmdRetryPolicy; - public FaultHandlingDbCommand(RetryDbConnection connection, DbCommand command, RetryPolicy cmdRetryPolicy) + public FaultHandlingDbCommand(RetryDbConnection connection, DbCommand command, RetryPolicy? cmdRetryPolicy) { _connection = connection; _inner = command; @@ -142,8 +143,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling protected override void Dispose(bool disposing) { if (disposing) - _inner?.Dispose(); - _inner = null; + _inner.Dispose(); + _inner = null!; base.Dispose(disposing); } @@ -152,6 +153,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling _inner.Cancel(); } + [AllowNull] public override string CommandText { get => _inner.CommandText; @@ -170,6 +172,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling set => _inner.CommandType = value; } + [AllowNull] protected override DbConnection DbConnection { get => _connection; @@ -190,7 +193,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling protected override DbParameterCollection DbParameterCollection => _inner.Parameters; - protected override DbTransaction DbTransaction + protected override DbTransaction? DbTransaction { get => _inner.Transaction; set => _inner.Transaction = value; @@ -208,7 +211,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling return Execute(() => _inner.ExecuteNonQuery()); } - public override object ExecuteScalar() + public override object? ExecuteScalar() { return Execute(() => _inner.ExecuteScalar()); } @@ -219,7 +222,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling { _connection.Ensure(); return f(); - }); + })!; } public override void Prepare() diff --git a/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs index 2de1bcef16..52daf7e351 100644 --- a/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs +++ b/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs @@ -6,7 +6,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence public interface IDbProviderFactoryCreator { - DbProviderFactory CreateFactory(string? providerName); + DbProviderFactory? CreateFactory(string? providerName); ISqlSyntaxProvider GetSqlSyntaxProvider(string providerName); IBulkSqlInsertProvider CreateBulkSqlInsertProvider(string providerName); void CreateDatabase(string providerName, string connectionString); diff --git a/src/Umbraco.Infrastructure/Persistence/ISqlContext.cs b/src/Umbraco.Infrastructure/Persistence/ISqlContext.cs index 8a6bfb8420..9178ba8ae7 100644 --- a/src/Umbraco.Infrastructure/Persistence/ISqlContext.cs +++ b/src/Umbraco.Infrastructure/Persistence/ISqlContext.cs @@ -48,6 +48,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// /// Gets the mappers. /// - IMapperCollection Mappers { get; } + IMapperCollection? Mappers { get; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/IUmbracoDatabaseFactory.cs b/src/Umbraco.Infrastructure/Persistence/IUmbracoDatabaseFactory.cs index a86deb8802..10af5a7421 100644 --- a/src/Umbraco.Infrastructure/Persistence/IUmbracoDatabaseFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/IUmbracoDatabaseFactory.cs @@ -14,7 +14,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// The new database must be disposed after being used. /// Creating a database causes the factory to initialize if it is not already initialized. /// - IUmbracoDatabase CreateDatabase(); + IUmbracoDatabase? CreateDatabase(); /// /// Gets a value indicating whether the database factory is configured, i.e. whether @@ -33,13 +33,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// Gets the connection string. /// /// May return null if the database factory is not configured. - string ConnectionString { get; } + string? ConnectionString { get; } /// /// Gets the provider name. /// /// May return null if the database factory is not configured. - string ProviderName { get; } + string? ProviderName { get; } /// /// Gets a value indicating whether the database factory is configured (see ), @@ -59,7 +59,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// /// Getting the causes the factory to initialize if it is not already initialized. /// - ISqlContext SqlContext { get; } + ISqlContext? SqlContext { get; } /// /// Gets the . @@ -67,7 +67,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// /// Getting the causes the factory to initialize if it is not already initialized. /// - IBulkSqlInsertProvider BulkSqlInsertProvider { get; } + IBulkSqlInsertProvider? BulkSqlInsertProvider { get; } /// /// Configures the database factory for upgrades. diff --git a/src/Umbraco.Infrastructure/Persistence/LocalDb.cs b/src/Umbraco.Infrastructure/Persistence/LocalDb.cs index fe616b56f6..709940f3cc 100644 --- a/src/Umbraco.Infrastructure/Persistence/LocalDb.cs +++ b/src/Umbraco.Infrastructure/Persistence/LocalDb.cs @@ -24,7 +24,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence { private int _version; private bool _hasVersion; - private string _exe; + private string? _exe; #region Availability & Version @@ -123,7 +123,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// /// The name of existing LocalDb instances. /// Thrown when LocalDb is not available. - public string[] GetInstances() + public string[]? GetInstances() { EnsureAvailable(); var rc = ExecuteSqlLocalDb("i", out var output, out var error); // info @@ -218,7 +218,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// The name of the instance. /// The instance with the specified name if it exists, otherwise null. /// Thrown when LocalDb is not available. - public Instance GetInstance(string instanceName) + public Instance? GetInstance(string instanceName) { EnsureAvailable(); return InstanceExists(instanceName) ? new Instance(instanceName) : null; @@ -500,7 +500,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// The name of the database. /// The directory containing the database files. /// Thrown when a database with the specified name does not exist. - public string DetachDatabase(string databaseName) + public string? DetachDatabase(string databaseName) { using (var conn = new SqlConnection(_masterCstr)) using (var cmd = conn.CreateCommand()) @@ -547,8 +547,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// The MDF filename. /// The LDF filename. public void GetFilenames(string databaseName, - out string mdfName, out string ldfName, - out string mdfFilename, out string ldfFilename) + out string? mdfName, out string? ldfName, + out string? mdfFilename, out string? ldfFilename) { using (var conn = new SqlConnection(_masterCstr)) using (var cmd = conn.CreateCommand()) @@ -587,13 +587,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// The Sql Command. /// The name of the database. /// The full filename of the MDF file, if the database exists, otherwise null. - private static string GetDatabase(SqlCommand cmd, string databaseName) + private static string? GetDatabase(SqlCommand cmd, string databaseName) { SetCommand(cmd, @" SELECT name, filename FROM master.dbo.sysdatabases WHERE ('[' + name + ']' = @0 OR name = @0)", databaseName); - string mdf = null; + string? mdf = null; using (var reader = cmd.ExecuteReader()) { if (reader.Read()) @@ -613,7 +613,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// The name of the database. /// The name of the database (MDF) file. /// The name of the log (LDF) file. - private static void ExecuteDropDatabase(SqlCommand cmd, string databaseName, string mdf, string ldf = null) + private static void ExecuteDropDatabase(SqlCommand cmd, string databaseName, string mdf, string? ldf = null) { try { @@ -736,8 +736,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// The MDF filename. /// The LDF filename. private void GetFilenames(SqlCommand cmd, string databaseName, - out string mdfName, out string ldfName, - out string mdfFilename, out string ldfFilename) + out string? mdfName, out string? ldfName, + out string? mdfFilename, out string? ldfFilename) { mdfName = ldfName = mdfFilename = ldfFilename = null; @@ -786,8 +786,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// Extensions are used eg to copy MyDatabase.mdf to MyDatabase.mdf.temp. /// public void CopyDatabaseFiles(string databaseName, string filesPath, - string targetDatabaseName = null, string targetFilesPath = null, - string sourceExtension = null, string targetExtension = null, + string? targetDatabaseName = null, string? targetFilesPath = null, + string? sourceExtension = null, string? targetExtension = null, bool overwrite = false, bool delete = false) { var nop = (targetFilesPath == null || targetFilesPath == filesPath) @@ -847,7 +847,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// /// Extensions are used eg to copy MyDatabase.mdf to MyDatabase.mdf.temp. /// - public bool DatabaseFilesExist(string databaseName, string filesPath, string extension = null) + public bool DatabaseFilesExist(string databaseName, string filesPath, string? extension = null) { GetDatabaseFiles(databaseName, filesPath, out _, out _, out _, out var mdfFilename, out var ldfFilename); diff --git a/src/Umbraco.Infrastructure/Persistence/Mappers/BaseMapper.cs b/src/Umbraco.Infrastructure/Persistence/Mappers/BaseMapper.cs index bc0deb56f1..f046ee9548 100644 --- a/src/Umbraco.Infrastructure/Persistence/Mappers/BaseMapper.cs +++ b/src/Umbraco.Infrastructure/Persistence/Mappers/BaseMapper.cs @@ -28,7 +28,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Mappers protected abstract void DefineMaps(); - internal string Map(string propertyName) + internal string Map(string? propertyName) { lock (_definedLock) { @@ -47,7 +47,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Mappers if (!_maps.TryGetValue(GetType(), out var mapperMaps)) throw new InvalidOperationException($"No maps defined for mapper {GetType().FullName}."); - if (!mapperMaps.TryGetValue(propertyName, out var mappedName)) + if (propertyName is null || !mapperMaps.TryGetValue(propertyName, out var mappedName)) throw new InvalidOperationException($"No map defined by mapper {GetType().FullName} for property {propertyName}."); return mappedName; } diff --git a/src/Umbraco.Infrastructure/Persistence/NPocoDatabaseExtensions.cs b/src/Umbraco.Infrastructure/Persistence/NPocoDatabaseExtensions.cs index 0159245bfd..7537ffc48f 100644 --- a/src/Umbraco.Infrastructure/Persistence/NPocoDatabaseExtensions.cs +++ b/src/Umbraco.Infrastructure/Persistence/NPocoDatabaseExtensions.cs @@ -31,7 +31,7 @@ namespace Umbraco.Extensions /// NPoco's normal Page returns a List{T} but sometimes we don't want all that in memory and instead want to /// iterate over each row with a reader using Query vs Fetch. /// - public static IEnumerable QueryPaged(this IDatabase database, long pageSize, Sql sql, Sql sqlCount) + public static IEnumerable QueryPaged(this IDatabase database, long pageSize, Sql sql, Sql? sqlCount) { var sqlString = sql.SQL; var sqlArgs = sql.Arguments; @@ -131,8 +131,8 @@ namespace Umbraco.Extensions /// public static RecordPersistenceType InsertOrUpdate(this IUmbracoDatabase db, T poco, - string updateCommand, - object updateArgs) + string? updateCommand, + object? updateArgs) where T : class { if (poco == null) @@ -142,9 +142,9 @@ namespace Umbraco.Extensions // in any case, no point trying to update if there's no primary key! // try to update - var rowCount = updateCommand.IsNullOrWhiteSpace() + var rowCount = updateCommand.IsNullOrWhiteSpace() || updateArgs is null ? db.Update(poco) - : db.Update(updateCommand, updateArgs); + : db.Update(updateCommand!, updateArgs); if (rowCount > 0) return RecordPersistenceType.Update; @@ -166,9 +166,9 @@ namespace Umbraco.Extensions // RC2 race cond here: another thread may remove the record // try to update - rowCount = updateCommand.IsNullOrWhiteSpace() + rowCount = updateCommand.IsNullOrWhiteSpace() || updateArgs is null ? db.Update(poco) - : db.Update(updateCommand, updateArgs); + : db.Update(updateCommand!, updateArgs); if (rowCount > 0) return RecordPersistenceType.Update; @@ -229,7 +229,7 @@ namespace Umbraco.Extensions /// /// /// - public static TTransaction GetTypedTransaction(IDbTransaction transaction) + public static TTransaction GetTypedTransaction(IDbTransaction? transaction) where TTransaction : class, IDbTransaction { var t = transaction; @@ -243,7 +243,7 @@ namespace Umbraco.Extensions t = profiled.WrappedTransaction; break; default: - throw new NotSupportedException(transaction.GetType().FullName); + throw new NotSupportedException(transaction?.GetType().FullName); } } } diff --git a/src/Umbraco.Infrastructure/Persistence/NPocoSqlExtensions.cs b/src/Umbraco.Infrastructure/Persistence/NPocoSqlExtensions.cs index 72b3f2cf5f..7c4498292b 100644 --- a/src/Umbraco.Infrastructure/Persistence/NPocoSqlExtensions.cs +++ b/src/Umbraco.Infrastructure/Persistence/NPocoSqlExtensions.cs @@ -55,7 +55,7 @@ namespace Umbraco.Extensions /// An expression specifying the field. /// The values. /// The Sql statement. - public static Sql WhereIn(this Sql sql, Expression> field, IEnumerable values) + public static Sql WhereIn(this Sql sql, Expression> field, IEnumerable? values) { var fieldName = sql.SqlContext.SqlSyntax.GetFieldName(field); sql.Where(fieldName + " IN (@values)", new { values }); @@ -70,7 +70,7 @@ namespace Umbraco.Extensions /// An expression specifying the field. /// A subquery returning the value. /// The Sql statement. - public static Sql WhereIn(this Sql sql, Expression> field, Sql values) + public static Sql WhereIn(this Sql sql, Expression> field, Sql? values) { return sql.WhereIn(field, values, false); } @@ -83,7 +83,7 @@ namespace Umbraco.Extensions /// An expression specifying the field. /// The values. /// The Sql statement. - public static Sql WhereNotIn(this Sql sql, Expression> field, IEnumerable values) + public static Sql WhereNotIn(this Sql sql, Expression> field, IEnumerable values) { var fieldName = sql.SqlContext.SqlSyntax.GetFieldName(field); sql.Where(fieldName + " NOT IN (@values)", new { values }); @@ -98,7 +98,7 @@ namespace Umbraco.Extensions /// An expression specifying the field. /// A subquery returning the value. /// The Sql statement. - public static Sql WhereNotIn(this Sql sql, Expression> field, Sql values) + public static Sql WhereNotIn(this Sql sql, Expression> field, Sql values) { return sql.WhereIn(field, values, true); } @@ -111,7 +111,7 @@ namespace Umbraco.Extensions /// Expressions specifying the fields. /// The values. /// The Sql statement. - public static Sql WhereAnyIn(this Sql sql, Expression>[] fields, IEnumerable values) + public static Sql WhereAnyIn(this Sql sql, Expression>[] fields, IEnumerable values) { var sqlSyntax = sql.SqlContext.SqlSyntax; var fieldNames = fields.Select(x => sqlSyntax.GetFieldName(x)).ToArray(); @@ -128,10 +128,10 @@ namespace Umbraco.Extensions return sql; } - private static Sql WhereIn(this Sql sql, Expression> fieldSelector, Sql valuesSql, bool not) + private static Sql WhereIn(this Sql sql, Expression> fieldSelector, Sql? valuesSql, bool not) { var fieldName = sql.SqlContext.SqlSyntax.GetFieldName(fieldSelector); - sql.Where(fieldName + (not ? " NOT" : "") +" IN (" + valuesSql.SQL + ")", valuesSql.Arguments); + sql.Where(fieldName + (not ? " NOT" : "") +" IN (" + valuesSql?.SQL + ")", valuesSql?.Arguments); return sql; } @@ -167,7 +167,7 @@ namespace Umbraco.Extensions /// Expression specifying the field. /// An optional alias for the table. /// The Sql statement. - public static Sql WhereNotNull(this Sql sql, Expression> field, string? tableAlias = null) + public static Sql WhereNotNull(this Sql sql, Expression> field, string? tableAlias = null) { return sql.WhereNull(field, tableAlias, true); } @@ -181,7 +181,7 @@ namespace Umbraco.Extensions /// An optional alias for the table. /// A value indicating whether to NOT NULL. /// The Sql statement. - public static Sql WhereNull(this Sql sql, Expression> field, string? tableAlias = null, bool not = false) + public static Sql WhereNull(this Sql sql, Expression> field, string? tableAlias = null, bool not = false) { var column = sql.GetColumns(columnExpressions: new[] { field }, tableAlias: tableAlias, withAlias: false).First(); return sql.Where("(" + column + " IS " + (not ? "NOT " : "") + "NULL)"); @@ -222,7 +222,7 @@ namespace Umbraco.Extensions /// The Sql statement. /// An expression specifying the field. /// The Sql statement. - public static Sql OrderBy(this Sql sql, Expression> field) + public static Sql OrderBy(this Sql sql, Expression> field) { return sql.OrderBy("(" + sql.SqlContext.SqlSyntax.GetFieldName(field) + ")"); } @@ -234,7 +234,7 @@ namespace Umbraco.Extensions /// The Sql statement. /// Expression specifying the fields. /// The Sql statement. - public static Sql OrderBy(this Sql sql, params Expression>[] fields) + public static Sql OrderBy(this Sql sql, params Expression>[] fields) { var sqlSyntax = sql.SqlContext.SqlSyntax; var columns = fields.Length == 0 @@ -250,7 +250,7 @@ namespace Umbraco.Extensions /// The Sql statement. /// An expression specifying the field. /// The Sql statement. - public static Sql OrderByDescending(this Sql sql, Expression> field) + public static Sql OrderByDescending(this Sql sql, Expression> field) { return sql.OrderBy("(" + sql.SqlContext.SqlSyntax.GetFieldName(field) + ") DESC"); } @@ -262,7 +262,7 @@ namespace Umbraco.Extensions /// The Sql statement. /// Expression specifying the fields. /// The Sql statement. - public static Sql OrderByDescending(this Sql sql, params Expression>[] fields) + public static Sql OrderByDescending(this Sql sql, params Expression>[] fields) { var sqlSyntax = sql.SqlContext.SqlSyntax; var columns = fields.Length == 0 @@ -277,7 +277,7 @@ namespace Umbraco.Extensions /// The Sql statement. /// Fields. /// The Sql statement. - public static Sql OrderByDescending(this Sql sql, params string[] fields) + public static Sql OrderByDescending(this Sql sql, params string?[] fields) { return sql.Append("ORDER BY " + string.Join(", ", fields.Select(x => x + " DESC"))); } @@ -289,7 +289,7 @@ namespace Umbraco.Extensions /// The Sql statement. /// An expression specifying the field. /// The Sql statement. - public static Sql GroupBy(this Sql sql, Expression> field) + public static Sql GroupBy(this Sql sql, Expression> field) { return sql.GroupBy(sql.SqlContext.SqlSyntax.GetFieldName(field)); } @@ -301,7 +301,7 @@ namespace Umbraco.Extensions /// The Sql statement. /// Expression specifying the fields. /// The Sql statement. - public static Sql GroupBy(this Sql sql, params Expression>[] fields) + public static Sql GroupBy(this Sql sql, params Expression>[] fields) { var sqlSyntax = sql.SqlContext.SqlSyntax; var columns = fields.Length == 0 @@ -317,7 +317,7 @@ namespace Umbraco.Extensions /// The Sql statement. /// Expressions specifying the fields. /// The Sql statement. - public static Sql AndBy(this Sql sql, params Expression>[] fields) + public static Sql AndBy(this Sql sql, params Expression>[] fields) { var sqlSyntax = sql.SqlContext.SqlSyntax; var columns = fields.Length == 0 @@ -333,7 +333,7 @@ namespace Umbraco.Extensions /// The Sql statement. /// Expressions specifying the fields. /// The Sql statement. - public static Sql AndByDescending(this Sql sql, params Expression>[] fields) + public static Sql AndByDescending(this Sql sql, params Expression>[] fields) { var sqlSyntax = sql.SqlContext.SqlSyntax; var columns = fields.Length == 0 @@ -448,7 +448,7 @@ namespace Umbraco.Extensions /// An expression specifying the right field. /// The Sql statement. public static Sql On(this Sql.SqlJoinClause sqlJoin, - Expression> leftField, Expression> rightField) + Expression> leftField, Expression> rightField) { // TODO: ugly - should define on SqlContext! @@ -563,7 +563,7 @@ namespace Umbraco.Extensions /// /// If is empty, all columns are counted. /// - public static Sql SelectCount(this Sql sql, params Expression>[] fields) + public static Sql SelectCount(this Sql sql, params Expression>[] fields) => sql.SelectCount(null, fields); /// @@ -577,7 +577,7 @@ namespace Umbraco.Extensions /// /// If is empty, all columns are counted. /// - public static Sql SelectCount(this Sql sql, string alias, params Expression>[] fields) + public static Sql SelectCount(this Sql sql, string? alias, params Expression>[] fields) { if (sql == null) throw new ArgumentNullException(nameof(sql)); var sqlSyntax = sql.SqlContext.SqlSyntax; @@ -610,7 +610,7 @@ namespace Umbraco.Extensions /// /// If is empty, all columns are selected. /// - public static Sql Select(this Sql sql, params Expression>[] fields) + public static Sql Select(this Sql sql, params Expression>[] fields) { if (sql == null) throw new ArgumentNullException(nameof(sql)); return sql.Select(sql.GetColumns(columnExpressions: fields)); @@ -626,7 +626,7 @@ namespace Umbraco.Extensions /// /// If is empty, all columns are selected. /// - public static Sql SelectDistinct(this Sql sql, params Expression>[] fields) + public static Sql SelectDistinct(this Sql sql, params Expression>[] fields) { if (sql == null) throw new ArgumentNullException(nameof(sql)); var columns = sql.GetColumns(columnExpressions: fields); @@ -647,7 +647,7 @@ namespace Umbraco.Extensions /// /// If is empty, all columns are selected. /// - public static Sql Select(this Sql sql, string tableAlias, params Expression>[] fields) + public static Sql Select(this Sql sql, string tableAlias, params Expression>[] fields) { if (sql == null) throw new ArgumentNullException(nameof(sql)); return sql.Select(sql.GetColumns(tableAlias: tableAlias, columnExpressions: fields)); @@ -675,7 +675,7 @@ namespace Umbraco.Extensions /// /// If is empty, all columns are selected. /// - public static Sql AndSelect(this Sql sql, params Expression>[] fields) + public static Sql AndSelect(this Sql sql, params Expression>[] fields) { if (sql == null) throw new ArgumentNullException(nameof(sql)); return sql.Append(", " + string.Join(", ", sql.GetColumns(columnExpressions: fields))); @@ -692,7 +692,7 @@ namespace Umbraco.Extensions /// /// If is empty, all columns are selected. /// - public static Sql AndSelect(this Sql sql, string tableAlias, params Expression>[] fields) + public static Sql AndSelect(this Sql sql, string tableAlias, params Expression>[] fields) { if (sql == null) throw new ArgumentNullException(nameof(sql)); return sql.Append(", " + string.Join(", ", sql.GetColumns(tableAlias: tableAlias, columnExpressions: fields))); @@ -722,7 +722,7 @@ namespace Umbraco.Extensions /// /// If is empty, all columns are counted. /// - public static Sql AndSelectCount(this Sql sql, params Expression>[] fields) + public static Sql AndSelectCount(this Sql sql, params Expression>[] fields) => sql.AndSelectCount(null, fields); /// @@ -736,7 +736,7 @@ namespace Umbraco.Extensions /// /// If is empty, all columns are counted. /// - public static Sql AndSelectCount(this Sql sql, string? alias = null, params Expression>[] fields) + public static Sql AndSelectCount(this Sql sql, string? alias = null, params Expression>[] fields) { if (sql == null) throw new ArgumentNullException(nameof(sql)); var sqlSyntax = sql.SqlContext.SqlSyntax; @@ -798,7 +798,7 @@ namespace Umbraco.Extensions /// /// The original Sql expression. /// The current Dtos prefix. - public SqlRef(Sql sql, string prefix) + public SqlRef(Sql sql, string? prefix) { Sql = sql; Prefix = prefix; @@ -812,7 +812,7 @@ namespace Umbraco.Extensions /// /// Gets the current Dtos prefix. /// - public string Prefix { get; } + public string? Prefix { get; } /// /// Appends fields for a referenced Dto. @@ -832,7 +832,7 @@ namespace Umbraco.Extensions /// The referenced Dto table alias. /// An optional expression representing a nested reference selection. /// A SqlRef statement. - public SqlRef Select(Expression> field, string tableAlias, Func, SqlRef>? reference = null) + public SqlRef Select(Expression> field, string? tableAlias, Func, SqlRef>? reference = null) { var property = field == null ? null : ExpressionHelper.FindProperty(field).Item1 as PropertyInfo; return Select(property, tableAlias, reference); @@ -862,13 +862,13 @@ namespace Umbraco.Extensions /// /// The referencing property has to be a List{}. /// - public SqlRef Select(Expression>> field, string tableAlias, Func, SqlRef>? reference = null) + public SqlRef Select(Expression>> field, string? tableAlias, Func, SqlRef>? reference = null) { var property = field == null ? null : ExpressionHelper.FindProperty(field).Item1 as PropertyInfo; return Select(property, tableAlias, reference); } - private SqlRef Select(PropertyInfo propertyInfo, string tableAlias, Func, SqlRef>? nested = null) + private SqlRef Select(PropertyInfo? propertyInfo, string? tableAlias, Func, SqlRef>? nested = null) { var referenceName = propertyInfo?.Name ?? typeof (TDto).Name; if (Prefix != null) referenceName = Prefix + PocoData.Separator + referenceName; @@ -891,7 +891,7 @@ namespace Umbraco.Extensions /// /// If is empty, all fields are selected. /// - public static string Columns(this Sql sql, params Expression>[] fields) + public static string Columns(this Sql sql, params Expression>[] fields) { if (sql == null) throw new ArgumentNullException(nameof(sql)); return string.Join(", ", sql.GetColumns(columnExpressions: fields, withAlias: false)); @@ -908,7 +908,7 @@ namespace Umbraco.Extensions /// /// If is empty, all fields are selected. /// - public static string Columns(this Sql sql, string alias, params Expression>[] fields) + public static string Columns(this Sql sql, string alias, params Expression>[] fields) { if (sql == null) throw new ArgumentNullException(nameof(sql)); return string.Join(", ", sql.GetColumns(columnExpressions: fields, withAlias: false, tableAlias: alias)); @@ -989,21 +989,21 @@ namespace Umbraco.Extensions public class SqlUpd { private readonly ISqlContext _sqlContext; - private readonly List> _setExpressions = new List>(); + private readonly List> _setExpressions = new List>(); public SqlUpd(ISqlContext sqlContext) { _sqlContext = sqlContext; } - public SqlUpd Set(Expression> fieldSelector, object value) + public SqlUpd Set(Expression> fieldSelector, object? value) { var fieldName = _sqlContext.SqlSyntax.GetFieldName(fieldSelector); - _setExpressions.Add(new Tuple(fieldName, value)); + _setExpressions.Add(new Tuple(fieldName, value)); return this; } - public List> SetExpressions => _setExpressions; + public List> SetExpressions => _setExpressions; } #endregion @@ -1045,7 +1045,7 @@ namespace Umbraco.Extensions #region Sql Inspection - private static SqlInspectionUtilities _sqlInspector; + private static SqlInspectionUtilities? _sqlInspector; private static SqlInspectionUtilities SqlInspector => _sqlInspector ?? (_sqlInspector = new SqlInspectionUtilities()); @@ -1054,13 +1054,13 @@ namespace Umbraco.Extensions private readonly Func _getSqlText; private readonly Action _setSqlText; private readonly Func _getSqlRhs; - private readonly Action _setSqlFinal; + private readonly Action _setSqlFinal; public SqlInspectionUtilities() { (_getSqlText, _setSqlText) = ReflectionUtilities.EmitFieldGetterAndSetter("_sql"); _getSqlRhs = ReflectionUtilities.EmitFieldGetter("_rhs"); - _setSqlFinal = ReflectionUtilities.EmitFieldSetter("_sqlFinal"); + _setSqlFinal = ReflectionUtilities.EmitFieldSetter("_sqlFinal"); } public string GetSqlText(Sql sql) => _getSqlText(sql); @@ -1095,7 +1095,7 @@ namespace Umbraco.Extensions #region Utilities - private static string[] GetColumns(this Sql sql, string? tableAlias = null, string? referenceName = null, Expression>[]? columnExpressions = null, bool withAlias = true) + private static string[] GetColumns(this Sql sql, string? tableAlias = null, string? referenceName = null, Expression>[]? columnExpressions = null, bool withAlias = true) { var pd = sql.SqlContext.PocoDataFactory.ForType(typeof (TDto)); var tableName = tableAlias ?? pd.TableInfo.TableName; @@ -1126,7 +1126,7 @@ namespace Umbraco.Extensions queryColumns.Sort((a, b) => names.IndexOf(a.Key).CompareTo(names.IndexOf(b.Key))); } - string GetAlias(PocoColumn column) + string? GetAlias(PocoColumn column) { if (aliases != null && aliases.TryGetValue(column.ColumnName, out var alias)) return alias; @@ -1139,7 +1139,7 @@ namespace Umbraco.Extensions .ToArray(); } - private static string GetColumn(DatabaseType dbType, string tableName, string columnName, string columnAlias, string? referenceName = null) + private static string GetColumn(DatabaseType dbType, string tableName, string columnName, string? columnAlias, string? referenceName = null) { tableName = dbType.EscapeTableName(tableName); columnName = dbType.EscapeSqlIdentifier(columnName); @@ -1179,7 +1179,7 @@ namespace Umbraco.Extensions ToText(sql.SQL, sql.Arguments, text); } - public static void ToText(string sql, object[] arguments, StringBuilder text) + public static void ToText(string? sql, object[]? arguments, StringBuilder text) { text.AppendLine(sql); diff --git a/src/Umbraco.Infrastructure/Persistence/PocoDataDataReader.cs b/src/Umbraco.Infrastructure/Persistence/PocoDataDataReader.cs index c3875d3770..17dc7937a6 100644 --- a/src/Umbraco.Infrastructure/Persistence/PocoDataDataReader.cs +++ b/src/Umbraco.Infrastructure/Persistence/PocoDataDataReader.cs @@ -115,7 +115,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// public override object GetValue(int i) { - return _enumerator.Current == null ? null : _readerColumns[i].GetValue(_enumerator.Current); + return _enumerator.Current == null ? null! : _readerColumns[i].GetValue(_enumerator.Current); } /// diff --git a/src/Umbraco.Infrastructure/Persistence/Querying/ExpressionVisitorBase.cs b/src/Umbraco.Infrastructure/Persistence/Querying/ExpressionVisitorBase.cs index d6584ed01d..3eb7c5d58b 100644 --- a/src/Umbraco.Infrastructure/Persistence/Querying/ExpressionVisitorBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Querying/ExpressionVisitorBase.cs @@ -160,11 +160,15 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying return Visited ? string.Empty : $"{result} = @{SqlParameters.Count - 1}"; } - return Visit(lambda.Body); + return Visit(lambda?.Body); } protected virtual string VisitBinary(BinaryExpression? b) { + if (b is null) + { + return string.Empty; + } var left = string.Empty; var right = string.Empty; @@ -251,9 +255,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying } } - protected virtual List VisitExpressionList(ReadOnlyCollection original) + protected virtual List VisitExpressionList(ReadOnlyCollection? original) { var list = new List(); + if (original is null) + { + return list; + } for (int i = 0, n = original.Count; i < n; i++) { if (original[i].NodeType == ExpressionType.NewArrayInit || @@ -269,8 +277,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying return list; } - protected virtual string VisitNew(NewExpression newExpression) + protected virtual string VisitNew(NewExpression? newExpression) { + if (newExpression is null) + { + return string.Empty; + } // TODO: check ! var member = Expression.Convert(newExpression, typeof(object)); var lambda = Expression.Lambda>(member); @@ -293,9 +305,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying } } - protected virtual string? VisitParameter(ParameterExpression p) + protected virtual string VisitParameter(ParameterExpression? p) { - return p.Name; + return p?.Name ?? string.Empty; } protected virtual string VisitConstant(ConstantExpression? c) @@ -308,14 +320,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying return Visited ? string.Empty : $"@{SqlParameters.Count - 1}"; } - protected virtual string VisitUnary(UnaryExpression u) + protected virtual string VisitUnary(UnaryExpression? u) { - switch (u.NodeType) + switch (u?.NodeType) { case ExpressionType.Not: return VisitNot(u.Operand); default: - return Visit(u.Operand); + return Visit(u?.Operand); } } @@ -357,14 +369,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying } } - protected virtual string VisitNewArray(NewArrayExpression na) + protected virtual string VisitNewArray(NewArrayExpression? na) { + if (na is null) + { + return string.Empty; + } var exprs = VisitExpressionList(na.Expressions); return Visited ? string.Empty : string.Join(",", exprs); } - protected virtual List VisitNewArrayFromExpressionList(NewArrayExpression na) - => VisitExpressionList(na.Expressions); + protected virtual List VisitNewArrayFromExpressionList(NewArrayExpression? na) + => VisitExpressionList(na?.Expressions); protected virtual string BindOperant(ExpressionType e) { @@ -403,8 +419,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying } } - protected virtual string VisitMethodCall(MethodCallExpression m) + protected virtual string VisitMethodCall(MethodCallExpression? m) { + if (m is null) + { + return string.Empty; + } // m.Object is the expression that represent the instance for instance method class, or null for static method calls // m.Arguments is the collection of expressions that represent arguments of the called method // m.MethodInfo is the method info for the method to be called @@ -548,8 +568,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying throw new NotSupportedException("An array Contains method is not supported"); } - SqlParameters.Add(RemoveQuote(searchValue)); - SqlParameters.Add(RemoveQuote(replaceValue)); + SqlParameters.Add(RemoveQuote(searchValue)!); + SqlParameters.Add(RemoveQuote(replaceValue)!); //don't execute if compiled return Visited ? string.Empty : $"replace({visitedMethodObject}, @{SqlParameters.Count - 2}, @{SqlParameters.Count - 1})"; @@ -703,13 +723,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying switch (verb) { case nameof(SqlExpressionExtensions.SqlWildcard): - SqlParameters.Add(RemoveQuote(val)); + SqlParameters.Add(RemoveQuote(val)!); return Visited ? string.Empty : SqlSyntax.GetStringColumnWildcardComparison(col, SqlParameters.Count - 1, columnType); case "Equals": case nameof(StringExtensions.InvariantEquals): case nameof(SqlExpressionExtensions.SqlEquals): - SqlParameters.Add(RemoveQuote(val)); + SqlParameters.Add(RemoveQuote(val)!); return Visited ? string.Empty : SqlSyntax.GetStringColumnEqualComparison(col, SqlParameters.Count - 1, columnType); case "StartsWith": @@ -740,14 +760,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying { return paramValue == null ? string.Empty - : sqlSyntax.EscapeString(paramValue.ToString()); + : sqlSyntax.EscapeString(paramValue.ToString()!); } - protected virtual string RemoveQuote(string exp) + protected virtual string? RemoveQuote(string? exp) { if (exp.IsNullOrWhiteSpace()) return exp; - var c = exp[0]; + var c = exp![0]; return (c == '"' || c == '`' || c == '\'') && exp[exp.Length - 1] == c ? exp.Length == 1 ? string.Empty diff --git a/src/Umbraco.Infrastructure/Persistence/Querying/ModelToSqlExpressionVisitor.cs b/src/Umbraco.Infrastructure/Persistence/Querying/ModelToSqlExpressionVisitor.cs index 5b83c1915f..afe00a7fe9 100644 --- a/src/Umbraco.Infrastructure/Persistence/Querying/ModelToSqlExpressionVisitor.cs +++ b/src/Umbraco.Infrastructure/Persistence/Querying/ModelToSqlExpressionVisitor.cs @@ -13,18 +13,22 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying /// This object is stateful and cannot be re-used to parse an expression. internal class ModelToSqlExpressionVisitor : ExpressionVisitorBase { - private readonly IMapperCollection _mappers; - private readonly BaseMapper _mapper; + private readonly IMapperCollection? _mappers; + private readonly BaseMapper? _mapper; - public ModelToSqlExpressionVisitor(ISqlSyntaxProvider sqlSyntax, IMapperCollection mappers) + public ModelToSqlExpressionVisitor(ISqlSyntaxProvider sqlSyntax, IMapperCollection? mappers) : base(sqlSyntax) { _mappers = mappers; - _mapper = mappers[typeof(T)]; // throws if not found + _mapper = mappers?[typeof(T)]; // throws if not found } - protected override string VisitMemberAccess(MemberExpression m) + protected override string VisitMemberAccess(MemberExpression? m) { + if (m is null) + { + return string.Empty; + } if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter && m.Expression.Type == typeof(T)) @@ -32,10 +36,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying //don't execute if compiled if (Visited == false) { - var field = _mapper.Map(m.Member.Name); + var field = _mapper?.Map(m.Member.Name); if (field.IsNullOrWhiteSpace()) throw new InvalidOperationException($"The mapper returned an empty field for the member name: {m.Member.Name} for type: {m.Expression.Type}."); - return field; + return field!; } //already compiled, return @@ -47,10 +51,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying //don't execute if compiled if (Visited == false) { - var field = _mapper.Map(m.Member.Name); + var field = _mapper?.Map(m.Member.Name); if (field.IsNullOrWhiteSpace()) throw new InvalidOperationException($"The mapper returned an empty field for the member name: {m.Member.Name} for type: {m.Expression.Type}."); - return field; + return field!; } //already compiled, return @@ -60,6 +64,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying if (m.Expression != null && m.Expression.Type != typeof(T) && EndsWithConstant(m) == false + && _mappers is not null && _mappers.TryGetMapper(m.Expression.Type, out var subMapper)) { //if this is the case, it means we have a sub expression / nested property access, such as: x.ContentType.Alias == "Test"; @@ -116,12 +121,16 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying /// private static bool EndsWithConstant(MemberExpression m) { - Expression expr = m; + Expression? expr = m; while (expr is MemberExpression) { var memberExpr = expr as MemberExpression; - expr = memberExpr.Expression; + if (memberExpr is not null) + { + expr = memberExpr.Expression; + } + } var constExpr = expr as ConstantExpression; diff --git a/src/Umbraco.Infrastructure/Persistence/Querying/PocoToSqlExpressionVisitor.cs b/src/Umbraco.Infrastructure/Persistence/Querying/PocoToSqlExpressionVisitor.cs index dacc82983c..87d758ebda 100644 --- a/src/Umbraco.Infrastructure/Persistence/Querying/PocoToSqlExpressionVisitor.cs +++ b/src/Umbraco.Infrastructure/Persistence/Querying/PocoToSqlExpressionVisitor.cs @@ -22,8 +22,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying _alias = alias; } - protected override string VisitMethodCall(MethodCallExpression m) + protected override string VisitMethodCall(MethodCallExpression? m) { + if (m is null) + { + return string.Empty; + } var declaring = m.Method.DeclaringType; if (declaring != typeof (SqlTemplate)) return base.VisitMethodCall(m); @@ -36,7 +40,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying throw new NotSupportedException($"Method SqlTemplate.{m.Method.Name}({string.Join(", ", parameters.Select(x => x.ParameterType))} is not supported."); var arg = m.Arguments[0]; - string name; + string? name; if (arg.NodeType == ExpressionType.Constant) { name = arg.ToString(); @@ -57,8 +61,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying : $"@{SqlParameters.Count - 1}"; } - protected override string VisitMemberAccess(MemberExpression m) + protected override string VisitMemberAccess(MemberExpression? m) { + if (m is null) + { + return string.Empty; + } if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter && m.Expression.Type == typeof(TDto)) { return Visited ? string.Empty : GetFieldName(_pd, m.Member.Name, _alias); @@ -79,7 +87,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying return Visited ? string.Empty : "@" + (SqlParameters.Count - 1); } - protected virtual string GetFieldName(PocoData pocoData, string name, string alias) + protected virtual string GetFieldName(PocoData pocoData, string name, string? alias) { var column = pocoData.Columns.FirstOrDefault(x => x.Value.MemberInfoData.Name == name); var tableName = SqlSyntax.GetQuotedTableName(alias ?? pocoData.TableInfo.TableName); @@ -99,7 +107,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying { private readonly PocoData _pocoData1, _pocoData2; private readonly string? _alias1, _alias2; - private string _parameterName1, _parameterName2; + private string? _parameterName1, _parameterName2; public PocoToSqlExpressionVisitor(ISqlContext sqlContext, string? alias1, string? alias2) : base(sqlContext.SqlSyntax) @@ -110,8 +118,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying _alias2 = alias2; } - protected override string VisitLambda(LambdaExpression lambda) + protected override string VisitLambda(LambdaExpression? lambda) { + if (lambda is null) + { + return string.Empty; + } if (lambda.Parameters.Count == 2) { _parameterName1 = lambda.Parameters[0].Name; @@ -124,8 +136,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying return base.VisitLambda(lambda); } - protected override string VisitMemberAccess(MemberExpression m) + protected override string VisitMemberAccess(MemberExpression? m) { + if (m is null) + { + return string.Empty; + } if (m.Expression != null) { if (m.Expression.NodeType == ExpressionType.Parameter) @@ -157,7 +173,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying return Visited ? string.Empty : "@" + (SqlParameters.Count - 1); } - protected virtual string GetFieldName(PocoData pocoData, string name, string alias) + protected virtual string GetFieldName(PocoData pocoData, string name, string? alias) { var column = pocoData.Columns.FirstOrDefault(x => x.Value.MemberInfoData.Name == name); var tableName = SqlSyntax.GetQuotedTableName(alias ?? pocoData.TableInfo.TableName); @@ -177,10 +193,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying internal class PocoToSqlExpressionVisitor : ExpressionVisitorBase { private readonly PocoData _pocoData1, _pocoData2, _pocoData3; - private readonly string _alias1, _alias2, _alias3; - private string _parameterName1, _parameterName2, _parameterName3; + private readonly string? _alias1, _alias2, _alias3; + private string? _parameterName1, _parameterName2, _parameterName3; - public PocoToSqlExpressionVisitor(ISqlContext sqlContext, string alias1, string alias2, string alias3) + public PocoToSqlExpressionVisitor(ISqlContext sqlContext, string? alias1, string? alias2, string? alias3) : base(sqlContext.SqlSyntax) { _pocoData1 = sqlContext.PocoDataFactory.ForType(typeof(TDto1)); @@ -191,8 +207,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying _alias3 = alias3; } - protected override string VisitLambda(LambdaExpression lambda) + protected override string VisitLambda(LambdaExpression? lambda) { + if (lambda is null) + { + return string.Empty; + } if (lambda.Parameters.Count == 3) { _parameterName1 = lambda.Parameters[0].Name; @@ -211,8 +231,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying return base.VisitLambda(lambda); } - protected override string VisitMemberAccess(MemberExpression m) + protected override string VisitMemberAccess(MemberExpression? m) { + if (m is null) + { + return string.Empty; + } if (m.Expression != null) { if (m.Expression.NodeType == ExpressionType.Parameter) @@ -247,7 +271,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying return Visited ? string.Empty : "@" + (SqlParameters.Count - 1); } - protected virtual string GetFieldName(PocoData pocoData, string name, string alias) + protected virtual string GetFieldName(PocoData pocoData, string name, string? alias) { var column = pocoData.Columns.FirstOrDefault(x => x.Value.MemberInfoData.Name == name); var tableName = SqlSyntax.GetQuotedTableName(alias ?? pocoData.TableInfo.TableName); diff --git a/src/Umbraco.Infrastructure/Persistence/Querying/Query.cs b/src/Umbraco.Infrastructure/Persistence/Querying/Query.cs index 8089b21cc1..f4535f9734 100644 --- a/src/Umbraco.Infrastructure/Persistence/Querying/Query.cs +++ b/src/Umbraco.Infrastructure/Persistence/Querying/Query.cs @@ -38,7 +38,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying /// /// Adds a where-in clause to the query. /// - public virtual IQuery WhereIn(Expression> fieldSelector, IEnumerable values) + public virtual IQuery WhereIn(Expression> fieldSelector, IEnumerable? values) { if (fieldSelector == null) return this; @@ -55,9 +55,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying { if (predicates == null) return this; - StringBuilder sb = null; - List parameters = null; - Sql sql = null; + StringBuilder? sb = null; + List? parameters = null; + Sql? sql = null; foreach (var predicate in predicates) { // see notes in Where() @@ -73,18 +73,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying else { sb.Append(" OR "); - sql.Append(" OR "); + sql?.Append(" OR "); } sb.Append(whereExpression); - parameters.AddRange(expressionHelper.GetSqlParameters()); - sql.Append(whereExpression, expressionHelper.GetSqlParameters()); + parameters?.AddRange(expressionHelper.GetSqlParameters()); + sql?.Append(whereExpression, expressionHelper.GetSqlParameters()); } if (sb == null) return this; sb.Append(")"); - _wheres.Add(Tuple.Create("(" + sql.SQL + ")", sql.Arguments)); + _wheres.Add(Tuple.Create("(" + sql?.SQL + ")", sql?.Arguments)!); return this; } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/IEntityRepositoryExtended.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/IEntityRepositoryExtended.cs index 7e1b2ad0df..ac07cd19dd 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/IEntityRepositoryExtended.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/IEntityRepositoryExtended.cs @@ -29,6 +29,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories /// IEnumerable GetPagedResultsByQuery( IQuery query, Guid[] objectTypes, long pageIndex, int pageSize, out long totalRecords, - IQuery filter, Ordering ordering, Action> sqlCustomization = null); + IQuery? filter, Ordering? ordering, Action>? sqlCustomization = null); } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs index 9cadc82e49..b94f99723a 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs @@ -51,7 +51,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } /// - protected override IAuditEntry PerformGet(int id) + protected override IAuditEntry? PerformGet(int id) { Sql sql = Sql() .Select() @@ -63,9 +63,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } /// - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { - if (ids.Length == 0) + if (ids?.Length == 0) { Sql sql = Sql() .Select() diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs index 644dc4bc26..cc5f08d58b 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs @@ -50,7 +50,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement }); } - protected override IAuditItem PerformGet(int id) + protected override IAuditItem? PerformGet(int id) { var sql = GetBaseQuery(false); sql.Where(GetBaseWhereClause(), new { Id = id }); @@ -61,7 +61,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement : new AuditItem(dto.NodeId, Enum.Parse(dto.Header), dto.UserId ?? Cms.Core.Constants.Security.UnknownUserId, dto.EntityType, dto.Comment, dto.Parameters); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { throw new NotImplementedException(); } @@ -146,8 +146,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// public IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, Direction orderDirection, - AuditType[] auditTypeFilter, - IQuery customFilter) + AuditType[]? auditTypeFilter, + IQuery? customFilter) { if (auditTypeFilter == null) auditTypeFilter = Array.Empty(); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/CacheInstructionRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/CacheInstructionRepository.cs index 3ce9aad530..6337ef1977 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/CacheInstructionRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/CacheInstructionRepository.cs @@ -21,53 +21,53 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement public CacheInstructionRepository(IScopeAccessor scopeAccessor) => _scopeAccessor = scopeAccessor; /// - private IDatabaseScope AmbientScope => _scopeAccessor.AmbientScope; + private IDatabaseScope? AmbientScope => _scopeAccessor.AmbientScope; /// public int CountAll() { - Sql sql = AmbientScope.SqlContext.Sql().Select("COUNT(*)") + Sql? sql = AmbientScope?.SqlContext.Sql().Select("COUNT(*)") .From(); - return AmbientScope.Database.ExecuteScalar(sql); + return AmbientScope?.Database.ExecuteScalar(sql) ?? 0; } /// public int CountPendingInstructions(int lastId) => - AmbientScope.Database.ExecuteScalar("SELECT SUM(instructionCount) FROM umbracoCacheInstruction WHERE id > @lastId", new { lastId }); + AmbientScope?.Database.ExecuteScalar("SELECT SUM(instructionCount) FROM umbracoCacheInstruction WHERE id > @lastId", new { lastId }) ?? 0; /// public int GetMaxId() => - AmbientScope.Database.ExecuteScalar("SELECT MAX(id) FROM umbracoCacheInstruction"); + AmbientScope?.Database.ExecuteScalar("SELECT MAX(id) FROM umbracoCacheInstruction") ?? 0; /// - public bool Exists(int id) => AmbientScope.Database.Exists(id); + public bool Exists(int id) => AmbientScope?.Database.Exists(id) ?? false; /// public void Add(CacheInstruction cacheInstruction) { CacheInstructionDto dto = CacheInstructionFactory.BuildDto(cacheInstruction); - AmbientScope.Database.Insert(dto); + AmbientScope?.Database.Insert(dto); } /// public IEnumerable GetPendingInstructions(int lastId, int maxNumberToRetrieve) { - Sql sql = AmbientScope.SqlContext.Sql().SelectAll() + Sql? sql = AmbientScope?.SqlContext.Sql().SelectAll() .From() .Where(dto => dto.Id > lastId) .OrderBy(dto => dto.Id); - Sql topSql = sql.SelectTop(maxNumberToRetrieve); - return AmbientScope.Database.Fetch(topSql).Select(CacheInstructionFactory.BuildEntity); + Sql? topSql = sql?.SelectTop(maxNumberToRetrieve); + return AmbientScope?.Database.Fetch(topSql).Select(CacheInstructionFactory.BuildEntity) ?? Array.Empty(); } /// public void DeleteInstructionsOlderThan(DateTime pruneDate) { // Using 2 queries is faster than convoluted joins. - var maxId = AmbientScope.Database.ExecuteScalar("SELECT MAX(id) FROM umbracoCacheInstruction;"); + var maxId = AmbientScope?.Database.ExecuteScalar("SELECT MAX(id) FROM umbracoCacheInstruction;"); Sql deleteSql = new Sql().Append(@"DELETE FROM umbracoCacheInstruction WHERE utcStamp < @pruneDate AND id < @maxId", new { pruneDate, maxId }); - AmbientScope.Database.Execute(deleteSql); + AmbientScope?.Database.Execute(deleteSql); } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs index 194369285b..057fb7e01c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs @@ -33,7 +33,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } /// - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { throw new NotSupportedException(); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs index 0b4af6bdee..f86b9b7a41 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs @@ -90,7 +90,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Versions // gets a specific version - public abstract TEntity GetVersion(int versionId); + public abstract TEntity? GetVersion(int versionId); // gets all versions, current first public abstract IEnumerable GetAllVersions(int nodeId); @@ -158,7 +158,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Count descendants of an item. /// - public int CountDescendants(int parentId, string contentTypeAlias = null) + public int CountDescendants(int parentId, string? contentTypeAlias = null) { var pathMatch = parentId == -1 ? "-1," @@ -192,7 +192,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Count children of an item. /// - public int CountChildren(int parentId, string contentTypeAlias = null) + public int CountChildren(int parentId, string? contentTypeAlias = null) { var sql = SqlContext.Sql() .SelectCount() @@ -222,7 +222,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Count items. /// - public int Count(string contentTypeAlias = null) + public int Count(string? contentTypeAlias = null) { var sql = SqlContext.Sql() .SelectCount() @@ -293,7 +293,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #endregion - private Sql PreparePageSql(Sql sql, Sql filterSql, Ordering ordering) + private Sql PreparePageSql(Sql sql, Sql? filterSql, Ordering ordering) { // non-filtering, non-ordering = nothing to do if (filterSql == null && ordering.IsEmpty) return sql; @@ -412,7 +412,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // no culture = can only work on the invariant name // see notes in ApplyOrdering: the field MUST be aliased if (ordering.Culture.IsNullOrWhiteSpace()) - return GetAliasedField(SqlSyntax.GetFieldName(x => x.Text), sql); + return GetAliasedField(SqlSyntax.GetFieldName(x => x.Text!), sql); // "variantName" alias is defined in DocumentRepository.GetBaseQuery // TODO: what if it is NOT a document but a ... media or whatever? @@ -428,7 +428,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .InnerJoin("ctype").On((content, contentType) => content.ContentTypeId == contentType.NodeId, aliasRight: "ctype"); // see notes in ApplyOrdering: the field MUST be selected + aliased - sql = Sql(InsertBefore(sql, "FROM", ", " + SqlSyntax.GetFieldName(x => x.Alias, "ctype") + " AS ordering "), sql.Arguments); + sql = Sql(InsertBefore(sql, "FROM", ", " + SqlSyntax.GetFieldName(x => x.Alias!, "ctype") + " AS ordering "), sql.Arguments); sql = InsertJoins(sql, joins); @@ -491,10 +491,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // would ensure that items without a value always come last, both in ASC and DESC-ending sorts } - public abstract IEnumerable GetPage(IQuery query, + public abstract IEnumerable GetPage(IQuery? query, long pageIndex, int pageSize, out long totalRecords, - IQuery filter, - Ordering ordering); + IQuery? filter, + Ordering? ordering); public ContentDataIntegrityReport CheckDataIntegrity(ContentDataIntegrityReportOptions options) { @@ -614,11 +614,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } // here, filter can be null and ordering cannot - protected IEnumerable GetPage(IQuery query, + protected IEnumerable GetPage(IQuery? query, long pageIndex, int pageSize, out long totalRecords, Func, IEnumerable> mapDtos, - Sql filter, - Ordering ordering) + Sql? filter, + Ordering? ordering) { if (ordering == null) throw new ArgumentNullException(nameof(ordering)); @@ -708,6 +708,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { // compositionProperties is the property types for the entire composition // use an index for perfs + if (temp.ContentType is null) + { + continue; + } if (compositionPropertiesIndex.TryGetValue(temp.ContentType.Id, out var compositionProperties) == false) compositionPropertiesIndex[temp.ContentType.Id] = compositionProperties = temp.ContentType.CompositionPropertyTypes.ToArray(); @@ -808,7 +812,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected class TempContent { - public TempContent(int id, int versionId, int publishedVersionId, IContentTypeComposition contentType) + public TempContent(int id, int versionId, int publishedVersionId, IContentTypeComposition? contentType) { Id = id; VersionId = versionId; @@ -834,7 +838,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Gets or sets the content type. /// - public IContentTypeComposition ContentType { get; set; } + public IContentTypeComposition? ContentType { get; set; } /// /// Gets or sets the identifier of the template 1 of the content. @@ -850,7 +854,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected class TempContent : TempContent where T : class, IContentBase { - public TempContent(int id, int versionId, int publishedVersionId, IContentTypeComposition contentType, T content = null) + public TempContent(int id, int versionId, int publishedVersionId, IContentTypeComposition? contentType, T? content = null) : base(id, versionId, publishedVersionId, contentType) { Content = content; @@ -859,7 +863,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Gets or sets the associated actual content. /// - public T Content { get; set; } + public T? Content { get; set; } } /// @@ -873,10 +877,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Utilities - protected virtual string EnsureUniqueNodeName(int parentId, string nodeName, int id = 0) + protected virtual string? EnsureUniqueNodeName(int parentId, string nodeName, int id = 0) { var template = SqlContext.Templates.Get(Cms.Core.Constants.SqlTemplates.VersionableRepository.EnsureUniqueNodeName, tsql => tsql - .Select(x => Alias(x.NodeId, "id"), x => Alias(x.Text, "name")) + .Select(x => Alias(x.NodeId, "id"), x => Alias(x.Text!, "name")) .From() .Where(x => x.NodeObjectType == SqlTemplate.Arg("nodeObjectType") && x.ParentId == SqlTemplate.Arg("parentId")) ); @@ -935,7 +939,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement public abstract int RecycleBinId { get; } - public virtual IEnumerable GetRecycleBin() + public virtual IEnumerable? GetRecycleBin() { return Get(Query().Where(entity => entity.Trashed)); } @@ -956,18 +960,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement trackedRelations = trackedRelations.Distinct().ToList(); var udiToGuids = trackedRelations.Select(x => x.Udi as GuidUdi) - .ToDictionary(x => (Udi)x, x => x.Guid); + .ToDictionary(x => (Udi)x!, x => x!.Guid); //lookup in the DB all INT ids for the GUIDs and chuck into a dictionary var keyToIds = Database.Fetch(Sql().Select(x => x.NodeId, x => x.UniqueId).From().WhereIn(x => x.UniqueId, udiToGuids.Values)) .ToDictionary(x => x.UniqueId, x => x.NodeId); - var allRelationTypes = RelationTypeRepository.GetMany(Array.Empty()) + var allRelationTypes = RelationTypeRepository.GetMany(Array.Empty())? .ToDictionary(x => x.Alias, x => x); var toSave = trackedRelations.Select(rel => { - if (!allRelationTypes.TryGetValue(rel.RelationTypeAlias, out var relationType)) + if (allRelationTypes is null || !allRelationTypes.TryGetValue(rel.RelationTypeAlias, out var relationType)) throw new InvalidOperationException($"The relation type {rel.RelationTypeAlias} does not exist"); if (!udiToGuids.TryGetValue(rel.Udi, out var guid)) @@ -994,7 +998,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Used when creating a new entity /// - protected void InsertPropertyValues(TEntity entity, int publishedVersionId, out bool edited, out HashSet editedCultures) + protected void InsertPropertyValues(TEntity entity, int publishedVersionId, out bool edited, out HashSet? editedCultures) { // persist the property data var propertyDataDtos = PropertyFactory.BuildDtos(entity.ContentType.Variations, entity.VersionId, publishedVersionId, entity.Properties, LanguageRepository, out edited, out editedCultures); @@ -1015,7 +1019,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// - protected void ReplacePropertyValues(TEntity entity, int versionId, int publishedVersionId, out bool edited, out HashSet editedCultures) + protected void ReplacePropertyValues(TEntity entity, int versionId, int publishedVersionId, out bool edited, out HashSet? editedCultures) { // Replace the property data. // Lookup the data to update with a UPDLOCK (using ForUpdate()) this is because we need to be atomic @@ -1023,7 +1027,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var propDataSql = SqlContext.Sql().Select("*").From().Where(x => x.VersionId == versionId).ForUpdate(); var existingPropData = Database.Fetch(propDataSql); - var propertyTypeToPropertyData = new Dictionary<(int propertyTypeId, int versionId, int? languageId, string segment), PropertyDataDto>(); + var propertyTypeToPropertyData = new Dictionary<(int propertyTypeId, int versionId, int? languageId, string? segment), PropertyDataDto>(); var existingPropDataIds = new List(); foreach (var p in existingPropData) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs index 66ab87b743..1a831db780 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs @@ -43,45 +43,49 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement _shortStringHelper = shortStringHelper; } - private IDatabaseScope AmbientScope => _scopeAccessor.AmbientScope; - private IUmbracoDatabase Database => AmbientScope.Database; + private IDatabaseScope? AmbientScope => _scopeAccessor.AmbientScope; + private IUmbracoDatabase? Database => AmbientScope?.Database; - private ISqlContext SqlContext => AmbientScope.SqlContext; + private ISqlContext? SqlContext => AmbientScope?.SqlContext; //private Sql Sql(string sql, params object[] args) => SqlContext.Sql(sql, args); //private ISqlSyntaxProvider SqlSyntax => SqlContext.SqlSyntax; //private IQuery Query() => SqlContext.Query(); /// - public IEnumerable GetAllTypes() => + public IEnumerable? GetAllTypes() => // use a 5 minutes sliding cache - same as FullDataSet cache policy _appCaches.RuntimeCache.GetCacheItem(CacheKey, GetAllTypesInternal, TimeSpan.FromMinutes(5), true); /// public void ClearCache() => _appCaches.RuntimeCache.Clear(CacheKey); - private Sql Sql() => SqlContext.Sql(); + private Sql? Sql() => SqlContext?.Sql(); private IEnumerable GetAllTypesInternal() { var contentTypes = new Dictionary(); // get content types - Sql sql1 = Sql() + Sql? sql1 = Sql()? .Select(r => r.Select(x => x.NodeDto)) .From() .InnerJoin().On((ct, n) => ct.NodeId == n.NodeId) .OrderBy(x => x.NodeId); - List contentTypeDtos = Database.Fetch(sql1); + List? contentTypeDtos = Database?.Fetch(sql1); // get allowed content types - Sql sql2 = Sql() + Sql? sql2 = Sql()? .Select() .From() .OrderBy(x => x.Id); - List allowedDtos = Database.Fetch(sql2); + List? allowedDtos = Database?.Fetch(sql2); + if (contentTypeDtos is null) + { + return contentTypes.Values; + } // prepare // note: same alias could be used for media, content... but always different ids = ok var aliases = Enumerable.ToDictionary(contentTypeDtos, x => x.NodeId, x => x.Alias); @@ -114,7 +118,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // map allowed content types var allowedContentTypes = new List(); - while (allowedDtoIx < allowedDtos.Count && allowedDtos[allowedDtoIx].Id == contentTypeDto.NodeId) + while (allowedDtoIx < allowedDtos?.Count && allowedDtos[allowedDtoIx].Id == contentTypeDto.NodeId) { ContentTypeAllowedContentTypeDto allowedDto = allowedDtos[allowedDtoIx]; if (!aliases.TryGetValue(allowedDto.AllowedId, out var alias)) @@ -123,7 +127,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } allowedContentTypes.Add(new ContentTypeSort(new Lazy(() => allowedDto.AllowedId), - allowedDto.SortOrder, alias)); + allowedDto.SortOrder, alias!)); allowedDtoIx++; } @@ -147,15 +151,15 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private void MapHistoryCleanup(Dictionary contentTypes) { // get templates - Sql sql1 = Sql() + Sql? sql1 = Sql()? .Select() .From() .OrderBy(x => x.ContentTypeId); - var contentVersionCleanupPolicyDtos = Database.Fetch(sql1); + var contentVersionCleanupPolicyDtos = Database?.Fetch(sql1); var contentVersionCleanupPolicyDictionary = - contentVersionCleanupPolicyDtos.ToDictionary(x => x.ContentTypeId); + contentVersionCleanupPolicyDtos?.ToDictionary(x => x.ContentTypeId); foreach (IContentTypeComposition c in contentTypes.Values) { if (!(c is ContentType contentType)) @@ -165,7 +169,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var historyCleanup = new HistoryCleanup(); - if (contentVersionCleanupPolicyDictionary.TryGetValue(contentType.Id, out var versionCleanup)) + if (contentVersionCleanupPolicyDictionary is not null && contentVersionCleanupPolicyDictionary.TryGetValue(contentType.Id, out var versionCleanup)) { historyCleanup.PreventCleanup = versionCleanup.PreventCleanup; historyCleanup.KeepAllVersionsNewerThanDays = versionCleanup.KeepAllVersionsNewerThanDays; @@ -179,14 +183,19 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private void MapTemplates(Dictionary contentTypes) { // get templates - Sql sql1 = Sql() + Sql? sql1 = Sql()? .Select() .From() .OrderBy(x => x.ContentTypeNodeId); - List templateDtos = Database.Fetch(sql1); + List? templateDtos = Database?.Fetch(sql1); //var templates = templateRepository.GetMany(templateDtos.Select(x => x.TemplateNodeId).ToArray()).ToDictionary(x => x.Id, x => x); - var templates = Enumerable.ToDictionary(_templateRepository.GetMany(), x => x.Id, x => x); + var allTemplates = _templateRepository.GetMany(); + if (allTemplates is null) + { + return; + } + var templates = Enumerable.ToDictionary(allTemplates, x => x.Id, x => x); var templateDtoIx = 0; foreach (IContentTypeComposition c in contentTypes.Values) @@ -199,12 +208,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // map allowed templates var allowedTemplates = new List(); var defaultTemplateId = 0; - while (templateDtoIx < templateDtos.Count && + while (templateDtoIx < templateDtos?.Count && templateDtos[templateDtoIx].ContentTypeNodeId == contentType.Id) { ContentTypeTemplateDto allowedDto = templateDtos[templateDtoIx]; templateDtoIx++; - if (!templates.TryGetValue(allowedDto.TemplateNodeId, out ITemplate template)) + if (!templates.TryGetValue(allowedDto.TemplateNodeId, out ITemplate? template)) { continue; } @@ -225,24 +234,24 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private void MapComposition(IDictionary contentTypes) { // get parent/child - Sql sql1 = Sql() + Sql? sql1 = Sql()? .Select() .From() .OrderBy(x => x.ChildId); - List compositionDtos = Database.Fetch(sql1); + List? compositionDtos = Database?.Fetch(sql1); // map var compositionIx = 0; foreach (IContentTypeComposition contentType in contentTypes.Values) { - while (compositionIx < compositionDtos.Count && + while (compositionIx < compositionDtos?.Count && compositionDtos[compositionIx].ChildId == contentType.Id) { ContentType2ContentTypeDto parentDto = compositionDtos[compositionIx]; compositionIx++; - if (!contentTypes.TryGetValue(parentDto.ParentId, out IContentTypeComposition parentContentType)) + if (!contentTypes.TryGetValue(parentDto.ParentId, out IContentTypeComposition? parentContentType)) { continue; } @@ -254,7 +263,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private void MapGroupsAndProperties(IDictionary contentTypes) { - Sql sql1 = Sql() + Sql? sql1 = Sql()? .Select() .From() .InnerJoin() @@ -262,9 +271,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .OrderBy(x => x.NodeId) .AndBy(x => x.SortOrder, x => x.Id); - List groupDtos = Database.Fetch(sql1); + List? groupDtos = Database?.Fetch(sql1); - Sql sql2 = Sql() + Sql? sql2 = Sql()? .Select(r => r.Select(x => x.DataTypeDto, r1 => r1.Select(x => x.NodeDto))) .AndSelect() .From() @@ -282,7 +291,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement x => x.Id) // NULLs will come first or last, never mind, we deal with it below .AndBy(x => x.SortOrder, x => x.Id); - List propertyDtos = Database.Fetch(sql2); + List? propertyDtos = Database?.Fetch(sql2); Dictionary builtinProperties = ConventionsHelper.GetStandardPropertyTypeStubs(_shortStringHelper); @@ -295,7 +304,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // get group-less properties (in case NULL is ordered first) var noGroupPropertyTypes = new PropertyTypeCollection(isPublishing); - while (propertyIx < propertyDtos.Count && propertyDtos[propertyIx].ContentTypeId == contentType.Id && + while (propertyIx < propertyDtos?.Count && propertyDtos[propertyIx].ContentTypeId == contentType.Id && propertyDtos[propertyIx].PropertyTypeGroupId == null) { noGroupPropertyTypes.Add(MapPropertyType(contentType, propertyDtos[propertyIx], builtinProperties)); @@ -304,17 +313,17 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // get groups and their properties var groupCollection = new PropertyGroupCollection(); - while (groupIx < groupDtos.Count && groupDtos[groupIx].ContentTypeNodeId == contentType.Id) + while (groupIx < groupDtos?.Count && groupDtos[groupIx].ContentTypeNodeId == contentType.Id) { PropertyGroup group = MapPropertyGroup(groupDtos[groupIx], isPublishing); groupCollection.Add(group); groupIx++; - while (propertyIx < propertyDtos.Count && + while (propertyIx < propertyDtos?.Count && propertyDtos[propertyIx].ContentTypeId == contentType.Id && propertyDtos[propertyIx].PropertyTypeGroupId == group.Id) { - group.PropertyTypes.Add(MapPropertyType(contentType, propertyDtos[propertyIx], + group.PropertyTypes?.Add(MapPropertyType(contentType, propertyDtos[propertyIx], builtinProperties)); propertyIx++; } @@ -323,7 +332,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement contentType.PropertyGroups = groupCollection; // get group-less properties (in case NULL is ordered last) - while (propertyIx < propertyDtos.Count && propertyDtos[propertyIx].ContentTypeId == contentType.Id && + while (propertyIx < propertyDtos?.Count && propertyDtos[propertyIx].ContentTypeId == contentType.Id && propertyDtos[propertyIx].PropertyTypeGroupId == null) { noGroupPropertyTypes.Add(MapPropertyType(contentType, propertyDtos[propertyIx], builtinProperties)); @@ -370,12 +379,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { var groupId = dto.PropertyTypeGroupId; - var readonlyStorageType = builtinProperties.TryGetValue(dto.Alias, out PropertyType propertyType); + var readonlyStorageType = builtinProperties.TryGetValue(dto.Alias!, out PropertyType? propertyType); ValueStorageType storageType = readonlyStorageType - ? propertyType.ValueStorageType + ? propertyType!.ValueStorageType : Enum.Parse(dto.DataTypeDto.DbType); - if (contentType is IMemberType memberType) + if (contentType is IMemberType memberType && dto.Alias is not null) { memberType.SetIsSensitiveProperty(dto.Alias, dto.IsSensitive); memberType.SetMemberCanEditProperty(dto.Alias, dto.CanEdit); @@ -393,7 +402,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement Key = dto.UniqueId, Mandatory = dto.Mandatory, MandatoryMessage = dto.MandatoryMessage, - Name = dto.Name, + Name = dto.Name ?? string.Empty, PropertyGroupId = groupId.HasValue ? new Lazy(() => groupId.Value) : null, SortOrder = dto.SortOrder, ValidationRegExp = dto.ValidationRegExp, diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs index 56fd356011..d42e4bab11 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs @@ -44,27 +44,27 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // and ah, well, this all caching should be refactored + the cache refreshers // should to repository.Clear() not deal with magic caches by themselves - protected override IContentType PerformGet(int id) - => GetMany().FirstOrDefault(x => x.Id == id); + protected override IContentType? PerformGet(int id) + => GetMany()?.FirstOrDefault(x => x.Id == id); - protected override IContentType PerformGet(Guid id) - => GetMany().FirstOrDefault(x => x.Key == id); + protected override IContentType? PerformGet(Guid id) + => GetMany()?.FirstOrDefault(x => x.Key == id); - protected override IContentType PerformGet(string alias) - => GetMany().FirstOrDefault(x => x.Alias.InvariantEquals(alias)); + protected override IContentType? PerformGet(string alias) + => GetMany()?.FirstOrDefault(x => x.Alias.InvariantEquals(alias)); protected override bool PerformExists(Guid id) - => GetMany().FirstOrDefault(x => x.Key == id) != null; + => GetMany()?.FirstOrDefault(x => x.Key == id) != null; - protected override IEnumerable GetAllWithFullCachePolicy() + protected override IEnumerable? GetAllWithFullCachePolicy() { - return CommonRepository.GetAllTypes().OfType(); + return CommonRepository.GetAllTypes()?.OfType(); } - protected override IEnumerable PerformGetAll(params Guid[] ids) + protected override IEnumerable? PerformGetAll(params Guid[]? ids) { var all = GetMany(); - return ids.Any() ? all.Where(x => ids.Contains(x.Key)) : all; + return ids?.Any() ?? false ? all?.Where(x => ids.Contains(x.Key)) : all; } protected override IEnumerable PerformGetByQuery(IQuery query) @@ -74,14 +74,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var sql = translator.Translate(); var ids = Database.Fetch(sql).Distinct().ToArray(); - return ids.Length > 0 ? GetMany(ids).OrderBy(x => x.Name) : Enumerable.Empty(); + return ids.Length > 0 ? GetMany(ids)?.OrderBy(x => x.Name) ?? Enumerable.Empty() : Enumerable.Empty(); } /// public IEnumerable GetByQuery(IQuery query) { var ints = PerformGetByQuery(query).ToArray(); - return ints.Length > 0 ? GetMany(ints) : Enumerable.Empty(); + return ints.Length > 0 ? GetMany(ints) ?? Enumerable.Empty() : Enumerable.Empty(); } protected IEnumerable PerformGetByQuery(IQuery query) @@ -198,9 +198,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { var query = Query().Where(x => x.ParentId == entity.Id); var children = Get(query); - foreach (var child in children) + if (children is not null) { - PersistDeletedItem(child); + foreach (var child in children) + { + PersistDeletedItem(child); + } } //Before we call the base class methods to run all delete clauses, we need to first @@ -257,7 +260,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement IsDefault = true }); } - foreach (var template in entity.AllowedTemplates.Where(x => x != null && x.Id != defaultTemplateId)) + foreach (var template in entity.AllowedTemplates?.Where(x => x != null && x.Id != defaultTemplateId) ?? Array.Empty()) { Database.Insert(new ContentTypeTemplateDto { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 5ffdf4bf10..1970bcaa9b 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -27,12 +27,15 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Exposes shared functionality /// - internal abstract class ContentTypeRepositoryBase : EntityRepositoryBase, IReadRepository + internal abstract class ContentTypeRepositoryBase : EntityRepositoryBase, + IReadRepository where TEntity : class, IContentTypeComposition { private readonly IShortStringHelper _shortStringHelper; - protected ContentTypeRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger> logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository, IShortStringHelper shortStringHelper) + protected ContentTypeRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, + ILogger> logger, IContentTypeCommonRepository commonRepository, + ILanguageRepository languageRepository, IShortStringHelper shortStringHelper) : base(scopeAccessor, cache, logger) { _shortStringHelper = shortStringHelper; @@ -55,17 +58,16 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement if (container != null) { // check path - if ((string.Format(",{0},", container.Path)).IndexOf(string.Format(",{0},", moving.Id), StringComparison.Ordinal) > -1) - throw new DataOperationException(MoveOperationStatusType.FailedNotAllowedByPath); + if ((string.Format(",{0},", container.Path)).IndexOf(string.Format(",{0},", moving.Id), + StringComparison.Ordinal) > -1) + throw new DataOperationException(MoveOperationStatusType + .FailedNotAllowedByPath); parentId = container.Id; } // track moved entities - var moveInfo = new List> - { - new MoveEventInfo(moving, moving.Path, parentId) - }; + var moveInfo = new List> {new MoveEventInfo(moving, moving.Path, parentId)}; // get the level delta (old pos to new pos) @@ -85,6 +87,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var paths = new Dictionary(); paths[moving.Id] = moving.Path; + if (descendants is null) + { + return moveInfo; + } foreach (var descendant in descendants.OrderBy(x => x.Level)) { moveInfo.Add(new MoveEventInfo(descendant, descendant.Path, descendant.ParentId)); @@ -98,7 +104,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return moveInfo; } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable? PerformGetAll(params int[]? ids) { var result = GetAllWithFullCachePolicy(); @@ -106,17 +112,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // even GetMany(ids) gets everything and filters afterwards, // however if we are using No Cache, we must still be able to support // collections of Ids, so this is to work around that: - if (ids.Any()) + if (ids?.Any() ?? false) { - return result.Where(x => ids.Contains(x.Id)); + return result?.Where(x => ids.Contains(x.Id)); } return result; } - protected abstract IEnumerable GetAllWithFullCachePolicy(); + protected abstract IEnumerable? GetAllWithFullCachePolicy(); - protected virtual PropertyType CreatePropertyType(string propertyEditorAlias, ValueStorageType storageType, string propertyTypeAlias) + protected virtual PropertyType CreatePropertyType(string propertyEditorAlias, ValueStorageType storageType, + string propertyTypeAlias) { return new PropertyType(_shortStringHelper, propertyEditorAlias, storageType, propertyTypeAlias); } @@ -138,25 +145,28 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement INNER JOIN umbracoNode ON cmsContentType.nodeId = umbracoNode.id WHERE cmsContentType." + SqlSyntax.GetQuotedColumnName("alias") + @"= @alias AND umbracoNode.nodeObjectType = @objectType", - new { alias = entity.Alias, objectType = NodeObjectTypeId }); + new {alias = entity.Alias, objectType = NodeObjectTypeId}); if (exists > 0) { throw new DuplicateNameException("An item with the alias " + entity.Alias + " already exists"); } //Logic for setting Path, Level and SortOrder - var parent = Database.First("WHERE id = @ParentId", new { ParentId = entity.ParentId }); + var parent = Database.First("WHERE id = @ParentId", new {ParentId = entity.ParentId}); int level = parent.Level + 1; int sortOrder = - Database.ExecuteScalar("SELECT COUNT(*) FROM umbracoNode WHERE parentID = @ParentId AND nodeObjectType = @NodeObjectType", - new { ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId }); + Database.ExecuteScalar( + "SELECT COUNT(*) FROM umbracoNode WHERE parentID = @ParentId AND nodeObjectType = @NodeObjectType", + new {ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId}); //Create the (base) node data - umbracoNode var nodeDto = dto.NodeDto; nodeDto.Path = parent.Path; nodeDto.Level = short.Parse(level.ToString(CultureInfo.InvariantCulture)); nodeDto.SortOrder = sortOrder; - var o = Database.IsNew(nodeDto) ? Convert.ToInt32(Database.Insert(nodeDto)) : Database.Update(nodeDto); + var o = Database.IsNew(nodeDto) + ? Convert.ToInt32(Database.Insert(nodeDto)) + : Database.Update(nodeDto); //Update with new correct path nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId); @@ -175,32 +185,41 @@ AND umbracoNode.nodeObjectType = @objectType", //Insert ContentType composition in new table foreach (var composition in entity.ContentTypeComposition) { - if (composition.Id == entity.Id) continue;//Just to ensure that we aren't creating a reference to ourself. + if (composition.Id == entity.Id) + continue; //Just to ensure that we aren't creating a reference to ourself. if (composition.HasIdentity) { - Database.Insert(new ContentType2ContentTypeDto { ParentId = composition.Id, ChildId = entity.Id }); + Database.Insert(new ContentType2ContentTypeDto {ParentId = composition.Id, ChildId = entity.Id}); } else { //Fallback for ContentTypes with no identity - var contentTypeDto = Database.FirstOrDefault("WHERE alias = @Alias", new { Alias = composition.Alias }); + var contentTypeDto = + Database.FirstOrDefault("WHERE alias = @Alias", + new {Alias = composition.Alias}); if (contentTypeDto != null) { - Database.Insert(new ContentType2ContentTypeDto { ParentId = contentTypeDto.NodeId, ChildId = entity.Id }); + Database.Insert(new ContentType2ContentTypeDto + { + ParentId = contentTypeDto.NodeId, ChildId = entity.Id + }); } } } - //Insert collection of allowed content types - foreach (var allowedContentType in entity.AllowedContentTypes) + if (entity.AllowedContentTypes is not null) { - Database.Insert(new ContentTypeAllowedContentTypeDto + //Insert collection of allowed content types + foreach (var allowedContentType in entity.AllowedContentTypes) { - Id = entity.Id, - AllowedId = allowedContentType.Id.Value, - SortOrder = allowedContentType.SortOrder - }); + Database.Insert(new ContentTypeAllowedContentTypeDto + { + Id = entity.Id, + AllowedId = allowedContentType.Id.Value, + SortOrder = allowedContentType.SortOrder + }); + } } //Insert Tabs @@ -208,16 +227,19 @@ AND umbracoNode.nodeObjectType = @objectType", { var tabDto = PropertyGroupFactory.BuildGroupDto(propertyGroup, nodeDto.NodeId); var primaryKey = Convert.ToInt32(Database.Insert(tabDto)); - propertyGroup.Id = primaryKey;//Set Id on PropertyGroup + propertyGroup.Id = primaryKey; //Set Id on PropertyGroup //Ensure that the PropertyGroup's Id is set on the PropertyTypes within a group //unless the PropertyGroupId has already been changed. - foreach (var propertyType in propertyGroup.PropertyTypes) + if (propertyGroup.PropertyTypes is not null) { - if (propertyType.IsPropertyDirty("PropertyGroupId") == false) + foreach (var propertyType in propertyGroup.PropertyTypes) { - var tempGroup = propertyGroup; - propertyType.PropertyGroupId = new Lazy(() => tempGroup.Id); + if (propertyType.IsPropertyDirty("PropertyGroupId") == false) + { + var tempGroup = propertyGroup; + propertyType.PropertyGroupId = new Lazy(() => tempGroup.Id); + } } } } @@ -231,12 +253,14 @@ AND umbracoNode.nodeObjectType = @objectType", { AssignDataTypeFromPropertyEditor(propertyType); } + var propertyTypeDto = PropertyGroupFactory.BuildPropertyTypeDto(tabId, propertyType, nodeDto.NodeId); int typePrimaryKey = Convert.ToInt32(Database.Insert(propertyTypeDto)); propertyType.Id = typePrimaryKey; //Set Id on new PropertyType //Update the current PropertyType with correct PropertyEditorAlias and DatabaseType - var dataTypeDto = Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = propertyTypeDto.DataTypeId }); + var dataTypeDto = + Database.FirstOrDefault("WHERE nodeId = @Id", new {Id = propertyTypeDto.DataTypeId}); propertyType.PropertyEditorAlias = dataTypeDto.EditorAlias; propertyType.ValueStorageType = dataTypeDto.DbType.EnumParse(true); } @@ -257,7 +281,7 @@ INNER JOIN umbracoNode ON cmsContentType.nodeId = umbracoNode.id WHERE cmsContentType." + SqlSyntax.GetQuotedColumnName("alias") + @"= @alias AND umbracoNode.nodeObjectType = @objectType AND umbracoNode.id <> @id", - new { id = dto.NodeId, alias = dto.Alias, objectType = NodeObjectTypeId }); + new {id = dto.NodeId, alias = dto.Alias, objectType = NodeObjectTypeId}); if (exists > 0) { throw new DuplicateNameException("An item with the alias " + dto.Alias + " already exists"); @@ -271,14 +295,14 @@ AND umbracoNode.id <> @id", // we NEED this: updating, so the .PrimaryKey already exists, but the entity does // not carry it and therefore the dto does not have it yet - must get it from db, // look up ContentType entry to get PrimaryKey for updating the DTO - var dtoPk = Database.First("WHERE nodeId = @Id", new { entity.Id }); + var dtoPk = Database.First("WHERE nodeId = @Id", new {entity.Id}); dto.PrimaryKey = dtoPk.PrimaryKey; Database.Update(dto); // handle (delete then recreate) compositions - Database.Delete("WHERE childContentTypeId = @Id", new { entity.Id }); + Database.Delete("WHERE childContentTypeId = @Id", new {entity.Id}); foreach (var composition in entity.ContentTypeComposition) - Database.Insert(new ContentType2ContentTypeDto { ParentId = composition.Id, ChildId = entity.Id }); + Database.Insert(new ContentType2ContentTypeDto {ParentId = composition.Id, ChildId = entity.Id}); // removing a ContentType from a composition (U4-1690) // 1. Find content based on the current ContentType: entity.Id @@ -301,7 +325,7 @@ AND umbracoNode.id <> @id", foreach (var key in entity.RemovedContentTypes) { // find PropertyTypes for the removed ContentType - var propertyTypes = Database.Fetch("WHERE contentTypeId = @Id", new { Id = key }); + var propertyTypes = Database.Fetch("WHERE contentTypeId = @Id", new {Id = key}); // loop through the Content that is based on the current ContentType in order to remove the Properties that are // based on the PropertyTypes that belong to the removed ContentType. foreach (var contentDto in contentDtos) @@ -314,37 +338,44 @@ AND umbracoNode.id <> @id", var propertySql = Sql() .Select(x => x.Id) .From() - .InnerJoin().On((left, right) => left.PropertyTypeId == right.Id) - .InnerJoin().On((left, right) => left.VersionId == right.Id) + .InnerJoin() + .On((left, right) => left.PropertyTypeId == right.Id) + .InnerJoin() + .On((left, right) => left.VersionId == right.Id) .Where(x => x.NodeId == nodeId) .Where(x => x.Id == propertyTypeId); // finally delete the properties that match our criteria for removing a ContentType from the composition - Database.Delete(new Sql("WHERE id IN (" + propertySql.SQL + ")", propertySql.Arguments)); + Database.Delete(new Sql("WHERE id IN (" + propertySql.SQL + ")", + propertySql.Arguments)); } } } } // delete the allowed content type entries before re-inserting the collection of allowed content types - Database.Delete("WHERE Id = @Id", new { entity.Id }); - foreach (var allowedContentType in entity.AllowedContentTypes) + Database.Delete("WHERE Id = @Id", new {entity.Id}); + if (entity.AllowedContentTypes is not null) { - Database.Insert(new ContentTypeAllowedContentTypeDto + foreach (var allowedContentType in entity.AllowedContentTypes) { - Id = entity.Id, - AllowedId = allowedContentType.Id.Value, - SortOrder = allowedContentType.SortOrder - }); + Database.Insert(new ContentTypeAllowedContentTypeDto + { + Id = entity.Id, + AllowedId = allowedContentType.Id.Value, + SortOrder = allowedContentType.SortOrder + }); + } } // Delete property types ... by excepting entries from db with entries from collections. // We check if the entity's own PropertyTypes has been modified and then also check // any of the property groups PropertyTypes has been modified. // This specifically tells us if any property type collections have changed. - if (entity.IsPropertyDirty("NoGroupPropertyTypes") || entity.PropertyGroups.Any(x => x.IsPropertyDirty("PropertyTypes"))) + if (entity.IsPropertyDirty("NoGroupPropertyTypes") || + entity.PropertyGroups.Any(x => x.IsPropertyDirty("PropertyTypes"))) { - var dbPropertyTypes = Database.Fetch("WHERE contentTypeId = @Id", new { entity.Id }); + var dbPropertyTypes = Database.Fetch("WHERE contentTypeId = @Id", new {entity.Id}); var dbPropertyTypeIds = dbPropertyTypes.Select(x => x.Id); var entityPropertyTypes = entity.PropertyTypes.Where(x => x.HasIdentity).Select(x => x.Id); var propertyTypeToDeleteIds = dbPropertyTypeIds.Except(entityPropertyTypes); @@ -355,7 +386,7 @@ AND umbracoNode.id <> @id", // Delete tabs ... by excepting entries from db with entries from collections. // We check if the entity's own PropertyGroups has been modified. // This specifically tells us if the property group collections have changed. - List orphanPropertyTypeIds = null; + List? orphanPropertyTypeIds = null; if (entity.IsPropertyDirty("PropertyGroups")) { // TODO: we used to try to propagate tabs renaming downstream, relying on ParentId, but @@ -375,7 +406,8 @@ AND umbracoNode.id <> @id", // delete tabs that do not exist anymore // get the tabs that are currently existing (in the db), get the tabs that we want, // now, and derive the tabs that we want to delete - var existingPropertyGroups = Database.Fetch("WHERE contentTypeNodeId = @id", new { id = entity.Id }) + var existingPropertyGroups = Database + .Fetch("WHERE contentTypeNodeId = @id", new {id = entity.Id}) .Select(x => x.Id) .ToList(); var newPropertyGroups = entity.PropertyGroups.Select(x => x.Id).ToList(); @@ -390,12 +422,15 @@ AND umbracoNode.id <> @id", // - move them to 'generic properties' so they remain consistent // - keep track of them, later on we'll figure out what to do with them // see http://issues.umbraco.org/issue/U4-8663 - orphanPropertyTypeIds = Database.Fetch("WHERE propertyTypeGroupId IN (@ids)", new { ids = groupsToDelete }) + orphanPropertyTypeIds = Database.Fetch("WHERE propertyTypeGroupId IN (@ids)", + new {ids = groupsToDelete}) .Select(x => x.Id).ToList(); - Database.Update("SET propertyTypeGroupId = NULL WHERE propertyTypeGroupId IN (@ids)", new { ids = groupsToDelete }); + Database.Update( + "SET propertyTypeGroupId = NULL WHERE propertyTypeGroupId IN (@ids)", + new {ids = groupsToDelete}); // now we can delete the tabs - Database.Delete("WHERE id IN (@ids)", new { ids = groupsToDelete }); + Database.Delete("WHERE id IN (@ids)", new {ids = groupsToDelete}); } } @@ -415,15 +450,21 @@ AND umbracoNode.id <> @id", // assign properties to the group // (all of them, even those that have .IsPropertyDirty("PropertyGroupId") == true, // because it should have been set to this group anyways and better be safe) - foreach (var propertyType in propertyGroup.PropertyTypes) - propertyType.PropertyGroupId = new Lazy(() => groupId); + if (propertyGroup.PropertyTypes is not null) + { + foreach (var propertyType in propertyGroup.PropertyTypes) + { + propertyType.PropertyGroupId = new Lazy(() => groupId); + } + } } //check if the content type variation has been changed var contentTypeVariationDirty = entity.IsPropertyDirty("Variations"); var oldContentTypeVariation = (ContentVariation)dtoPk.Variations; var newContentTypeVariation = entity.Variations; - var contentTypeVariationChanging = contentTypeVariationDirty && oldContentTypeVariation != newContentTypeVariation; + var contentTypeVariationChanging = + contentTypeVariationDirty && oldContentTypeVariation != newContentTypeVariation; if (contentTypeVariationChanging) { MoveContentTypeVariantData(entity, oldContentTypeVariation, newContentTypeVariation); @@ -432,7 +473,7 @@ AND umbracoNode.id <> @id", } // collect property types that have a dirty variation - List propertyTypeVariationDirty = null; + List? propertyTypeVariationDirty = null; // note: this only deals with *local* property types, we're dealing w/compositions later below foreach (var propertyType in entity.PropertyTypes) @@ -463,7 +504,8 @@ AND umbracoNode.id <> @id", // via composition, with their original variations (ie not filtered by this // content type variations - we need this true value to make decisions. - propertyTypeVariationChanges = propertyTypeVariationChanges ?? new Dictionary(); + propertyTypeVariationChanges = propertyTypeVariationChanges ?? + new Dictionary(); foreach (var composedPropertyType in entity.GetOriginalComposedPropertyTypes()) { @@ -566,23 +608,29 @@ AND umbracoNode.id <> @id", // For example, when entity.Variations is set to Culture a property cannot be set to Segment. var isValid = entity.Variations.HasFlag(prop.Variations); if (!isValid) - throw new InvalidOperationException($"The property {prop.Alias} cannot have variations of {prop.Variations} with the content type variations of {entity.Variations}"); + throw new InvalidOperationException( + $"The property {prop.Alias} cannot have variations of {prop.Variations} with the content type variations of {entity.Variations}"); } } - private IEnumerable GetImpactedContentTypes(IContentTypeComposition contentType, IEnumerable all) + private IEnumerable GetImpactedContentTypes(IContentTypeComposition contentType, + IEnumerable? all) { + if (all is null) + { + return Enumerable.Empty(); + } var impact = new List(); - var set = new List { contentType }; + var set = new List {contentType}; var tree = new Dictionary>(); foreach (var x in all) - foreach (var y in x.ContentTypeComposition) - { - if (!tree.TryGetValue(y.Id, out var list)) - list = tree[y.Id] = new List(); - list.Add(x); - } + foreach (var y in x.ContentTypeComposition) + { + if (!tree.TryGetValue(y.Id, out var list)) + list = tree[y.Id] = new List(); + list.Add(x); + } var nset = new List(); do @@ -604,7 +652,8 @@ AND umbracoNode.id <> @id", // gets property types that have actually changed, and the corresponding changes // returns null if no property type has actually changed - private Dictionary GetPropertyVariationChanges(IEnumerable propertyTypes) + private Dictionary? + GetPropertyVariationChanges(IEnumerable propertyTypes) { var propertyTypesL = propertyTypes.ToList(); @@ -617,7 +666,7 @@ AND umbracoNode.id <> @id", var oldVariations = Database.Dictionary(selectCurrentVariations); // build a dictionary of actual changes - Dictionary changes = null; + Dictionary? changes = null; foreach (var propertyType in propertyTypesL) { @@ -653,7 +702,8 @@ AND umbracoNode.id <> @id", .Where(x => x.ContentTypeId == contentType.Id); var sqlDelete = Sql() .Delete() - .WhereIn((System.Linq.Expressions.Expression>)(x => x.ContentKey), sqlSelect); + .WhereIn((System.Linq.Expressions.Expression>)(x => x.ContentKey), + sqlSelect); Database.Execute(sqlDelete); } @@ -682,7 +732,9 @@ AND umbracoNode.id <> @id", /// /// Moves variant data for property type variation changes. /// - private void MovePropertyTypeVariantData(IDictionary propertyTypeChanges, IEnumerable impacted) + private void MovePropertyTypeVariantData( + IDictionary propertyTypeChanges, + IEnumerable impacted) { var defaultLanguageId = GetDefaultLanguageId(); var impactedL = impacted.Select(x => x.Id).ToList(); @@ -716,7 +768,8 @@ AND umbracoNode.id <> @id", /// /// Moves variant data for a content type variation change. /// - private void MoveContentTypeVariantData(IContentTypeComposition contentType, ContentVariation fromVariation, ContentVariation toVariation) + private void MoveContentTypeVariantData(IContentTypeComposition contentType, ContentVariation fromVariation, + ContentVariation toVariation) { var defaultLanguageId = GetDefaultLanguageId(); @@ -732,7 +785,8 @@ AND umbracoNode.id <> @id", //clear out the versionCultureVariation table var sqlSelect = Sql().Select(x => x.Id) .From() - .InnerJoin().On(x => x.Id, x => x.VersionId) + .InnerJoin() + .On(x => x.Id, x => x.VersionId) .InnerJoin().On(x => x.NodeId, x => x.NodeId) .Where(x => x.ContentTypeId == contentType.Id) .Where(x => x.LanguageId == defaultLanguageId); @@ -757,18 +811,21 @@ AND umbracoNode.id <> @id", //now we need to insert names into these 2 tables based on the invariant data //insert rows into the versionCultureVariationDto table based on the data from contentVersionDto for the default lang - var cols = Sql().Columns(x => x.VersionId, x => x.Name, x => x.UpdateUserId, x => x.UpdateDate, x => x.LanguageId); + var cols = Sql().Columns(x => x.VersionId, x => x.Name, + x => x.UpdateUserId, x => x.UpdateDate, x => x.LanguageId); sqlSelect = Sql().Select(x => x.Id, x => x.Text, x => x.UserId, x => x.VersionDate) .Append($", {defaultLanguageId}") //default language ID .From() .InnerJoin().On(x => x.NodeId, x => x.NodeId) .Where(x => x.ContentTypeId == contentType.Id); - var sqlInsert = Sql($"INSERT INTO {ContentVersionCultureVariationDto.TableName} ({cols})").Append(sqlSelect); + var sqlInsert = Sql($"INSERT INTO {ContentVersionCultureVariationDto.TableName} ({cols})") + .Append(sqlSelect); Database.Execute(sqlInsert); //insert rows into the documentCultureVariation table - cols = Sql().Columns(x => x.NodeId, x => x.Edited, x => x.Published, x => x.Name, x => x.Available, x => x.LanguageId); + cols = Sql().Columns(x => x.NodeId, x => x.Edited, x => x.Published, + x => x.Name, x => x.Available, x => x.LanguageId); sqlSelect = Sql().Select(x => x.NodeId, x => x.Edited, x => x.Published) .AndSelect(x => x.Text) .Append($", 1, {defaultLanguageId}") //make Available + default language ID @@ -790,7 +847,8 @@ AND umbracoNode.id <> @id", } /// - private void CopyTagData(int? sourceLanguageId, int? targetLanguageId, IReadOnlyCollection propertyTypeIds, IReadOnlyCollection contentTypeIds = null) + private void CopyTagData(int? sourceLanguageId, int? targetLanguageId, IReadOnlyCollection propertyTypeIds, + IReadOnlyCollection? contentTypeIds = null) { // note: important to use SqlNullableEquals for nullable types, cannot directly compare language identifiers @@ -808,7 +866,8 @@ AND umbracoNode.id <> @id", if (contentTypeIds != null) sqlSelectTagsToDelete - .InnerJoin().On((rel, content) => rel.NodeId == content.NodeId) + .InnerJoin() + .On((rel, content) => rel.NodeId == content.NodeId) .WhereIn(x => x.ContentTypeId, contentTypeIds); sqlSelectTagsToDelete @@ -844,11 +903,15 @@ AND umbracoNode.id <> @id", sqlSelectTagsToInsert .InnerJoin().On((tag, rel) => tag.Id == rel.TagId) - .LeftJoin("xtags").On((tag, xtag) => tag.Text == xtag.Text && tag.Group == xtag.Group && xtag.LanguageId.SqlNullableEquals(targetLanguageId, -1), aliasRight: "xtags"); + .LeftJoin("xtags") + .On( + (tag, xtag) => tag.Text == xtag.Text && tag.Group == xtag.Group && + xtag.LanguageId.SqlNullableEquals(targetLanguageId, -1), aliasRight: "xtags"); if (contentTypeIds != null) sqlSelectTagsToInsert - .InnerJoin().On((rel, content) => rel.NodeId == content.NodeId) + .InnerJoin() + .On((rel, content) => rel.NodeId == content.NodeId) .WhereIn(x => x.ContentTypeId, contentTypeIds); sqlSelectTagsToInsert @@ -873,19 +936,25 @@ AND umbracoNode.id <> @id", .AndSelect("otag", x => x.Id) .From() .InnerJoin().On((rel, tag) => rel.TagId == tag.Id) - .InnerJoin("otag").On((tag, otag) => tag.Text == otag.Text && tag.Group == otag.Group && otag.LanguageId.SqlNullableEquals(targetLanguageId, -1), aliasRight: "otag"); + .InnerJoin("otag") + .On( + (tag, otag) => tag.Text == otag.Text && tag.Group == otag.Group && + otag.LanguageId.SqlNullableEquals(targetLanguageId, -1), aliasRight: "otag"); if (contentTypeIds != null) sqlSelectRelationsToInsert - .InnerJoin().On((rel, content) => rel.NodeId == content.NodeId) + .InnerJoin() + .On((rel, content) => rel.NodeId == content.NodeId) .WhereIn(x => x.ContentTypeId, contentTypeIds); sqlSelectRelationsToInsert .Where(x => x.LanguageId.SqlNullableEquals(sourceLanguageId, -1)) .WhereIn(x => x.PropertyTypeId, propertyTypeIds); - var relationColumnsToInsert = Sql().Columns(x => x.NodeId, x => x.PropertyTypeId, x => x.TagId); - var sqlInsertRelations = Sql($"INSERT INTO {TagRelationshipDto.TableName} ({relationColumnsToInsert})").Append(sqlSelectRelationsToInsert); + var relationColumnsToInsert = + Sql().Columns(x => x.NodeId, x => x.PropertyTypeId, x => x.TagId); + var sqlInsertRelations = Sql($"INSERT INTO {TagRelationshipDto.TableName} ({relationColumnsToInsert})") + .Append(sqlSelectRelationsToInsert); Database.Execute(sqlInsertRelations); @@ -899,7 +968,8 @@ AND umbracoNode.id <> @id", if (contentTypeIds != null) sqlSelectTagsToDelete - .InnerJoin().On((rel, content) => rel.NodeId == content.NodeId) + .InnerJoin() + .On((rel, content) => rel.NodeId == content.NodeId) .WhereIn(x => x.ContentTypeId, contentTypeIds); sqlSelectTagsToDelete @@ -928,7 +998,8 @@ AND umbracoNode.id <> @id", /// The target language (can be null ie invariant) /// The property type identifiers. /// The content type identifiers. - private void CopyPropertyData(int? sourceLanguageId, int? targetLanguageId, IReadOnlyCollection propertyTypeIds, IReadOnlyCollection contentTypeIds = null) + private void CopyPropertyData(int? sourceLanguageId, int? targetLanguageId, + IReadOnlyCollection propertyTypeIds, IReadOnlyCollection? contentTypeIds = null) { // note: important to use SqlNullableEquals for nullable types, cannot directly compare language identifiers // @@ -947,13 +1018,14 @@ AND umbracoNode.id <> @id", // .InnerJoin().On((pdata, cversion) => pdata.VersionId == cversion.Id) // .InnerJoin().On((cversion, c) => cversion.NodeId == c.NodeId); - Sql inSql = null; + Sql? inSql = null; if (contentTypeIds != null) { inSql = Sql() .Select(x => x.Id) .From() - .InnerJoin().On((cversion, c) => cversion.NodeId == c.NodeId) + .InnerJoin() + .On((cversion, c) => cversion.NodeId == c.NodeId) .WhereIn(x => x.ContentTypeId, contentTypeIds); sqlDelete.WhereIn(x => x.VersionId, inSql); } @@ -972,15 +1044,20 @@ AND umbracoNode.id <> @id", //now insert all property data into the target language that exists under the source language var targetLanguageIdS = targetLanguageId.HasValue ? targetLanguageId.ToString() : "NULL"; - var cols = Sql().Columns(x => x.VersionId, x => x.PropertyTypeId, x => x.Segment, x => x.IntegerValue, x => x.DecimalValue, x => x.DateValue, x => x.VarcharValue, x => x.TextValue, x => x.LanguageId); - var sqlSelectData = Sql().Select(x => x.VersionId, x => x.PropertyTypeId, x => x.Segment, x => x.IntegerValue, x => x.DecimalValue, x => x.DateValue, x => x.VarcharValue, x => x.TextValue) + var cols = Sql().Columns(x => x.VersionId, x => x.PropertyTypeId, x => x.Segment, + x => x.IntegerValue, x => x.DecimalValue, x => x.DateValue, x => x.VarcharValue, x => x.TextValue, + x => x.LanguageId); + var sqlSelectData = Sql().Select(x => x.VersionId, x => x.PropertyTypeId, x => x.Segment, + x => x.IntegerValue, x => x.DecimalValue, x => x.DateValue, x => x.VarcharValue, x => x.TextValue) .Append(", " + targetLanguageIdS) //default language ID .From(); if (contentTypeIds != null) sqlSelectData - .InnerJoin().On((pdata, cversion) => pdata.VersionId == cversion.Id) - .InnerJoin().On((cversion, c) => cversion.NodeId == c.NodeId); + .InnerJoin() + .On((pdata, cversion) => pdata.VersionId == cversion.Id) + .InnerJoin() + .On((cversion, c) => cversion.NodeId == c.NodeId); sqlSelectData.Where(x => x.LanguageId.SqlNullableEquals(sourceLanguageId, -1)); @@ -1011,7 +1088,6 @@ AND umbracoNode.id <> @id", Database.Execute(sqlDelete); } - } /// @@ -1024,7 +1100,8 @@ AND umbracoNode.id <> @id", /// if the property was changed to invariant. In order to do this we need to recalculate this value based on the values stored for each /// property, culture and current/published version. /// - private void RenormalizeDocumentEditedFlags(IReadOnlyCollection propertyTypeIds, IReadOnlyCollection contentTypeIds = null) + private void RenormalizeDocumentEditedFlags(IReadOnlyCollection propertyTypeIds, + IReadOnlyCollection? contentTypeIds = null) { var defaultLang = LanguageRepository.GetDefaultId(); @@ -1041,16 +1118,21 @@ AND umbracoNode.id <> @id", .AndSelect(x => x.Published) .AndSelect(x => x.Variations) .From() - .InnerJoin().On((left, right) => left.Id == right.VersionId) - .InnerJoin().On((left, right) => left.Id == right.PropertyTypeId); + .InnerJoin() + .On((left, right) => left.Id == right.VersionId) + .InnerJoin() + .On((left, right) => left.Id == right.PropertyTypeId); if (contentTypeIds != null) { - propertySql.InnerJoin().On((c, cversion) => c.NodeId == cversion.NodeId); + propertySql.InnerJoin() + .On((c, cversion) => c.NodeId == cversion.NodeId); } - propertySql.LeftJoin().On((docversion, cversion) => cversion.Id == docversion.Id) - .Where((docversion, cversion) => cversion.Current || docversion.Published) + propertySql.LeftJoin() + .On((docversion, cversion) => cversion.Id == docversion.Id) + .Where((docversion, cversion) => + cversion.Current || docversion.Published) .WhereIn(x => x.PropertyTypeId, propertyTypeIds); if (contentTypeIds != null) @@ -1069,7 +1151,7 @@ AND umbracoNode.id <> @id", var nodeId = -1; var propertyTypeId = -1; - PropertyValueVersionDto pubRow = null; + PropertyValueVersionDto? pubRow = null; //This is a reader (Query), we are not fetching this all into memory so we cannot make any changes during this iteration, we are just collecting data. //Published data will always come before Current data based on the version id sort. @@ -1100,7 +1182,9 @@ AND umbracoNode.id <> @id", editedLanguageVersions.Add((row.NodeId, row.LanguageId), false); //mark as false if the item doesn't exist, else coerce to true - editedDocument[row.NodeId] = editedDocument.TryGetValue(row.NodeId, out var edited) ? (edited |= false) : false; + editedDocument[row.NodeId] = editedDocument.TryGetValue(row.NodeId, out var edited) + ? (edited |= false) + : false; } else if (pubRow == null) { @@ -1112,7 +1196,8 @@ AND umbracoNode.id <> @id", else if (IsPropertyValueChanged(pubRow, row)) { //Here we would check if the property is invariant, in which case the edited language should be indicated by the default lang - editedLanguageVersions[(row.NodeId, !propVariations.VariesByCulture() ? defaultLang : row.LanguageId)] = true; + editedLanguageVersions[ + (row.NodeId, !propVariations.VariesByCulture() ? defaultLang : row.LanguageId)] = true; editedDocument[row.NodeId] = true; } @@ -1134,7 +1219,8 @@ AND umbracoNode.id <> @id", return Database.Fetch(sql); }) - .ToDictionary(x => (x.NodeId, (int?)x.LanguageId), x => x); //convert to dictionary with the same key type + .ToDictionary(x => (x.NodeId, (int?)x.LanguageId), + x => x); //convert to dictionary with the same key type var toUpdate = new List(); foreach (var ev in editedLanguageVersions) @@ -1151,7 +1237,8 @@ AND umbracoNode.id <> @id", else if (ev.Key.langId.HasValue) { //This should never happen! If a property culture is flagged as edited then the culture must exist at the document level - throw new PanicException($"The existing DocumentCultureVariationDto was not found for node {ev.Key.nodeId} and language {ev.Key.langId}"); + throw new PanicException( + $"The existing DocumentCultureVariationDto was not found for node {ev.Key.nodeId} and language {ev.Key.langId}"); } } @@ -1173,10 +1260,10 @@ AND umbracoNode.id <> @id", private static bool IsPropertyValueChanged(PropertyValueVersionDto pubRow, PropertyValueVersionDto row) { return !pubRow.TextValue.IsNullOrWhiteSpace() && pubRow.TextValue != row.TextValue - || !pubRow.VarcharValue.IsNullOrWhiteSpace() && pubRow.VarcharValue != row.VarcharValue - || pubRow.DateValue.HasValue && pubRow.DateValue != row.DateValue - || pubRow.DecimalValue.HasValue && pubRow.DecimalValue != row.DecimalValue - || pubRow.IntValue.HasValue && pubRow.IntValue != row.IntValue; + || !pubRow.VarcharValue.IsNullOrWhiteSpace() && pubRow.VarcharValue != row.VarcharValue + || pubRow.DateValue.HasValue && pubRow.DateValue != row.DateValue + || pubRow.DecimalValue.HasValue && pubRow.DecimalValue != row.DecimalValue + || pubRow.IntValue.HasValue && pubRow.IntValue != row.IntValue; } private class NameCompareDto @@ -1184,8 +1271,8 @@ AND umbracoNode.id <> @id", public int NodeId { get; set; } public int CurrentVersion { get; set; } public int LanguageId { get; set; } - public string CurrentName { get; set; } - public string PublishedName { get; set; } + public string? CurrentName { get; set; } + public string? PublishedName { get; set; } public int? PublishedVersion { get; set; } public int Id { get; set; } // the Id of the DocumentCultureVariationDto public bool Edited { get; set; } @@ -1196,10 +1283,11 @@ AND umbracoNode.id <> @id", public int VersionId { get; set; } public int PropertyTypeId { get; set; } public int? LanguageId { get; set; } - public string Segment { get; set; } + public string? Segment { get; set; } public int? IntValue { get; set; } private decimal? _decimalValue; + [Column("decimalValue")] public decimal? DecimalValue { @@ -1208,8 +1296,8 @@ AND umbracoNode.id <> @id", } public DateTime? DateValue { get; set; } - public string VarcharValue { get; set; } - public string TextValue { get; set; } + public string? VarcharValue { get; set; } + public string? TextValue { get; set; } public int NodeId { get; set; } public bool Current { get; set; } @@ -1221,21 +1309,23 @@ AND umbracoNode.id <> @id", private void DeletePropertyType(int contentTypeId, int propertyTypeId) { // first clear dependencies - Database.Delete("WHERE propertyTypeId = @Id", new { Id = propertyTypeId }); - Database.Delete("WHERE propertyTypeId = @Id", new { Id = propertyTypeId }); + Database.Delete("WHERE propertyTypeId = @Id", new {Id = propertyTypeId}); + Database.Delete("WHERE propertyTypeId = @Id", new {Id = propertyTypeId}); // then delete the property type Database.Delete("WHERE contentTypeId = @Id AND id = @PropertyTypeId", - new { Id = contentTypeId, PropertyTypeId = propertyTypeId }); + new {Id = contentTypeId, PropertyTypeId = propertyTypeId}); } protected void ValidateAlias(IPropertyType pt) { if (string.IsNullOrWhiteSpace(pt.Alias)) { - var ex = new InvalidOperationException($"Property Type '{pt.Name}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias."); + var ex = new InvalidOperationException( + $"Property Type '{pt.Name}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias."); - Logger.LogError("Property Type '{PropertyTypeName}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.", + Logger.LogError( + "Property Type '{PropertyTypeName}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.", pt.Name); throw ex; @@ -1246,9 +1336,11 @@ AND umbracoNode.id <> @id", { if (string.IsNullOrWhiteSpace(entity.Alias)) { - var ex = new InvalidOperationException($"{typeof(TEntity).Name} '{entity.Name}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias."); + var ex = new InvalidOperationException( + $"{typeof(TEntity).Name} '{entity.Name}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias."); - Logger.LogError("{EntityTypeName} '{EntityName}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.", + Logger.LogError( + "{EntityTypeName} '{EntityName}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.", typeof(TEntity).Name, entity.Name); @@ -1269,7 +1361,8 @@ AND umbracoNode.id <> @id", .Select(dt => dt.Select(x => x.NodeDto)) .From() .InnerJoin().On((dt, n) => dt.NodeId == n.NodeId) - .Where("propertyEditorAlias = @propertyEditorAlias", new { propertyEditorAlias = propertyType.PropertyEditorAlias }) + .Where("propertyEditorAlias = @propertyEditorAlias", + new {propertyEditorAlias = propertyType.PropertyEditorAlias}) .OrderBy(typeDto => typeDto.NodeId); var datatype = Database.FirstOrDefault(sql); //we cannot assign a data type if one was not found @@ -1280,14 +1373,16 @@ AND umbracoNode.id <> @id", } else { - Logger.LogWarning("Could not assign a data type for the property type {PropertyTypeAlias} since no data type was found with a property editor {PropertyEditorAlias}", propertyType.Alias, propertyType.PropertyEditorAlias); + Logger.LogWarning( + "Could not assign a data type for the property type {PropertyTypeAlias} since no data type was found with a property editor {PropertyEditorAlias}", + propertyType.Alias, propertyType.PropertyEditorAlias); } } } - protected abstract TEntity PerformGet(Guid id); - protected abstract TEntity PerformGet(string alias); - protected abstract IEnumerable PerformGetAll(params Guid[] ids); + protected abstract TEntity? PerformGet(Guid id); + protected abstract TEntity? PerformGet(string alias); + protected abstract IEnumerable? PerformGetAll(params Guid[]? ids); protected abstract bool PerformExists(Guid id); /// @@ -1295,7 +1390,7 @@ AND umbracoNode.id <> @id", /// /// /// - public TEntity Get(string alias) + public TEntity? Get(string alias) { return PerformGet(alias); } @@ -1305,7 +1400,7 @@ AND umbracoNode.id <> @id", /// /// /// - public TEntity Get(Guid id) + public TEntity? Get(Guid id) { return PerformGet(id); } @@ -1318,7 +1413,7 @@ AND umbracoNode.id <> @id", /// /// Ensure explicit implementation, we don't want to have any accidental calls to this since it is essentially the same signature as the main GetAll when there are no parameters /// - IEnumerable IReadRepository.GetMany(params Guid[] ids) + IEnumerable? IReadRepository.GetMany(params Guid[]? ids) { return PerformGetAll(ids); } @@ -1340,7 +1435,7 @@ AND umbracoNode.id <> @id", var aliases = Database.Fetch(@"SELECT cmsContentType." + aliasColumn + @" FROM cmsContentType INNER JOIN umbracoNode ON cmsContentType.nodeId = umbracoNode.id WHERE cmsContentType." + aliasColumn + @" LIKE @pattern", - new { pattern = alias + "%", objectType = NodeObjectTypeId }); + new {pattern = alias + "%", objectType = NodeObjectTypeId}); var i = 1; string test; while (aliases.Contains(test = alias + i)) i++; @@ -1350,7 +1445,8 @@ WHERE cmsContentType." + aliasColumn + @" LIKE @pattern", /// public bool HasContainerInPath(string contentPath) { - var ids = contentPath.Split(Constants.CharArrays.Comma).Select(s => int.Parse(s, CultureInfo.InvariantCulture)).ToArray(); + var ids = contentPath.Split(Constants.CharArrays.Comma) + .Select(s => int.Parse(s, CultureInfo.InvariantCulture)).ToArray(); return HasContainerInPath(ids); } @@ -1359,7 +1455,8 @@ WHERE cmsContentType." + aliasColumn + @" LIKE @pattern", { var sql = new Sql($@"SELECT COUNT(*) FROM cmsContentType INNER JOIN {Cms.Core.Constants.DatabaseSchema.Tables.Content} ON cmsContentType.nodeId={Cms.Core.Constants.DatabaseSchema.Tables.Content}.contentTypeId -WHERE {Cms.Core.Constants.DatabaseSchema.Tables.Content}.nodeId IN (@ids) AND cmsContentType.isContainer=@isContainer", new { ids, isContainer = true }); +WHERE {Cms.Core.Constants.DatabaseSchema.Tables.Content}.nodeId IN (@ids) AND cmsContentType.isContainer=@isContainer", + new {ids, isContainer = true}); return Database.ExecuteScalar(sql) > 0; } @@ -1370,7 +1467,7 @@ WHERE {Cms.Core.Constants.DatabaseSchema.Tables.Content}.nodeId IN (@ids) AND cm { var sql = new Sql( $"SELECT CASE WHEN EXISTS (SELECT * FROM {Cms.Core.Constants.DatabaseSchema.Tables.Content} WHERE contentTypeId = @id) THEN 1 ELSE 0 END", - new { id }); + new {id}); return Database.ExecuteScalar(sql) == 1; } @@ -1390,9 +1487,12 @@ WHERE {Cms.Core.Constants.DatabaseSchema.Tables.Content}.nodeId IN (@ids) AND cm "DELETE FROM cmsContentTypeAllowedContentType WHERE AllowedId = @id", "DELETE FROM cmsContentType2ContentType WHERE parentContentTypeId = @id", "DELETE FROM cmsContentType2ContentType WHERE childContentTypeId = @id", - "DELETE FROM " + Cms.Core.Constants.DatabaseSchema.Tables.PropertyData + " WHERE propertyTypeId IN (SELECT id FROM cmsPropertyType WHERE contentTypeId = @id)", - "DELETE FROM " + Cms.Core.Constants.DatabaseSchema.Tables.PropertyType + " WHERE contentTypeId = @id", - "DELETE FROM " + Cms.Core.Constants.DatabaseSchema.Tables.PropertyTypeGroup + " WHERE contenttypeNodeId = @id" + "DELETE FROM " + Cms.Core.Constants.DatabaseSchema.Tables.PropertyData + + " WHERE propertyTypeId IN (SELECT id FROM cmsPropertyType WHERE contentTypeId = @id)", + "DELETE FROM " + Cms.Core.Constants.DatabaseSchema.Tables.PropertyType + + " WHERE contentTypeId = @id", + "DELETE FROM " + Cms.Core.Constants.DatabaseSchema.Tables.PropertyTypeGroup + + " WHERE contenttypeNodeId = @id" }; return list; } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/CreatedPackageSchemaRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/CreatedPackageSchemaRepository.cs index 462ae0a64e..e3dd6a9d68 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/CreatedPackageSchemaRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/CreatedPackageSchemaRepository.cs @@ -25,7 +25,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement public class CreatedPackageSchemaRepository : ICreatedPackagesRepository { private readonly PackageDefinitionXmlParser _xmlParser; - private readonly IUmbracoDatabase _umbracoDatabase; + private readonly IUmbracoDatabase? _umbracoDatabase; private readonly IHostingEnvironment _hostingEnvironment; private readonly FileSystems _fileSystems; private readonly IEntityXmlSerializer _serializer; @@ -59,8 +59,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement MediaFileManager mediaFileManager, IMacroService macroService, IContentTypeService contentTypeService, - string mediaFolderPath = null, - string tempFolderPath = null) + string? mediaFolderPath = null, + string? tempFolderPath = null) { _umbracoDatabase = umbracoDatabaseFactory.CreateDatabase(); _hostingEnvironment = hostingEnvironment; @@ -83,7 +83,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement public IEnumerable GetAll() { - Sql query = new Sql(_umbracoDatabase.SqlContext) + Sql query = new Sql(_umbracoDatabase!.SqlContext) .Select() .From() .OrderBy(x => x.Id); @@ -94,18 +94,21 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement foreach (CreatedPackageSchemaDto packageSchema in xmlSchemas) { var packageDefinition = _xmlParser.ToPackageDefinition(XElement.Parse(packageSchema.Value)); - packageDefinition.Id = packageSchema.Id; - packageDefinition.Name = packageSchema.Name; - packageDefinition.PackageId = packageSchema.PackageId; - packageDefinitions.Add(packageDefinition); + if (packageDefinition is not null) + { + packageDefinition.Id = packageSchema.Id; + packageDefinition.Name = packageSchema.Name; + packageDefinition.PackageId = packageSchema.PackageId; + packageDefinitions.Add(packageDefinition); + } } return packageDefinitions; } - public PackageDefinition GetById(int id) + public PackageDefinition? GetById(int id) { - Sql query = new Sql(_umbracoDatabase.SqlContext) + Sql query = new Sql(_umbracoDatabase!.SqlContext) .Select() .From() .Where(x => x.Id == id); @@ -118,9 +121,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var packageSchema = schemaDtos.First(); var packageDefinition = _xmlParser.ToPackageDefinition(XElement.Parse(packageSchema.Value)); - packageDefinition.Id = packageSchema.Id; - packageDefinition.Name = packageSchema.Name; - packageDefinition.PackageId = packageSchema.PackageId; + if (packageDefinition is not null) + { + packageDefinition.Id = packageSchema.Id; + packageDefinition.Name = packageSchema.Name; + packageDefinition.PackageId = packageSchema.PackageId; + } + return packageDefinition; } @@ -128,12 +135,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { // Delete package snapshot var packageDef = GetById(id); - if (File.Exists(packageDef.PackagePath)) + if (File.Exists(packageDef?.PackagePath)) { File.Delete(packageDef.PackagePath); } - Sql query = new Sql(_umbracoDatabase.SqlContext) + Sql query = new Sql(_umbracoDatabase!.SqlContext) .Delete() .Where(x => x.Id == id); @@ -169,7 +176,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // Set the ids, we have to save in database first to get the Id definition.PackageId = dto.PackageId; - var result = _umbracoDatabase.Insert(dto); + var result = _umbracoDatabase!.Insert(dto); var decimalResult = result.SafeCast(); definition.Id = decimal.ToInt32(decimalResult); } @@ -185,7 +192,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement PackageId = definition.PackageId, UpdateDate = DateTime.Now }; - _umbracoDatabase.Update(updatedDto); + _umbracoDatabase?.Update(updatedDto); return true; } @@ -217,9 +224,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement PackageMediaTypes(definition, root); PackageTemplates(definition, root); PackageStylesheets(definition, root); - PackageStaticFiles(definition.Scripts, root, "Scripts", "Script", _fileSystems.ScriptsFileSystem); + PackageStaticFiles(definition.Scripts, root, "Scripts", "Script", _fileSystems.ScriptsFileSystem!); PackageStaticFiles(definition.PartialViews, root, "PartialViews", "View", - _fileSystems.PartialViewsFileSystem); + _fileSystems.PartialViewsFileSystem!); PackageMacros(definition, root); PackageDictionaryItems(definition, root); PackageLanguages(definition, root); @@ -329,7 +336,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement continue; } - IDataType dataType = _dataTypeService.GetDataType(outInt); + IDataType? dataType = _dataTypeService.GetDataType(outInt); if (dataType == null) { continue; @@ -351,7 +358,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement continue; } - ILanguage lang = _localizationService.GetLanguageById(outInt); + ILanguage? lang = _localizationService.GetLanguageById(outInt); if (lang == null) { continue; @@ -375,7 +382,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement continue; } - IDictionaryItem di = _localizationService.GetDictionaryItemById(outInt); + IDictionaryItem? di = _localizationService.GetDictionaryItemById(outInt); if (di == null) { @@ -452,14 +459,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement continue; } - XElement macroXml = GetMacroXml(outInt, out IMacro macro); - if (macroXml == null) + XElement? macroXml = GetMacroXml(outInt, out IMacro? macro); + if (macroXml is null) { continue; } macros.Add(macroXml); - packagedMacros.Add(macro); + packagedMacros.Add(macro!); } root.Add(macros); @@ -469,7 +476,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .Where(x => x.MacroSource.StartsWith(Constants.SystemDirectories.MacroPartials)) .Select(x => x.MacroSource.Substring(Constants.SystemDirectories.MacroPartials.Length).Replace('/', '\\')); - PackageStaticFiles(views, root, "MacroPartialViews", "View", _fileSystems.MacroPartialsFileSystem); + PackageStaticFiles(views, root, "MacroPartialViews", "View", _fileSystems.MacroPartialsFileSystem!); } private void PackageStylesheets(PackageDefinition definition, XContainer root) @@ -482,7 +489,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement continue; } - XElement xml = GetStylesheetXml(stylesheet, true); + XElement? xml = GetStylesheetXml(stylesheet, true); if (xml != null) { stylesheetsXml.Add(xml); @@ -512,15 +519,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement throw new InvalidOperationException("No file found with path " + file); } - using (Stream stream = fileSystem.OpenFile(file)) - using (var reader = new StreamReader(stream)) + using Stream? stream = fileSystem.OpenFile(file); + if (stream is not null) { - var fileContents = reader.ReadToEnd(); - scriptsXml.Add( - new XElement( - elementName, - new XAttribute("path", file), - new XCData(fileContents))); + using (var reader = new StreamReader(stream)) + { + var fileContents = reader.ReadToEnd(); + scriptsXml.Add( + new XElement( + elementName, + new XAttribute("path", file), + new XCData(fileContents))); + } } } @@ -537,7 +547,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement continue; } - ITemplate template = _fileService.GetTemplate(outInt); + ITemplate? template = _fileService.GetTemplate(outInt); if (template == null) { continue; @@ -560,7 +570,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement continue; } - IContentType contentType = _contentTypeService.Get(outInt); + IContentType? contentType = _contentTypeService.Get(outInt); if (contentType == null) { continue; @@ -588,7 +598,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement continue; } - IMediaType mediaType = _mediaTypeService.Get(outInt); + IMediaType? mediaType = _mediaTypeService.Get(outInt); if (mediaType == null) { continue; @@ -614,7 +624,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement if (contentNodeId > 0) { // load content from umbraco. - IContent content = _contentService.GetById(contentNodeId); + IContent? content = _contentService.GetById(contentNodeId); if (content != null) { var contentXml = definition.ContentLoadChildNodes @@ -645,13 +655,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // get the media file path and store that separately in the XML. // the media file path is different from the URL and is specifically // extracted using the property editor for this media file and the current media file system. - Stream mediaStream = _mediaFileManager.GetFile(media, out var mediaFilePath); + Stream? mediaStream = _mediaFileManager.GetFile(media, out var mediaFilePath); if (mediaStream != null) { - xmlMedia.Add(new XAttribute("mediaFilePath", mediaFilePath)); + xmlMedia.Add(new XAttribute("mediaFilePath", mediaFilePath!)); // add the stream to our outgoing stream - mediaStreams.Add(mediaFilePath, mediaStream); + mediaStreams.Add(mediaFilePath!, mediaStream); } } @@ -677,7 +687,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Gets a macros xml node /// - private XElement GetMacroXml(int macroId, out IMacro macro) + private XElement? GetMacroXml(int macroId, out IMacro? macro) { macro = _macroService.GetById(macroId); if (macro == null) @@ -694,14 +704,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// The path of the stylesheet. /// if set to true [include properties]. - private XElement GetStylesheetXml(string path, bool includeProperties) + private XElement? GetStylesheetXml(string path, bool includeProperties) { if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("Value cannot be null or whitespace.", nameof(path)); } - IStylesheet stylesheet = _fileService.GetStylesheet(path); + IStylesheet? stylesheet = _fileService.GetStylesheet(path); if (stylesheet == null) { return null; @@ -714,7 +724,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { if (dt.ParentId > 0) { - IContentType parent = _contentTypeService.Get(dt.ParentId); + IContentType? parent = _contentTypeService.Get(dt.ParentId); if (parent != null) { AddDocumentType(parent, dtl); @@ -731,7 +741,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { if (mediaType.ParentId > 0) { - IMediaType parent = _mediaTypeService.Get(mediaType.ParentId); + IMediaType? parent = _mediaTypeService.Get(mediaType.ParentId); if (parent != null) { AddMediaType(parent, mediaTypes); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs index 954d3e0d0f..9425de1b36 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; @@ -49,16 +50,16 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Overrides of RepositoryBase - protected override IDataType PerformGet(int id) + protected override IDataType? PerformGet(int id) { - return GetMany(id).FirstOrDefault(); + return GetMany(id)?.FirstOrDefault(); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { var dataTypeSql = GetBaseQuery(false); - if (ids.Any()) + if (ids?.Any() ?? false) { dataTypeSql.Where("umbracoNode.id in (@ids)", new { ids }); } @@ -123,7 +124,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement entity.AddingEntity(); //ensure a datatype has a unique name before creating it - entity.Name = EnsureUniqueNodeName(entity.Name); + entity.Name = EnsureUniqueNodeName(entity.Name)!; // TODO: should the below be removed? //Cannot add a duplicate data type @@ -173,7 +174,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected override void PersistUpdatedItem(IDataType entity) { - entity.Name = EnsureUniqueNodeName(entity.Name, entity.Id); + entity.Name = EnsureUniqueNodeName(entity.Name, entity.Id)!; //Cannot change to a duplicate alias var existsSql = Sql() @@ -244,7 +245,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #endregion - public IEnumerable> Move(IDataType toMove, EntityContainer container) + public IEnumerable> Move(IDataType toMove, EntityContainer? container) { var parentId = -1; if (container != null) @@ -278,15 +279,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var descendants = Get(Query().Where(type => type.Path.StartsWith(origPath + ","))); var lastParent = toMove; - foreach (var descendant in descendants.OrderBy(x => x.Level)) + if (descendants is not null) { - moveInfo.Add(new MoveEventInfo(descendant, descendant.Path, descendant.ParentId)); + foreach (var descendant in descendants.OrderBy(x => x.Level)) + { + moveInfo.Add(new MoveEventInfo(descendant, descendant.Path, descendant.ParentId)); - descendant.ParentId = lastParent.Id; - descendant.Path = string.Concat(lastParent.Path, ",", descendant.Id); + descendant.ParentId = lastParent.Id; + descendant.Path = string.Concat(lastParent.Path, ",", descendant.Id); - //schedule it for updating in the transaction - Save(descendant); + //schedule it for updating in the transaction + Save(descendant); + } } return moveInfo; @@ -310,11 +314,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var dtos = Database.FetchOneToMany(ct => ct.PropertyTypes, sql); return dtos.ToDictionary( - x => (Udi)new GuidUdi(ObjectTypes.GetUdiType(x.NodeDto.NodeObjectType.Value), x.NodeDto.UniqueId).EnsureClosed(), + x => (Udi)new GuidUdi(ObjectTypes.GetUdiType(x.NodeDto.NodeObjectType!.Value), x.NodeDto.UniqueId).EnsureClosed(), x => (IEnumerable)x.PropertyTypes.Select(p => p.Alias).ToList()); } - private string EnsureUniqueNodeName(string nodeName, int id = 0) + private string? EnsureUniqueNodeName(string nodeName, int id = 0) { var template = SqlContext.Templates.Get(Cms.Core.Constants.SqlTemplates.DataTypeRepository.EnsureUniqueNodeName, tsql => tsql .Select(x => Alias(x.NodeId, "id"), x => Alias(x.Text, "name")) @@ -333,17 +337,17 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { [ResultColumn] [Reference(ReferenceType.Many)] - public List PropertyTypes { get; set; } + public List PropertyTypes { get; set; } = null!; } [TableName(Cms.Core.Constants.DatabaseSchema.Tables.PropertyType)] private class PropertyTypeReferenceDto { [Column("ptAlias")] - public string Alias { get; set; } + public string? Alias { get; set; } [Column("ptName")] - public string Name { get; set; } + public string? Name { get; set; } } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs index 98b1820204..7f39bb3ee6 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs @@ -43,7 +43,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Overrides of RepositoryBase - protected override IDictionaryItem PerformGet(int id) + protected override IDictionaryItem? PerformGet(int id) { var sql = GetBaseQuery(false) .Where(GetBaseWhereClause(), new { id = id }) @@ -64,10 +64,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return entity; } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { var sql = GetBaseQuery(false).Where(x => x.PrimaryKey > 0); - if (ids.Any()) + if (ids?.Any() ?? false) { sql.WhereIn(x => x.PrimaryKey, ids); } @@ -225,19 +225,19 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return entity; } - public IDictionaryItem Get(Guid uniqueId) + public IDictionaryItem? Get(Guid uniqueId) { var uniqueIdRepo = new DictionaryByUniqueIdRepository(this, ScopeAccessor, AppCaches, _loggerFactory.CreateLogger()); return uniqueIdRepo.Get(uniqueId); } - public IDictionaryItem Get(string key) + public IDictionaryItem? Get(string key) { var keyRepo = new DictionaryByKeyRepository(this, ScopeAccessor, AppCaches, _loggerFactory.CreateLogger()); return keyRepo.Get(key); } - private IEnumerable GetRootDictionaryItems() + private IEnumerable? GetRootDictionaryItems() { var query = Query().Where(x => x.ParentId == null); return Get(query); @@ -252,7 +252,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private class DictionaryItemKeyIdDto { - public string Key { get; set; } + public string Key { get; set; } = null!; public Guid Id { get; set; } } @@ -281,7 +281,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement }; var childItems = parentId.HasValue == false - ? new[] { GetRootDictionaryItems() } + ? new[] { GetRootDictionaryItems()! } : getItemsFromParents(new[] { parentId.Value }); return childItems.SelectRecursive(items => getItemsFromParents(items.Select(x => x.Key).ToArray())).SelectMany(items => items); @@ -372,7 +372,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return _dictionaryRepository.ConvertFromDto(dto); } - protected override object GetBaseWhereClauseArguments(string id) + protected override object GetBaseWhereClauseArguments(string? id) { return new { id = id }; } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs index 0d77f3d53b..630620901a 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs @@ -37,7 +37,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private readonly IJsonSerializer _serializer; private readonly AppCaches _appCaches; private readonly ILoggerFactory _loggerFactory; - private PermissionRepository _permissionRepository; + private PermissionRepository? _permissionRepository; private readonly ContentByGuidReadRepository _contentByGuidReadRepository; private readonly IScopeAccessor _scopeAccessor; @@ -98,7 +98,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected override Guid NodeObjectTypeId => Cms.Core.Constants.ObjectTypes.Document; - protected override IContent PerformGet(int id) + protected override IContent? PerformGet(int id) { var sql = GetBaseQuery(QueryType.Single) .Where(x => x.NodeId == id) @@ -110,11 +110,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement : MapDtoToContent(dto); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { var sql = GetBaseQuery(QueryType.Many); - if (ids.Any()) + if (ids?.Any() ?? false) sql.WhereIn(x => x.NodeId, ids); return MapDtosToContent(Database.Fetch(sql)); @@ -301,7 +301,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement false, false, true); } - public override IContent GetVersion(int versionId) + public override IContent? GetVersion(int versionId) { var sql = GetBaseQuery(QueryType.Single, false) .Where(x => x.Id == versionId); @@ -456,7 +456,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } // persist the property data - IEnumerable propertyDataDtos = PropertyFactory.BuildDtos(entity.ContentType.Variations, entity.VersionId, entity.PublishedVersionId, entity.Properties, LanguageRepository, out var edited, out HashSet editedCultures); + IEnumerable propertyDataDtos = PropertyFactory.BuildDtos(entity.ContentType.Variations, entity.VersionId, entity.PublishedVersionId, entity.Properties, LanguageRepository, out var edited, out HashSet? editedCultures); foreach (PropertyDataDto propertyDataDto in propertyDataDtos) { Database.Insert(propertyDataDto); @@ -486,7 +486,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { // names also impact 'edited' // ReSharper disable once UseDeconstruction - foreach (ContentCultureInfos cultureInfo in entity.CultureInfos) + foreach (ContentCultureInfos cultureInfo in entity.CultureInfos!) { if (cultureInfo.Name != entity.GetPublishName(cultureInfo.Culture)) { @@ -495,7 +495,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } // refresh content - entity.SetCultureEdited(editedCultures); + entity.SetCultureEdited(editedCultures!); // bump dates to align cultures to version entity.AdjustDates(contentVersionDto.VersionDate, publishing); @@ -504,7 +504,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement Database.BulkInsertRecords(GetContentVariationDtos(entity, publishing)); // insert document variations - Database.BulkInsertRecords(GetDocumentVariationDtos(entity, editedCultures)); + Database.BulkInsertRecords(GetDocumentVariationDtos(entity, editedCultures!)); } // trigger here, before we reset Published etc @@ -657,7 +657,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var versionToDelete = publishing ? entity.PublishedVersionId : entity.VersionId; // insert property data - ReplacePropertyValues(entity, versionToDelete, publishing ? entity.PublishedVersionId : 0, out var edited, out HashSet editedCultures); + ReplacePropertyValues(entity, versionToDelete, publishing ? entity.PublishedVersionId : 0, out var edited, out HashSet? editedCultures); // if !publishing, we may have a new name != current publish name, // also impacts 'edited' @@ -683,7 +683,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { // names also impact 'edited' // ReSharper disable once UseDeconstruction - foreach (var cultureInfo in entity.CultureInfos) + foreach (var cultureInfo in entity.CultureInfos!) { if (cultureInfo.Name != entity.GetPublishName(cultureInfo.Culture)) { @@ -699,7 +699,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } // refresh content - entity.SetCultureEdited(editedCultures); + entity.SetCultureEdited(editedCultures!); // bump dates to align cultures to version entity.AdjustDates(contentVersionDto.VersionDate, publishing); @@ -723,7 +723,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement Database.BulkInsertRecords(GetContentVariationDtos(entity, publishing)); // insert document variations - Database.BulkInsertRecords(GetDocumentVariationDtos(entity, editedCultures)); + Database.BulkInsertRecords(GetDocumentVariationDtos(entity, editedCultures!)); } // update the document dto @@ -857,7 +857,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Content Repository - public int CountPublished(string contentTypeAlias = null) + public int CountPublished(string? contentTypeAlias = null) { var sql = SqlContext.Sql(); if (contentTypeAlias.IsNullOrWhiteSpace()) @@ -918,11 +918,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } /// - public override IEnumerable GetPage(IQuery query, + public override IEnumerable GetPage(IQuery? query, long pageIndex, int pageSize, out long totalRecords, - IQuery filter, Ordering ordering) + IQuery? filter, Ordering? ordering) { - Sql filterSql = null; + Sql? filterSql = null; // if we have a filter, map its clauses to an Sql statement if (filter != null) @@ -954,17 +954,17 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement ordering); } - public bool IsPathPublished(IContent content) + public bool IsPathPublished(IContent? content) { // fail fast - if (content.Path.StartsWith("-1,-20,")) + if (content?.Path.StartsWith("-1,-20,") ?? false) return false; // succeed fast - if (content.ParentId == -1) + if (content?.ParentId == -1) return content.Published; - var ids = content.Path.Split(Constants.CharArrays.Comma).Skip(1).Select(s => int.Parse(s, CultureInfo.InvariantCulture)); + var ids = content?.Path.Split(Constants.CharArrays.Comma).Skip(1).Select(s => int.Parse(s, CultureInfo.InvariantCulture)); var sql = SqlContext.Sql() .SelectCount(x => x.NodeId) @@ -973,7 +973,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .WhereIn(x => x.NodeId, ids); var count = Database.ExecuteScalar(sql); - return count == content.Level; + return count == content?.Level; } #endregion @@ -995,12 +995,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Read Repository implementation for Guid keys - public IContent Get(Guid id) + public IContent? Get(Guid id) { return _contentByGuidReadRepository.Get(id); } - IEnumerable IReadRepository.GetMany(params Guid[] ids) + IEnumerable? IReadRepository.GetMany(params Guid[]? ids) { return _contentByGuidReadRepository.GetMany(ids); } @@ -1023,7 +1023,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement _outerRepo = outerRepo; } - protected override IContent PerformGet(Guid id) + protected override IContent? PerformGet(Guid id) { var sql = _outerRepo.GetBaseQuery(QueryType.Single) .Where(x => x.UniqueId == id); @@ -1038,10 +1038,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return content; } - protected override IEnumerable PerformGetAll(params Guid[] ids) + protected override IEnumerable PerformGetAll(params Guid[]? ids) { var sql = _outerRepo.GetBaseQuery(QueryType.Many); - if (ids.Length > 0) + if (ids?.Length > 0) sql.WhereIn(x => x.UniqueId, ids); return _outerRepo.MapDtosToContent(Database.Fetch(sql)); @@ -1219,7 +1219,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement bool loadVariants = true) { var temps = new List>(); - var contentTypes = new Dictionary(); + var contentTypes = new Dictionary(); var templateIds = new List(); var content = new Content[dtos.Count]; @@ -1275,15 +1275,15 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement temps.Add(temp); } - Dictionary templates = null; + Dictionary? templates = null; if (loadTemplates) { // load all required templates in 1 query, and index - templates = _templateRepository.GetMany(templateIds.ToArray()) + templates = _templateRepository.GetMany(templateIds.ToArray())? .ToDictionary(x => x.Id, x => x); } - IDictionary properties = null; + IDictionary? properties = null; if (loadProperties) { // load all properties for all documents from database in 1 query - indexed by version id @@ -1296,18 +1296,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement if (loadTemplates) { // set the template ID if it matches an existing template - if (temp.Template1Id.HasValue && templates.ContainsKey(temp.Template1Id.Value)) - temp.Content.TemplateId = temp.Template1Id; - if (temp.Template2Id.HasValue && templates.ContainsKey(temp.Template2Id.Value)) - temp.Content.PublishTemplateId = temp.Template2Id; + if (temp.Template1Id.HasValue && (templates?.ContainsKey(temp.Template1Id.Value) ?? false)) + temp.Content!.TemplateId = temp.Template1Id; + if (temp.Template2Id.HasValue && (templates?.ContainsKey(temp.Template2Id.Value) ?? false)) + temp.Content!.PublishTemplateId = temp.Template2Id; } // set properties if (loadProperties) { - if (properties.ContainsKey(temp.VersionId)) - temp.Content.Properties = properties[temp.VersionId]; + if (properties?.ContainsKey(temp.VersionId) ?? false) + temp.Content!.Properties = properties[temp.VersionId]; else throw new InvalidOperationException($"No property data found for version: '{temp.VersionId}'."); } @@ -1316,7 +1316,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement if (loadVariants) { // set variations, if varying - temps = temps.Where(x => x.ContentType.VariesByCulture()).ToList(); + temps = temps.Where(x => x.ContentType?.VariesByCulture() ?? false).ToList(); if (temps.Count > 0) { // load all variations for all documents from database, in one query @@ -1361,7 +1361,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement content.Properties = properties[dto.DocumentVersionDto.Id]; // set variations, if varying - if (contentType.VariesByCulture()) + if (contentType?.VariesByCulture() ?? false) { var contentVariations = GetContentVariations(ltemp); var documentVariations = GetDocumentVariations(ltemp); @@ -1401,8 +1401,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return result; } - private void SetVariations(Content content, IDictionary> contentVariations, IDictionary> documentVariations) + private void SetVariations(Content? content, IDictionary> contentVariations, IDictionary> documentVariations) { + if (content is null) + { + return; + } if (contentVariations.TryGetValue(content.VersionId, out var contentVariation)) foreach (var v in contentVariation) content.SetCultureInfo(v.Culture, v.Name, v.Date); @@ -1484,34 +1488,40 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private IEnumerable GetContentVariationDtos(IContent content, bool publishing) { - // create dtos for the 'current' (non-published) version, all cultures - // ReSharper disable once UseDeconstruction - foreach (var cultureInfo in content.CultureInfos) - yield return new ContentVersionCultureVariationDto - { - VersionId = content.VersionId, - LanguageId = LanguageRepository.GetIdByIsoCode(cultureInfo.Culture) ?? throw new InvalidOperationException("Not a valid culture."), - Culture = cultureInfo.Culture, - Name = cultureInfo.Name, - UpdateDate = content.GetUpdateDate(cultureInfo.Culture) ?? DateTime.MinValue // we *know* there is a value - }; + if (content.CultureInfos is not null) + { + // create dtos for the 'current' (non-published) version, all cultures + // ReSharper disable once UseDeconstruction + foreach (var cultureInfo in content.CultureInfos) + yield return new ContentVersionCultureVariationDto + { + VersionId = content.VersionId, + LanguageId = LanguageRepository.GetIdByIsoCode(cultureInfo.Culture) ?? throw new InvalidOperationException("Not a valid culture."), + Culture = cultureInfo.Culture, + Name = cultureInfo.Name, + UpdateDate = content.GetUpdateDate(cultureInfo.Culture) ?? DateTime.MinValue // we *know* there is a value + }; + } // if not publishing, we're just updating the 'current' (non-published) version, // so there are no DTOs to create for the 'published' version which remains unchanged if (!publishing) yield break; - // create dtos for the 'published' version, for published cultures (those having a name) - // ReSharper disable once UseDeconstruction - foreach (var cultureInfo in content.PublishCultureInfos) - yield return new ContentVersionCultureVariationDto - { - VersionId = content.PublishedVersionId, - LanguageId = LanguageRepository.GetIdByIsoCode(cultureInfo.Culture) ?? throw new InvalidOperationException("Not a valid culture."), - Culture = cultureInfo.Culture, - Name = cultureInfo.Name, - UpdateDate = content.GetPublishDate(cultureInfo.Culture) ?? DateTime.MinValue // we *know* there is a value - }; + if (content.PublishCultureInfos is not null) + { + // create dtos for the 'published' version, for published cultures (those having a name) + // ReSharper disable once UseDeconstruction + foreach (var cultureInfo in content.PublishCultureInfos) + yield return new ContentVersionCultureVariationDto + { + VersionId = content.PublishedVersionId, + LanguageId = LanguageRepository.GetIdByIsoCode(cultureInfo.Culture) ?? throw new InvalidOperationException("Not a valid culture."), + Culture = cultureInfo.Culture, + Name = cultureInfo.Name, + UpdateDate = content.GetPublishDate(cultureInfo.Culture) ?? DateTime.MinValue // we *know* there is a value + }; + } } private IEnumerable GetDocumentVariationDtos(IContent content, HashSet editedCultures) @@ -1540,14 +1550,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private class ContentVariation { - public string Culture { get; set; } - public string Name { get; set; } + public string? Culture { get; set; } + public string? Name { get; set; } public DateTime Date { get; set; } } private class DocumentVariation { - public string Culture { get; set; } + public string? Culture { get; set; } public bool Edited { get; set; } } @@ -1579,15 +1589,15 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { // content varies by culture // then it must have at least a variant name, else it makes no sense - if (content.CultureInfos.Count == 0) + if (content.CultureInfos?.Count == 0) throw new InvalidOperationException("Cannot save content with an empty name."); // and then, we need to set the invariant name implicitly, // using the default culture if it has a name, otherwise anything we can var defaultCulture = LanguageRepository.GetDefaultIsoCode(); - content.Name = defaultCulture != null && content.CultureInfos.TryGetValue(defaultCulture, out var cultureName) - ? cultureName.Name - : content.CultureInfos[0].Name; + content.Name = defaultCulture != null && (content.CultureInfos?.TryGetValue(defaultCulture, out var cultureName) ?? false) + ? cultureName.Name! + : content.CultureInfos![0].Name!; } else { @@ -1604,7 +1614,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected override string EnsureUniqueNodeName(int parentId, string nodeName, int id = 0) { - return EnsureUniqueNaming == false ? nodeName : base.EnsureUniqueNodeName(parentId, nodeName, id); + return EnsureUniqueNaming == false ? nodeName : base.EnsureUniqueNodeName(parentId, nodeName, id)!; } private SqlTemplate SqlEnsureVariantNamesAreUnique => SqlContext.Templates.Get("Umbraco.Core.DomainRepository.EnsureVariantNamesAreUnique", tsql => tsql @@ -1620,7 +1630,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private void EnsureVariantNamesAreUnique(IContent content, bool publishing) { - if (!EnsureUniqueNaming || !content.ContentType.VariesByCulture() || content.CultureInfos.Count == 0) + if (!EnsureUniqueNaming || !content.ContentType.VariesByCulture() || content.CultureInfos?.Count == 0) return; // get names per culture, at same level (ie all siblings) @@ -1636,6 +1646,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // of whether the name has changed (ie the culture has been updated) - some saving culture // fr-FR could cause culture en-UK name to change - not sure that is clean + if (content.CultureInfos is null) + { + return; + } foreach (var cultureInfo in content.CultureInfos) { var langId = LanguageRepository.GetIdByIsoCode(cultureInfo.Culture); @@ -1653,7 +1667,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // update the name, and the publish name if published content.SetCultureName(uniqueName, cultureInfo.Culture); - if (publishing && content.PublishCultureInfos.ContainsKey(cultureInfo.Culture)) + if (publishing && (content.PublishCultureInfos?.ContainsKey(cultureInfo.Culture) ?? false)) content.SetPublishInfo(cultureInfo.Culture, uniqueName, DateTime.Now); //TODO: This is weird, this call will have already been made in the SetCultureName } } @@ -1662,7 +1676,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private class CultureNodeName { public int Id { get; set; } - public string Name { get; set; } + public string? Name { get; set; } public int LanguageId { get; set; } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentVersionRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentVersionRepository.cs index 52b73bed26..aff71feb63 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentVersionRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentVersionRepository.cs @@ -25,11 +25,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// Never includes current published version.
/// Never includes versions marked as "preventCleanup".
/// - public IReadOnlyCollection GetDocumentVersionsEligibleForCleanup() + public IReadOnlyCollection? GetDocumentVersionsEligibleForCleanup() { - Sql query = _scopeAccessor.AmbientScope.SqlContext.Sql(); + Sql? query = _scopeAccessor.AmbientScope?.SqlContext.Sql(); - query.Select(@"umbracoDocument.nodeId as contentId, + query?.Select(@"umbracoDocument.nodeId as contentId, umbracoContent.contentTypeId as contentTypeId, umbracoContentVersion.id as versionId, umbracoContentVersion.userId as userId, @@ -51,26 +51,26 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .Where(x => !x.PreventCleanup) // Never delete "pinned" versions .Where(x => !x.Published); // Never delete published version - return _scopeAccessor.AmbientScope.Database.Fetch(query); + return _scopeAccessor.AmbientScope?.Database.Fetch(query); } /// - public IReadOnlyCollection GetCleanupPolicies() + public IReadOnlyCollection? GetCleanupPolicies() { - Sql query = _scopeAccessor.AmbientScope.SqlContext.Sql(); + Sql? query = _scopeAccessor.AmbientScope?.SqlContext.Sql(); - query.Select() + query?.Select() .From(); - return _scopeAccessor.AmbientScope.Database.Fetch(query); + return _scopeAccessor.AmbientScope?.Database.Fetch(query); } /// - public IEnumerable GetPagedItemsByContentId(int contentId, long pageIndex, int pageSize, out long totalRecords, int? languageId = null) + public IEnumerable? GetPagedItemsByContentId(int contentId, long pageIndex, int pageSize, out long totalRecords, int? languageId = null) { - Sql query = _scopeAccessor.AmbientScope.SqlContext.Sql(); + Sql? query = _scopeAccessor.AmbientScope?.SqlContext.Sql(); - query.Select(@"umbracoDocument.nodeId as contentId, + query?.Select(@"umbracoDocument.nodeId as contentId, umbracoContent.contentTypeId as contentTypeId, umbracoContentVersion.id as versionId, umbracoContentVersion.userId as userId, @@ -94,16 +94,16 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // TODO: If there's not a better way to write this then we need a better way to write this. query = languageId.HasValue - ? query.Where(x => x.LanguageId == languageId.Value) - : query.Where("umbracoContentVersionCultureVariation.languageId is null"); + ? query?.Where(x => x.LanguageId == languageId.Value) + : query?.Where("umbracoContentVersionCultureVariation.languageId is null"); - query = query.OrderByDescending(x => x.Id); + query = query?.OrderByDescending(x => x.Id); - Page page = _scopeAccessor.AmbientScope.Database.Page(pageIndex + 1, pageSize, query); + Page? page = _scopeAccessor.AmbientScope?.Database.Page(pageIndex + 1, pageSize, query); - totalRecords = page.TotalItems; + totalRecords = page?.TotalItems ?? 0; - return page.Items; + return page?.Items; } /// @@ -121,44 +121,44 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement * Can use test PerformContentVersionCleanup_WithNoKeepPeriods_DeletesEverythingExceptActive to try things out. */ - Sql query = _scopeAccessor.AmbientScope.SqlContext.Sql() + Sql? query = _scopeAccessor.AmbientScope?.SqlContext.Sql() .Delete() .WhereIn(x => x.VersionId, groupedVersionIds); - _scopeAccessor.AmbientScope.Database.Execute(query); + _scopeAccessor.AmbientScope?.Database.Execute(query); - query = _scopeAccessor.AmbientScope.SqlContext.Sql() + query = _scopeAccessor.AmbientScope?.SqlContext.Sql() .Delete() .WhereIn(x => x.VersionId, groupedVersionIds); - _scopeAccessor.AmbientScope.Database.Execute(query); + _scopeAccessor.AmbientScope?.Database.Execute(query); - query = _scopeAccessor.AmbientScope.SqlContext.Sql() + query = _scopeAccessor.AmbientScope?.SqlContext.Sql() .Delete() .WhereIn(x => x.Id, groupedVersionIds); - _scopeAccessor.AmbientScope.Database.Execute(query); + _scopeAccessor.AmbientScope?.Database.Execute(query); - query = _scopeAccessor.AmbientScope.SqlContext.Sql() + query = _scopeAccessor.AmbientScope?.SqlContext.Sql() .Delete() .WhereIn(x => x.Id, groupedVersionIds); - _scopeAccessor.AmbientScope.Database.Execute(query); + _scopeAccessor.AmbientScope?.Database.Execute(query); } } /// public void SetPreventCleanup(int versionId, bool preventCleanup) { - Sql query = _scopeAccessor.AmbientScope.SqlContext.Sql() + Sql? query = _scopeAccessor.AmbientScope?.SqlContext.Sql() .Update(x => x.Set(y => y.PreventCleanup, preventCleanup)) .Where(x => x.Id == versionId); - _scopeAccessor.AmbientScope.Database.Execute(query); + _scopeAccessor.AmbientScope?.Database.Execute(query); } /// - public ContentVersionMeta Get(int versionId) + public ContentVersionMeta? Get(int versionId) { - Sql query = _scopeAccessor.AmbientScope.SqlContext.Sql(); + Sql? query = _scopeAccessor.AmbientScope?.SqlContext.Sql(); - query.Select(@"umbracoDocument.nodeId as contentId, + query?.Select(@"umbracoDocument.nodeId as contentId, umbracoContent.contentTypeId as contentTypeId, umbracoContentVersion.id as versionId, umbracoContentVersion.userId as userId, @@ -178,7 +178,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .On(left => left.Id, right => right.UserId) .Where(x => x.Id == versionId); - return _scopeAccessor.AmbientScope.Database.Single(query); + return _scopeAccessor.AmbientScope?.Database.Single(query); } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs index 7633264ed6..793a88c262 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs @@ -29,16 +29,16 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return new FullDataSetRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false); } - protected override IDomain PerformGet(int id) + protected override IDomain? PerformGet(int id) { //use the underlying GetAll which will force cache all domains - return GetMany().FirstOrDefault(x => x.Id == id); + return GetMany()?.FirstOrDefault(x => x.Id == id); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { var sql = GetBaseQuery(false).Where(x => x.Id > 0); - if (ids.Any()) + if (ids?.Any() ?? false) { sql.WhereIn(x => x.Id, ids); } @@ -152,24 +152,24 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement entity.ResetDirtyProperties(); } - public IDomain GetByName(string domainName) + public IDomain? GetByName(string domainName) { - return GetMany().FirstOrDefault(x => x.DomainName.InvariantEquals(domainName)); + return GetMany()?.FirstOrDefault(x => x.DomainName.InvariantEquals(domainName)); } public bool Exists(string domainName) { - return GetMany().Any(x => x.DomainName.InvariantEquals(domainName)); + return GetMany()?.Any(x => x.DomainName.InvariantEquals(domainName)) ?? false; } - public IEnumerable GetAll(bool includeWildcards) + public IEnumerable? GetAll(bool includeWildcards) { - return GetMany().Where(x => includeWildcards || x.IsWildcard == false); + return GetMany()?.Where(x => includeWildcards || x.IsWildcard == false); } - public IEnumerable GetAssignedDomains(int contentId, bool includeWildcards) + public IEnumerable? GetAssignedDomains(int contentId, bool includeWildcards) { - return GetMany() + return GetMany()? .Where(x => x.RootContentId == contentId) .Where(x => includeWildcards || x.IsWildcard == false); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityContainerRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityContainerRepository.cs index 37cbf979e2..468b83062c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityContainerRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityContainerRepository.cs @@ -41,21 +41,21 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected override IRepositoryCachePolicy CreateCachePolicy() => NoCacheRepositoryCachePolicy.Instance; - protected override EntityContainer PerformGet(int id) + protected override EntityContainer? PerformGet(int id) { Sql sql = GetBaseQuery(false) .Where(GetBaseWhereClause(), new { id, NodeObjectType = NodeObjectTypeId }); - NodeDto nodeDto = Database.Fetch(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault(); + NodeDto? nodeDto = Database.Fetch(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault(); return nodeDto == null ? null : CreateEntity(nodeDto); } // temp - so we don't have to implement GetByQuery - public EntityContainer Get(Guid id) + public EntityContainer? Get(Guid id) { Sql sql = GetBaseQuery(false).Where("UniqueId=@uniqueId", new { uniqueId = id }); - NodeDto nodeDto = Database.Fetch(sql).FirstOrDefault(); + NodeDto? nodeDto = Database.Fetch(sql).FirstOrDefault(); return nodeDto == null ? null : CreateEntity(nodeDto); } @@ -67,9 +67,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return Database.Fetch(sql).Select(CreateEntity); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { - if (ids.Any()) + if (ids?.Any() ?? false) { return Database.FetchByGroups(ids, Constants.Sql.MaxParameterCount, batch => GetBaseQuery(false) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs index 965c85b6e6..8bf59d67db 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs @@ -35,14 +35,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Repository public IEnumerable GetPagedResultsByQuery(IQuery query, Guid objectType, long pageIndex, int pageSize, out long totalRecords, - IQuery filter, Ordering ordering) + IQuery? filter, Ordering? ordering) { return GetPagedResultsByQuery(query, new[] { objectType }, pageIndex, pageSize, out totalRecords, filter, ordering); } // get a page of entities public IEnumerable GetPagedResultsByQuery(IQuery query, Guid[] objectTypes, long pageIndex, int pageSize, out long totalRecords, - IQuery filter, Ordering ordering, Action> sqlCustomization = null) + IQuery? filter, Ordering? ordering, Action>? sqlCustomization = null) { var isContent = objectTypes.Any(objectType => objectType == Cms.Core.Constants.ObjectTypes.Document || objectType == Cms.Core.Constants.ObjectTypes.DocumentBlueprint); var isMedia = objectTypes.Any(objectType => objectType == Cms.Core.Constants.ObjectTypes.Media); @@ -91,7 +91,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return entities; } - public IEntitySlim Get(Guid key) + public IEntitySlim? Get(Guid key) { var sql = GetBaseWhere(false, false, false, false, key); var dto = Database.FirstOrDefault(sql); @@ -99,7 +99,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } - private IEntitySlim GetEntity(Sql sql, bool isContent, bool isMedia, bool isMember) + private IEntitySlim? GetEntity(Sql sql, bool isContent, bool isMedia, bool isMember) { // isContent is going to return a 1:M result now with the variants so we need to do different things if (isContent) @@ -120,7 +120,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return entity; } - public IEntitySlim Get(Guid key, Guid objectTypeId) + public IEntitySlim? Get(Guid key, Guid objectTypeId) { var isContent = objectTypeId == Cms.Core.Constants.ObjectTypes.Document || objectTypeId == Cms.Core.Constants.ObjectTypes.DocumentBlueprint; var isMedia = objectTypeId == Cms.Core.Constants.ObjectTypes.Media; @@ -130,14 +130,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return GetEntity(sql, isContent, isMedia, isMember); } - public IEntitySlim Get(int id) + public IEntitySlim? Get(int id) { var sql = GetBaseWhere(false, false, false, false, id); var dto = Database.FirstOrDefault(sql); return dto == null ? null : BuildEntity(dto); } - public IEntitySlim Get(int id, Guid objectTypeId) + public IEntitySlim? Get(int id, Guid objectTypeId) { var isContent = objectTypeId == Cms.Core.Constants.ObjectTypes.Document || objectTypeId == Cms.Core.Constants.ObjectTypes.DocumentBlueprint; var isMedia = objectTypeId == Cms.Core.Constants.ObjectTypes.Media; @@ -182,7 +182,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return entities; } - private IEnumerable PerformGetAll(Guid objectType, Action> filter = null) + private IEnumerable PerformGetAll(Guid objectType, Action>? filter = null) { var isContent = objectType == Cms.Core.Constants.ObjectTypes.Document || objectType == Cms.Core.Constants.ObjectTypes.DocumentBlueprint; var isMedia = objectType == Cms.Core.Constants.ObjectTypes.Media; @@ -192,9 +192,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return GetEntities(sql, isContent, isMedia, isMember); } - public IEnumerable GetAllPaths(Guid objectType, params int[] ids) + public IEnumerable GetAllPaths(Guid objectType, params int[]? ids) { - return ids.Any() + return ids?.Any() ?? false ? PerformGetAllPaths(objectType, sql => sql.WhereIn(x => x.NodeId, ids.Distinct())) : PerformGetAllPaths(objectType); } @@ -206,7 +206,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement : PerformGetAllPaths(objectType); } - private IEnumerable PerformGetAllPaths(Guid objectType, Action> filter = null) + private IEnumerable PerformGetAllPaths(Guid objectType, Action>? filter = null) { // NodeId is named Id on TreeEntityPath = use an alias var sql = Sql().Select(x => Alias(x.NodeId, nameof(TreeEntityPath.Id)), x => x.Path).From().Where(x => x.NodeObjectType == objectType); @@ -300,7 +300,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private IEnumerable BuildVariants(IEnumerable entities) { - List v = null; + List? v = null; var entitiesList = entities.ToList(); foreach (var e in entitiesList) { @@ -374,7 +374,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } // gets the full sql for a given object type, with a given filter - protected Sql GetFullSqlForEntityType(bool isContent, bool isMedia, bool isMember, Guid objectType, Action> filter) + protected Sql GetFullSqlForEntityType(bool isContent, bool isMedia, bool isMember, Guid objectType, Action>? filter) { var sql = GetBaseWhere(isContent, isMedia, isMember, false, filter, new[] { objectType }); return AddGroupBy(isContent, isMedia, isMember, sql, true); @@ -382,7 +382,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // gets the base SELECT + FROM [+ filter] sql // always from the 'current' content version - protected Sql GetBase(bool isContent, bool isMedia, bool isMember, Action> filter, bool isCount = false) + protected Sql GetBase(bool isContent, bool isMedia, bool isMember, Action>? filter, bool isCount = false) { var sql = Sql(); @@ -453,7 +453,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // gets the base SELECT + FROM [+ filter] + WHERE sql // for a given object type, with a given filter - protected Sql GetBaseWhere(bool isContent, bool isMedia, bool isMember, bool isCount, Action> filter, Guid[] objectTypes) + protected Sql GetBaseWhere(bool isContent, bool isMedia, bool isMember, bool isCount, Action>? filter, Guid[] objectTypes) { var sql = GetBase(isContent, isMedia, isMember, filter, isCount); if (objectTypes.Length > 0) @@ -537,14 +537,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // TODO: although the default ordering string works for name, it wont work for others without a table or an alias of some sort // As more things are attempted to be sorted we'll prob have to add more expressions here string orderBy; - switch (ordering.OrderBy.ToUpperInvariant()) + switch (ordering.OrderBy?.ToUpperInvariant()) { case "PATH": orderBy = SqlSyntax.GetQuotedColumn(NodeDto.TableName, "path"); break; default: - orderBy = ordering.OrderBy; + orderBy = ordering.OrderBy ?? string.Empty; break; } @@ -563,7 +563,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// private class GenericContentEntityDto : DocumentEntityDto { - public string MediaPath { get; set; } + public string? MediaPath { get; set; } } /// @@ -582,7 +582,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// private class MediaEntityDto : BaseDto { - public string MediaPath { get; set; } + public string? MediaPath { get; set; } } /// @@ -595,8 +595,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement public class VariantInfoDto { public int NodeId { get; set; } - public string IsoCode { get; set; } - public string Name { get; set; } + public string IsoCode { get; set; } = null!; + public string Name { get; set; } = null!; public bool DocumentPublished { get; set; } public bool DocumentEdited { get; set; } @@ -618,18 +618,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement public int ParentId { get; set; } public int? UserId { get; set; } public int Level { get; set; } - public string Path { get; set; } + public string Path { get; set; } = null!; public int SortOrder { get; set; } public Guid UniqueId { get; set; } - public string Text { get; set; } + public string? Text { get; set; } public Guid NodeObjectType { get; set; } public DateTime CreateDate { get; set; } public DateTime VersionDate { get; set; } public int Children { get; set; } public int VersionId { get; set; } - public string Alias { get; set; } - public string Icon { get; set; } - public string Thumbnail { get; set; } + public string Alias { get; set; } = null!; + public string? Icon { get; set; } + public string? Thumbnail { get; set; } public bool IsContainer { get; set; } // ReSharper restore UnusedAutoPropertyAccessor.Local diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepositoryBase.cs index 3518803490..d7618fcde6 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepositoryBase.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Persistence; using Umbraco.Cms.Core.Persistence.Querying; @@ -23,9 +24,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement public abstract class EntityRepositoryBase : RepositoryBase, IReadWriteQueryRepository where TEntity : class, IEntity { - private static RepositoryCachePolicyOptions s_defaultOptions; - private IRepositoryCachePolicy _cachePolicy; - private IQuery _hasIdQuery; + private static RepositoryCachePolicyOptions? s_defaultOptions; + private IRepositoryCachePolicy? _cachePolicy; + private IQuery? _hasIdQuery; /// /// Initializes a new instance of the class. @@ -136,16 +137,16 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Gets an entity by the passed in Id utilizing the repository's cache policy /// - public TEntity Get(TId id) + public TEntity? Get(TId? id) => CachePolicy.Get(id, PerformGet, PerformGetAll); /// /// Gets all entities of type TEntity or a list according to the passed in Ids /// - public IEnumerable GetMany(params TId[] ids) + public IEnumerable? GetMany(params TId[]? ids) { // ensure they are de-duplicated, easy win if people don't do this as this can cause many excess queries - ids = ids.Distinct() + ids = ids?.Distinct() // don't query by anything that is a default of T (like a zero) // TODO: I think we should enabled this in case accidental calls are made to get all with invalid ids @@ -154,7 +155,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // can't query more than 2000 ids at a time... but if someone is really querying 2000+ entities, // the additional overhead of fetching them in groups is minimal compared to the lookup time of each group - if (ids.Length <= Constants.Sql.MaxParameterCount) + if (ids?.Length <= Constants.Sql.MaxParameterCount) { return CachePolicy.GetAll(ids, PerformGetAll); } @@ -162,7 +163,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var entities = new List(); foreach (IEnumerable group in ids.InGroupsOf(Constants.Sql.MaxParameterCount)) { - entities.AddRange(CachePolicy.GetAll(group.ToArray(), PerformGetAll)); + var groups = CachePolicy.GetAll(group.ToArray(), PerformGetAll); + if (groups is not null) + { + entities.AddRange(groups); + } } return entities; @@ -171,8 +176,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Gets a list of entities by the passed in query /// - public IEnumerable Get(IQuery query) - => PerformGetByQuery(query) + public IEnumerable? Get(IQuery query) + => PerformGetByQuery(query)? .WhereNotNull(); // ensure we don't include any null refs in the returned collection! /// @@ -199,11 +204,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected virtual IRepositoryCachePolicy CreateCachePolicy() => new DefaultRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, DefaultOptions); - protected abstract TEntity PerformGet(TId id); + protected abstract TEntity? PerformGet(TId? id); - protected abstract IEnumerable PerformGetAll(params TId[] ids); + protected abstract IEnumerable? PerformGetAll(params TId[]? ids); - protected abstract IEnumerable PerformGetByQuery(IQuery query); + protected abstract IEnumerable? PerformGetByQuery(IQuery query); protected abstract void PersistNewItem(TEntity item); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs index 955cbf5d5d..0208329df3 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs @@ -48,7 +48,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .ForUpdate(); // deduplicate the logins - logins = logins.LegacyDistinctBy(x => x.ProviderKey + x.LoginProvider).ToList(); + logins = logins.LegacyDistinctBy(x => x!.ProviderKey + x.LoginProvider).ToList(); var toUpdate = new Dictionary(); var toDelete = new List(); @@ -88,7 +88,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement Database.InsertBulk(toInsert.Select(i => ExternalLoginFactory.BuildDto(userOrMemberKey, i))); } - protected override IIdentityUserLogin PerformGet(int id) + protected override IIdentityUserLogin? PerformGet(int id) { var sql = GetBaseQuery(false); sql.Where(GetBaseWhereClause(), new { id = id }); @@ -105,9 +105,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return entity; } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { - if (ids.Any()) + if (ids?.Any() ?? false) { return PerformGetAllOnIds(ids); } @@ -123,7 +123,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement if (ids.Any() == false) yield break; foreach (var id in ids) { - yield return Get(id); + IIdentityUserLogin? identityUserLogin = Get(id); + if (identityUserLogin is not null) + { + yield return identityUserLogin; + } } } @@ -237,7 +241,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .ToDictionary(x => x.LoginProvider, x => x.Id); // deduplicate the tokens - tokens = tokens.LegacyDistinctBy(x => x.LoginProvider + x.Name).ToList(); + tokens = tokens.LegacyDistinctBy(x => x!.LoginProvider + x.Name).ToList(); var providers = tokens.Select(x => x.LoginProvider).Distinct().ToList(); @@ -253,7 +257,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement foreach (ExternalLoginTokenDto existing in existingTokens) { - IExternalLoginToken found = tokens.FirstOrDefault(x => + IExternalLoginToken? found = tokens.FirstOrDefault(x => x.LoginProvider.InvariantEquals(existing.ExternalLoginDto.LoginProvider) && x.Name.InvariantEquals(existing.Name)); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/FileRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/FileRepository.cs index 23365939e0..0b5c826d47 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/FileRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/FileRepository.cs @@ -12,9 +12,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement internal abstract class FileRepository : IReadRepository, IWriteRepository where TEntity : IFile { - protected FileRepository(IFileSystem fileSystem) => FileSystem = fileSystem; + protected FileRepository(IFileSystem? fileSystem) => FileSystem = fileSystem; - protected IFileSystem FileSystem { get; } + protected IFileSystem? FileSystem { get; } public virtual void AddFolder(string folderPath) => PersistNewItem(new Folder(folderPath)); @@ -24,7 +24,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement public virtual void Save(TEntity entity) { - if (FileSystem.FileExists(entity.OriginalPath) == false) + if (FileSystem?.FileExists(entity.OriginalPath) == false) { PersistNewItem(entity); } @@ -36,11 +36,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement public virtual void Delete(TEntity entity) => PersistDeletedItem(entity); - public abstract TEntity Get(TId id); + public abstract TEntity? Get(TId? id); - public abstract IEnumerable GetMany(params TId[] ids); + public abstract IEnumerable GetMany(params TId[]? ids); - public virtual bool Exists(TId id) => FileSystem.FileExists(id.ToString()); + public virtual bool Exists(TId id) => FileSystem?.FileExists(id!.ToString()) ?? false; #endregion @@ -76,14 +76,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #endregion - internal virtual void PersistNewFolder(Folder entity) => FileSystem.CreateFolder(entity.Path); + internal virtual void PersistNewFolder(Folder entity) => FileSystem?.CreateFolder(entity.Path); - internal virtual void PersistDeletedFolder(Folder entity) => FileSystem.DeleteDirectory(entity.Path); + internal virtual void PersistDeletedFolder(Folder entity) => FileSystem?.DeleteDirectory(entity.Path); #region Abstract IUnitOfWorkRepository Methods protected virtual void PersistNewItem(TEntity entity) { + if (entity.Content is null || FileSystem is null) + { + return; + } using (Stream stream = GetContentStream(entity.Content)) { FileSystem.AddFile(entity.Path, stream, true); @@ -92,12 +96,16 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement //the id can be the hash entity.Id = entity.Path.GetHashCode(); entity.Key = entity.Path.EncodeAsGuid(); - entity.VirtualPath = FileSystem.GetUrl(entity.Path); + entity.VirtualPath = FileSystem?.GetUrl(entity.Path); } } protected virtual void PersistUpdatedItem(TEntity entity) { + if (entity.Content is null || FileSystem is null) + { + return; + } using (Stream stream = GetContentStream(entity.Content)) { FileSystem.AddFile(entity.Path, stream, true); @@ -113,7 +121,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement if (entity.Path.InvariantEquals(entity.OriginalPath) == false) { //delete the original file - FileSystem.DeleteFile(entity.OriginalPath); + FileSystem?.DeleteFile(entity.OriginalPath); //reset the original path on the file entity.ResetOriginalPath(); } @@ -121,7 +129,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected virtual void PersistDeletedItem(TEntity entity) { - if (FileSystem.FileExists(entity.Path)) + if (FileSystem?.FileExists(entity.Path) ?? false) { FileSystem.DeleteFile(entity.Path); } @@ -152,29 +160,37 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected IEnumerable FindAllFiles(string path, string filter) { var list = new List(); - list.AddRange(FileSystem.GetFiles(path, filter)); - - IEnumerable directories = FileSystem.GetDirectories(path); - foreach (var directory in directories) + var collection = FileSystem?.GetFiles(path, filter); + if (collection is not null) { - list.AddRange(FindAllFiles(directory, filter)); + list.AddRange(collection); + } + + IEnumerable? directories = FileSystem?.GetDirectories(path); + if (directories is not null) + { + foreach (var directory in directories) + { + list.AddRange(FindAllFiles(directory, filter)); + } } return list; } - protected string GetFileContent(string filename) + protected string? GetFileContent(string? filename) { - if (FileSystem.FileExists(filename) == false) + if (FileSystem?.FileExists(filename) == false) { return null; } try { - using (Stream stream = FileSystem.OpenFile(filename)) - using (var reader = new StreamReader(stream, Encoding.UTF8, true)) + using Stream? stream = FileSystem?.OpenFile(filename!); + if (stream is not null) { + using var reader = new StreamReader(stream, Encoding.UTF8, true); return reader.ReadToEnd(); } } @@ -182,18 +198,20 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { return null; // deal with race conds } + + return null; } - public Stream GetFileContentStream(string filepath) + public Stream? GetFileContentStream(string filepath) { - if (FileSystem.FileExists(filepath) == false) + if (FileSystem?.FileExists(filepath) == false) { return null; } try { - return FileSystem.OpenFile(filepath); + return FileSystem?.OpenFile(filepath); } catch { @@ -201,18 +219,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } } - public void SetFileContent(string filepath, Stream content) => FileSystem.AddFile(filepath, content, true); + public void SetFileContent(string filepath, Stream content) => FileSystem?.AddFile(filepath, content, true); public long GetFileSize(string filename) { - if (FileSystem.FileExists(filename) == false) + if (FileSystem?.FileExists(filename) == false) { return -1; } try { - return FileSystem.GetSize(filename); + return FileSystem!.GetSize(filename); } catch { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs index 653e916be6..8a752776da 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs @@ -21,9 +21,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { } /// - public IReadOnlyDictionary FindByKeyPrefix(string keyPrefix) - => Get(Query().Where(entity => entity.Identifier.StartsWith(keyPrefix))) - .ToDictionary(x => x.Identifier, x => x.Value); + public IReadOnlyDictionary? FindByKeyPrefix(string keyPrefix) + => Get(Query().Where(entity => entity.Identifier!.StartsWith(keyPrefix)))? + .ToDictionary(x => x.Identifier!, x => x.Value!); #region Overrides of IReadWriteQueryRepository @@ -57,18 +57,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected override IEnumerable GetDeleteClauses() => Enumerable.Empty(); - protected override IKeyValue PerformGet(string id) + protected override IKeyValue? PerformGet(string? id) { var sql = GetBaseQuery(false).Where(x => x.Key == id); var dto = Database.Fetch(sql).FirstOrDefault(); return dto == null ? null : Map(dto); } - protected override IEnumerable PerformGetAll(params string[] ids) + protected override IEnumerable? PerformGetAll(params string[]? ids) { var sql = GetBaseQuery(false).WhereIn(x => x.Key, ids); var dtos = Database.Fetch(sql); - return dtos.WhereNotNull().Select(Map); + return dtos?.WhereNotNull().Select(Map)!; } protected override IEnumerable PerformGetByQuery(IQuery query) @@ -76,7 +76,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var sqlClause = GetBaseQuery(false); var translator = new SqlTranslator(sqlClause, query); var sql = translator.Translate(); - return Database.Fetch(sql).Select(Map); + return Database.Fetch(sql).Select(Map).WhereNotNull(); } protected override void PersistNewItem(IKeyValue entity) @@ -88,10 +88,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected override void PersistUpdatedItem(IKeyValue entity) { var dto = Map(entity); - Database.Update(dto); + if (dto is not null) + { + Database.Update(dto); + } } - private static KeyValueDto Map(IKeyValue keyValue) + private static KeyValueDto? Map(IKeyValue keyValue) { if (keyValue == null) return null; @@ -103,7 +106,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement }; } - private static IKeyValue Map(KeyValueDto dto) + private static IKeyValue? Map(KeyValueDto dto) { if (dto == null) return null; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs index fc40343692..92806b0043 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs @@ -38,19 +38,19 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return new FullDataSetRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false); } - private FullDataSetRepositoryCachePolicy TypedCachePolicy => CachePolicy as FullDataSetRepositoryCachePolicy; + private FullDataSetRepositoryCachePolicy? TypedCachePolicy => CachePolicy as FullDataSetRepositoryCachePolicy; #region Overrides of RepositoryBase - protected override ILanguage PerformGet(int id) + protected override ILanguage? PerformGet(int id) { return PerformGetAll(id).FirstOrDefault(); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { var sql = GetBaseQuery(false).Where(x => x.Id > 0); - if (ids.Any()) + if (ids?.Any() ?? false) { sql.WhereIn(x => x.Id, ids); } @@ -243,7 +243,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return entity; } - public ILanguage GetByIsoCode(string isoCode) + public ILanguage? GetByIsoCode(string isoCode) { // ensure cache is populated, in a non-expensive way if (TypedCachePolicy != null) @@ -256,7 +256,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // fast way of getting an id for an isoCode - avoiding cloning // _codeIdMap is rebuilt whenever PerformGetAll runs - public int? GetIdByIsoCode(string isoCode, bool throwOnNotFound = true) + public int? GetIdByIsoCode(string? isoCode, bool throwOnNotFound = true) { if (isoCode == null) return null; @@ -278,7 +278,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // fast way of getting an isoCode for an id - avoiding cloning // _idCodeMap is rebuilt whenever PerformGetAll runs - public string GetIsoCodeById(int? id, bool throwOnNotFound = true) + public string? GetIsoCodeById(int? id, bool throwOnNotFound = true) { if (id == null) return null; @@ -300,7 +300,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement public string GetDefaultIsoCode() { - return GetDefault()?.IsoCode; + return GetDefault().IsoCode; } public int? GetDefaultId() @@ -313,7 +313,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { // get all cached var languages = (TypedCachePolicy?.GetAllCached(PerformGetAll) //try to get all cached non-cloned if using the correct cache policy (not the case in unit tests) - ?? CachePolicy.GetAll(Array.Empty(), PerformGetAll)).ToList(); + ?? CachePolicy.GetAll(Array.Empty(), PerformGetAll)!).ToList(); var language = languages.FirstOrDefault(x => x.IsDefault); if (language != null) return language; @@ -323,14 +323,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // still, don't kill the site, and return "something" - ILanguage first = null; + ILanguage? first = null; foreach (var l in languages) { if (first == null || l.Id < first.Id) first = l; } - return first; + return first!; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LogViewerQueryRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LogViewerQueryRepository.cs index 3482da377d..bfecc66765 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LogViewerQueryRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LogViewerQueryRepository.cs @@ -25,10 +25,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return new FullDataSetRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { var sql = GetBaseQuery(false).Where($"{Cms.Core.Constants.DatabaseSchema.Tables.LogViewerQuery}.id > 0"); - if (ids.Any()) + if (ids?.Any() ?? false) { sql.Where($"{Cms.Core.Constants.DatabaseSchema.Tables.LogViewerQuery}.id in (@ids)", new { ids = ids }); } @@ -120,16 +120,16 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } } - protected override ILogViewerQuery PerformGet(int id) + protected override ILogViewerQuery? PerformGet(int id) { //use the underlying GetAll which will force cache all log queries - return GetMany().FirstOrDefault(x => x.Id == id); + return GetMany()?.FirstOrDefault(x => x.Id == id); } - public ILogViewerQuery GetByName(string name) + public ILogViewerQuery? GetByName(string name) { //use the underlying GetAll which will force cache all log queries - return GetMany().FirstOrDefault(x => x.Name == name); + return GetMany()?.FirstOrDefault(x => x.Name == name); } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs index c0ba8f3ac4..2bddc4a1ea 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs @@ -28,20 +28,20 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement _shortStringHelper = shortStringHelper; } - protected override IMacro PerformGet(int id) + protected override IMacro? PerformGet(int id) { var sql = GetBaseQuery(false); sql.Where(GetBaseWhereClause(), new { id }); return GetBySql(sql); } - public IMacro Get(Guid id) + public IMacro? Get(Guid id) { var sql = GetBaseQuery().Where(x => x.UniqueId == id); return GetBySql(sql); } - private IMacro GetBySql(Sql sql) + private IMacro? GetBySql(Sql sql) { var macroDto = Database .FetchOneToMany(x => x.MacroPropertyDtos, sql) @@ -58,9 +58,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return entity; } - public IEnumerable GetMany(params Guid[] ids) + public IEnumerable GetMany(params Guid[]? ids) { - return ids.Length > 0 ? ids.Select(Get) : GetAllNoIds(); + return ids?.Length > 0 ? ids.Select(Get).WhereNotNull() : GetAllNoIds(); } public bool Exists(Guid id) @@ -68,9 +68,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return Get(id) != null; } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { - return ids.Length > 0 ? ids.Select(Get) : GetAllNoIds(); + return ids?.Length > 0 ? ids.Select(Get).WhereNotNull() : GetAllNoIds(); } private IEnumerable GetAllNoIds() @@ -97,15 +97,15 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } } - protected override IEnumerable PerformGetByQuery(IQuery query) + protected override IEnumerable? PerformGetByQuery(IQuery query) { var sqlClause = GetBaseQuery(false); var translator = new SqlTranslator(sqlClause, query); var sql = translator.Translate(); - return Database + return Database? .FetchOneToMany(x => x.MacroPropertyDtos, sql) - .Select(x => Get(x.Id)); + .Select(x => Get(x.Id)!); } protected override Sql GetBaseQuery(bool isCount) @@ -146,12 +146,15 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var id = Convert.ToInt32(Database.Insert(dto)); entity.Id = id; - foreach (var propDto in dto.MacroPropertyDtos) + if (dto.MacroPropertyDtos is not null) { - //need to set the id explicitly here - propDto.Macro = id; - var propId = Convert.ToInt32(Database.Insert(propDto)); - entity.Properties[propDto.Alias].Id = propId; + foreach (var propDto in dto.MacroPropertyDtos) + { + //need to set the id explicitly here + propDto.Macro = id; + var propId = Convert.ToInt32(Database.Insert(propDto)); + entity.Properties[propDto.Alias].Id = propId; + } } entity.ResetDirtyProperties(); @@ -168,8 +171,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var macro = (Macro)entity; if (macro.IsPropertyDirty("Properties") || macro.Properties.Values.Any(x => x.IsDirty())) { - var ids = dto.MacroPropertyDtos.Where(x => x.Id > 0).Select(x => x.Id).ToArray(); - if (ids.Length > 0) + var ids = dto.MacroPropertyDtos?.Where(x => x.Id > 0).Select(x => x.Id).ToArray(); + if (ids?.Length > 0) Database.Delete("WHERE macro=@macro AND id NOT IN (@ids)", new { macro = dto.Id, ids }); else Database.Delete("WHERE macro=@macro", new { macro = dto.Id }); @@ -177,6 +180,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // detect new aliases, replace with temp aliases // this ensures that we don't have collisions, ever var aliases = new Dictionary(); + if (dto.MacroPropertyDtos is null) + { + return; + } foreach (var propDto in dto.MacroPropertyDtos) { var prop = macro.Properties.Values.FirstOrDefault(x => x.Id == propDto.Id); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs index a431fb6896..8c21d3625a 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs @@ -68,7 +68,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected override Guid NodeObjectTypeId => Cms.Core.Constants.ObjectTypes.Media; - protected override IMedia PerformGet(int id) + protected override IMedia? PerformGet(int id) { var sql = GetBaseQuery(QueryType.Single) .Where(x => x.NodeId == id) @@ -80,11 +80,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement : MapDtoToContent(dto); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { var sql = GetBaseQuery(QueryType.Many); - if (ids.Any()) + if (ids?.Any() ?? false) sql.WhereIn(x => x.NodeId, ids); return MapDtosToContent(Database.Fetch(sql)); @@ -196,7 +196,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return MapDtosToContent(Database.Fetch(sql), true); } - public override IMedia GetVersion(int versionId) + public override IMedia? GetVersion(int versionId) { var sql = GetBaseQuery(QueryType.Single) .Where(x => x.Id == versionId); @@ -205,7 +205,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return dto == null ? null : MapDtoToContent(dto); } - public IMedia GetMediaByPath(string mediaPath) + public IMedia? GetMediaByPath(string mediaPath) { var umbracoFileValue = mediaPath; const string pattern = ".*[_][0-9]+[x][0-9]+[.].*"; @@ -244,7 +244,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement entity.AddingEntity(); // ensure unique name on the same level - entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name); + entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name)!; // ensure that strings don't contain characters that are invalid in xml // TODO: do we really want to keep doing this here? @@ -328,7 +328,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement if (!isMoving) { // ensure unique name on the same level - entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name, entity.Id); + entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name, entity.Id)!; // ensure that strings don't contain characters that are invalid in xml // TODO: do we really want to keep doing this here? @@ -404,12 +404,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Read Repository implementation for Guid keys - public IMedia Get(Guid id) + public IMedia? Get(Guid id) { return _mediaByGuidReadRepository.Get(id); } - IEnumerable IReadRepository.GetMany(params Guid[] ids) + IEnumerable? IReadRepository.GetMany(params Guid[]? ids) { return _mediaByGuidReadRepository.GetMany(ids); } @@ -433,7 +433,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement _outerRepo = outerRepo; } - protected override IMedia PerformGet(Guid id) + protected override IMedia? PerformGet(Guid id) { var sql = _outerRepo.GetBaseQuery(QueryType.Single) .Where(x => x.UniqueId == id); @@ -448,10 +448,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return content; } - protected override IEnumerable PerformGetAll(params Guid[] ids) + protected override IEnumerable PerformGetAll(params Guid[]? ids) { var sql = _outerRepo.GetBaseQuery(QueryType.Many); - if (ids.Length > 0) + if (ids?.Length > 0) sql.WhereIn(x => x.UniqueId, ids); return _outerRepo.MapDtosToContent(Database.Fetch(sql)); @@ -491,11 +491,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #endregion /// - public override IEnumerable GetPage(IQuery query, + public override IEnumerable GetPage(IQuery? query, long pageIndex, int pageSize, out long totalRecords, - IQuery filter, Ordering ordering) + IQuery? filter, Ordering? ordering) { - Sql filterSql = null; + Sql? filterSql = null; if (filter != null) { @@ -513,7 +513,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private IEnumerable MapDtosToContent(List dtos, bool withCache = false) { var temps = new List>(); - var contentTypes = new Dictionary(); + var contentTypes = new Dictionary(); var content = new Core.Models.Media[dtos.Count]; for (var i = 0; i < dtos.Count; i++) @@ -536,7 +536,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // get the content type - the repository is full cache *but* still deep-clones // whatever comes out of it, so use our own local index here to avoid this var contentTypeId = dto.ContentTypeId; - if (contentTypes.TryGetValue(contentTypeId, out IMediaType contentType) == false) + if (contentTypes.TryGetValue(contentTypeId, out IMediaType? contentType) == false) contentTypes[contentTypeId] = contentType = _mediaTypeRepository.Get(contentTypeId); var c = content[i] = ContentBaseFactory.BuildEntity(dto, contentType); @@ -552,10 +552,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // assign properties foreach (var temp in temps) { - temp.Content.Properties = properties[temp.VersionId]; + if (temp.Content is not null) + { + temp.Content.Properties = properties[temp.VersionId]; - // reset dirty initial properties (U4-1946) - temp.Content.ResetDirtyProperties(false); + // reset dirty initial properties (U4-1946) + temp.Content.ResetDirtyProperties(false); + } } return content; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs index 0a07fb2260..55ba96b86b 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs @@ -38,37 +38,37 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // every PerformGet/Exists just GetMany() and then filters // except PerformGetAll which is the one really doing the job - protected override IMediaType PerformGet(int id) - => GetMany().FirstOrDefault(x => x.Id == id); + protected override IMediaType? PerformGet(int id) + => GetMany()?.FirstOrDefault(x => x.Id == id); - protected override IMediaType PerformGet(Guid id) - => GetMany().FirstOrDefault(x => x.Key == id); + protected override IMediaType? PerformGet(Guid id) + => GetMany()?.FirstOrDefault(x => x.Key == id); protected override bool PerformExists(Guid id) - => GetMany().FirstOrDefault(x => x.Key == id) != null; + => GetMany()?.FirstOrDefault(x => x.Key == id) != null; - protected override IMediaType PerformGet(string alias) - => GetMany().FirstOrDefault(x => x.Alias.InvariantEquals(alias)); + protected override IMediaType? PerformGet(string alias) + => GetMany()?.FirstOrDefault(x => x.Alias.InvariantEquals(alias)); - protected override IEnumerable GetAllWithFullCachePolicy() + protected override IEnumerable? GetAllWithFullCachePolicy() { - return CommonRepository.GetAllTypes().OfType(); + return CommonRepository.GetAllTypes()?.OfType(); } - protected override IEnumerable PerformGetAll(params Guid[] ids) + protected override IEnumerable? PerformGetAll(params Guid[]? ids) { var all = GetMany(); - return ids.Any() ? all.Where(x => ids.Contains(x.Key)) : all; + return ids?.Any() ?? false ? all?.Where(x => ids.Contains(x.Key)) : all; } - protected override IEnumerable PerformGetByQuery(IQuery query) + protected override IEnumerable? PerformGetByQuery(IQuery query) { var baseQuery = GetBaseQuery(false); var translator = new SqlTranslator(baseQuery, query); var sql = translator.Translate(); var ids = Database.Fetch(sql).Distinct().ToArray(); - return ids.Length > 0 ? GetMany(ids).OrderBy(x => x.Name) : Enumerable.Empty(); + return ids.Length > 0 ? GetMany(ids)?.OrderBy(x => x.Name) : Enumerable.Empty(); } protected override Sql GetBaseQuery(bool isCount) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs index 89858951d7..16d400858c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs @@ -25,7 +25,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement : base(scopeAccessor, cache, logger) => _eventMessagesFactory = eventMessagesFactory; - protected override IMemberGroup PerformGet(int id) + protected override IMemberGroup? PerformGet(int id) { var sql = GetBaseQuery(false); sql.Where(GetBaseWhereClause(), new { id = id }); @@ -35,14 +35,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return dto == null ? null : MemberGroupFactory.BuildEntity(dto); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { var sql = Sql() .SelectAll() .From() .Where(dto => dto.NodeObjectType == NodeObjectTypeId); - if (ids.Any()) + if (ids?.Any() ?? false) sql.WhereIn(x => x.NodeId, ids); return Database.Fetch(sql).Select(x => MemberGroupFactory.BuildEntity(x)); @@ -121,7 +121,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement entity.ResetDirtyProperties(); } - public IMemberGroup Get(Guid uniqueId) + public IMemberGroup? Get(Guid uniqueId) { var sql = GetBaseQuery(false); sql.Where(x => x.UniqueId == uniqueId); @@ -131,7 +131,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return dto == null ? null : MemberGroupFactory.BuildEntity(dto); } - public IMemberGroup GetByName(string name) + public IMemberGroup? GetByName(string name) { return IsolatedCache.GetCacheItem( typeof(IMemberGroup).FullName + "." + name, @@ -139,7 +139,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { var qry = Query().Where(group => group.Name.Equals(name)); var result = Get(qry); - return result.FirstOrDefault(); + return result?.FirstOrDefault(); }, //cache for 5 mins since that is the default in the Runtime app cache TimeSpan.FromMinutes(5), @@ -147,12 +147,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement true); } - public IMemberGroup CreateIfNotExists(string roleName) + public IMemberGroup? CreateIfNotExists(string roleName) { - var qry = Query().Where(group => group.Name.Equals(roleName)); + var qry = Query().Where(group => group.Name!.Equals(roleName)); var result = Get(qry); - if (result.Any()) + if (result?.Any() ?? false) return null; var grp = new MemberGroup @@ -183,11 +183,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .Where(x => x.Member == memberId); return Database.Fetch(sql) - .LegacyDistinctBy(dto => dto.NodeId) + .LegacyDistinctBy(dto => dto!.NodeId) .Select(x => MemberGroupFactory.BuildEntity(x)); } - public IEnumerable GetMemberGroupsForMember(string username) + public IEnumerable GetMemberGroupsForMember(string? username) { var sql = Sql() .Select("un.*") @@ -200,7 +200,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .Where("cmsMember.LoginName=@loginName", new { loginName = username }); return Database.Fetch(sql) - .LegacyDistinctBy(dto => dto.NodeId) + .LegacyDistinctBy(dto => dto!.NodeId) .Select(x => MemberGroupFactory.BuildEntity(x)); } @@ -222,8 +222,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .From() .Where(dto => dto.NodeObjectType == NodeObjectTypeId) .Where("umbracoNode." + SqlSyntax.GetQuotedColumnName("text") + " in (@names)", new { names = roleNames }); - IEnumerable existingRoles = Database.Fetch(existingSql).Select(x => x.Text); - IEnumerable missingRoles = roleNames.Except(existingRoles, StringComparer.CurrentCultureIgnoreCase); + IEnumerable existingRoles = Database.Fetch(existingSql).Select(x => x.Text); + IEnumerable missingRoles = roleNames.Except(existingRoles, StringComparer.CurrentCultureIgnoreCase); MemberGroup[] missingGroups = missingRoles.Select(x => new MemberGroup { Name = x }).ToArray(); var evtMsgs = _eventMessagesFactory.Get(); @@ -241,7 +241,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement //now go get all the dto's for roles with these role names var rolesForNames = Database.Fetch(existingSql) - .ToDictionary(x => x.Text, StringComparer.InvariantCultureIgnoreCase); + .ToDictionary(x => x.Text!, StringComparer.InvariantCultureIgnoreCase); AssignedRolesDto[] currentlyAssigned; if (replace) @@ -274,14 +274,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement //exist in the roleNames list, then determine which ones are not currently assigned. var mId = memberId; AssignedRolesDto[] found = currentlyAssigned.Where(x => x.MemberId == mId).ToArray(); - IEnumerable assignedRoles = found.Where(x => roleNames.Contains(x.RoleName, StringComparer.CurrentCultureIgnoreCase)).Select(x => x.RoleName); - IEnumerable nonAssignedRoles = roleNames.Except(assignedRoles, StringComparer.CurrentCultureIgnoreCase); + IEnumerable assignedRoles = found.Where(x => roleNames.Contains(x.RoleName, StringComparer.CurrentCultureIgnoreCase)).Select(x => x.RoleName); + IEnumerable nonAssignedRoles = roleNames.Except(assignedRoles, StringComparer.CurrentCultureIgnoreCase); IEnumerable dtos = nonAssignedRoles .Select(x => new Member2MemberGroupDto { Member = mId, - MemberGroup = rolesForNames[x].NodeId + MemberGroup = rolesForNames[x!].NodeId }); Database.InsertBulk(dtos); @@ -309,7 +309,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private class AssignedRolesDto { [Column("text")] - public string RoleName { get; set; } + public string? RoleName { get; set; } [Column("Member")] public int MemberId { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs index 4a3ed0aba6..72ba6c6b26 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs @@ -41,7 +41,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private readonly IPasswordHasher _passwordHasher; private readonly ITagRepository _tagRepository; private bool _passwordConfigInitialized; - private string _passwordConfigJson; + private string? _passwordConfigJson; public MemberRepository( IScopeAccessor scopeAccessor, @@ -77,7 +77,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Returns a serialized dictionary of the password configuration that is stored against the member in the database /// - private string DefaultPasswordConfigJson + private string? DefaultPasswordConfigJson { get { @@ -105,8 +105,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith) { //get the group id - IQuery grpQry = Query().Where(group => group.Name.Equals(roleName)); - IMemberGroup memberGroup = _memberGroupRepository.Get(grpQry).FirstOrDefault(); + IQuery grpQry = Query().Where(group => group.Name!.Equals(roleName)); + IMemberGroup? memberGroup = _memberGroupRepository.Get(grpQry)?.FirstOrDefault(); if (memberGroup == null) { return Enumerable.Empty(); @@ -135,10 +135,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement throw new ArgumentOutOfRangeException(nameof(matchType)); } - IMember[] matchedMembers = Get(query).ToArray(); + IMember[]? matchedMembers = Get(query)?.ToArray(); var membersInGroup = new List(); + if (matchedMembers is null) + { + return membersInGroup; + } //then we need to filter the matched members that are in the role foreach (IEnumerable group in matchedMembers.Select(x => x.Id) .InGroupsOf(Constants.Sql.MaxParameterCount)) @@ -163,8 +167,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// public IEnumerable GetByMemberGroup(string groupName) { - IQuery grpQry = Query().Where(group => group.Name.Equals(groupName)); - IMemberGroup memberGroup = _memberGroupRepository.Get(grpQry).FirstOrDefault(); + IQuery grpQry = Query().Where(group => group.Name!.Equals(groupName)); + IMemberGroup? memberGroup = _memberGroupRepository.Get(grpQry)?.FirstOrDefault(); if (memberGroup == null) { return Enumerable.Empty(); @@ -264,12 +268,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Gets paged member results. /// - public override IEnumerable GetPage(IQuery query, + public override IEnumerable GetPage(IQuery? query, long pageIndex, int pageSize, out long totalRecords, - IQuery filter, - Ordering ordering) + IQuery? filter, + Ordering? ordering) { - Sql filterSql = null; + Sql? filterSql = null; if (filter != null) { @@ -286,7 +290,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement ordering); } - public IMember GetByUsername(string username) => + public IMember? GetByUsername(string username) => _memberByUsernameCachePolicy.Get(username, PerformGetByUsername, PerformGetAllByUsername); public int[] GetMemberIds(string[] usernames) @@ -345,7 +349,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private IEnumerable MapDtosToContent(List dtos, bool withCache = false) { var temps = new List>(); - var contentTypes = new Dictionary(); + var contentTypes = new Dictionary(); var content = new Member[dtos.Count]; for (var i = 0; i < dtos.Count; i++) @@ -355,7 +359,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement if (withCache) { // if the cache contains the (proper version of the) item, use it - IMember cached = + IMember? cached = IsolatedCache.GetCacheItem(RepositoryCacheKeys.GetKey(dto.NodeId)); if (cached != null && cached.VersionId == dto.ContentVersionDto.Id) { @@ -369,7 +373,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // get the content type - the repository is full cache *but* still deep-clones // whatever comes out of it, so use our own local index here to avoid this var contentTypeId = dto.ContentDto.ContentTypeId; - if (contentTypes.TryGetValue(contentTypeId, out IMemberType contentType) == false) + if (contentTypes.TryGetValue(contentTypeId, out IMemberType? contentType) == false) { contentTypes[contentTypeId] = contentType = _memberTypeRepository.Get(contentTypeId); } @@ -387,10 +391,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // assign properties foreach (TempContent temp in temps) { - temp.Content.Properties = properties[temp.VersionId]; + if (temp.Content is not null) + { + temp.Content.Properties = properties[temp.VersionId]; - // reset dirty initial properties (U4-1946) - temp.Content.ResetDirtyProperties(false); + // reset dirty initial properties (U4-1946) + temp.Content.ResetDirtyProperties(false); + } } return content; @@ -398,7 +405,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private IMember MapDtoToContent(MemberDto dto) { - IMemberType memberType = _memberTypeRepository.Get(dto.ContentDto.ContentTypeId); + IMemberType? memberType = _memberTypeRepository.Get(dto.ContentDto.ContentTypeId); Member member = ContentBaseFactory.BuildEntity(dto, memberType); // get properties - indexed by version id @@ -413,13 +420,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return member; } - private IMember PerformGetByUsername(string username) + private IMember? PerformGetByUsername(string? username) { IQuery query = Query().Where(x => x.Username.Equals(username)); return PerformGetByQuery(query).FirstOrDefault(); } - private IEnumerable PerformGetAllByUsername(params string[] usernames) + private IEnumerable PerformGetAllByUsername(params string[]? usernames) { IQuery query = Query().WhereIn(x => x.Username, usernames); return PerformGetByQuery(query); @@ -429,23 +436,23 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected override Guid NodeObjectTypeId => Constants.ObjectTypes.Member; - protected override IMember PerformGet(int id) + protected override IMember? PerformGet(int id) { Sql sql = GetBaseQuery(QueryType.Single) .Where(x => x.NodeId == id) .SelectTop(1); - MemberDto dto = Database.Fetch(sql).FirstOrDefault(); + MemberDto? dto = Database.Fetch(sql).FirstOrDefault(); return dto == null ? null : MapDtoToContent(dto); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { Sql sql = GetBaseQuery(QueryType.Many); - if (ids.Any()) + if (ids?.Any() ?? false) { sql.WhereIn(x => x.NodeId, ids); } @@ -598,12 +605,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return MapDtosToContent(Database.Fetch(sql), true); } - public override IMember GetVersion(int versionId) + public override IMember? GetVersion(int versionId) { Sql sql = GetBaseQuery(QueryType.Single) .Where(x => x.Id == versionId); - MemberDto dto = Database.Fetch(sql).FirstOrDefault(); + MemberDto? dto = Database.Fetch(sql).FirstOrDefault(); return dto == null ? null : MapDtoToContent(dto); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs index 27e51551e2..93b00bdc8f 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs @@ -43,30 +43,30 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // every PerformGet/Exists just GetMany() and then filters // except PerformGetAll which is the one really doing the job - protected override IMemberType PerformGet(int id) - => GetMany().FirstOrDefault(x => x.Id == id); + protected override IMemberType? PerformGet(int id) + => GetMany()?.FirstOrDefault(x => x.Id == id); - protected override IMemberType PerformGet(Guid id) - => GetMany().FirstOrDefault(x => x.Key == id); + protected override IMemberType? PerformGet(Guid id) + => GetMany()?.FirstOrDefault(x => x.Key == id); - protected override IEnumerable PerformGetAll(params Guid[] ids) + protected override IEnumerable? PerformGetAll(params Guid[]? ids) { var all = GetMany(); - return ids.Any() ? all.Where(x => ids.Contains(x.Key)) : all; + return ids?.Any() ?? false ? all?.Where(x => ids.Contains(x.Key)) : all; } protected override bool PerformExists(Guid id) - => GetMany().FirstOrDefault(x => x.Key == id) != null; + => GetMany()?.FirstOrDefault(x => x.Key == id) != null; - protected override IMemberType PerformGet(string alias) - => GetMany().FirstOrDefault(x => x.Alias.InvariantEquals(alias)); + protected override IMemberType? PerformGet(string alias) + => GetMany()?.FirstOrDefault(x => x.Alias.InvariantEquals(alias)); - protected override IEnumerable GetAllWithFullCachePolicy() + protected override IEnumerable? GetAllWithFullCachePolicy() { - return CommonRepository.GetAllTypes().OfType(); + return CommonRepository.GetAllTypes()?.OfType(); } - protected override IEnumerable PerformGetByQuery(IQuery query) + protected override IEnumerable? PerformGetByQuery(IQuery query) { var subQuery = GetSubquery(); var translator = new SqlTranslator(subQuery, query); @@ -76,7 +76,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .OrderBy(x => x.SortOrder); var ids = Database.Fetch(sql).Distinct().ToArray(); - return ids.Length > 0 ? GetMany(ids).OrderBy(x => x.Name) : Enumerable.Empty(); + return ids.Length > 0 ? GetMany(ids)?.OrderBy(x => x.Name) : Enumerable.Empty(); } protected override Sql GetBaseQuery(bool isCount) @@ -211,7 +211,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement //custom property type constructor logic to set explicit dbtype's for built in properties var builtinProperties = ConventionsHelper.GetStandardPropertyTypeStubs(_shortStringHelper); var readonlyStorageType = builtinProperties.TryGetValue(propertyTypeAlias, out var propertyType); - storageType = readonlyStorageType ? propertyType.ValueStorageType : storageType; + storageType = readonlyStorageType ? propertyType!.ValueStorageType : storageType; return new PropertyType(_shortStringHelper, propertyEditorAlias, storageType, readonlyStorageType, propertyTypeAlias); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/NotificationsRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/NotificationsRepository.cs index c35052b9d1..892c079fc6 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/NotificationsRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/NotificationsRepository.cs @@ -21,12 +21,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement _scopeAccessor = scopeAccessor; } - private IDatabaseScope AmbientScope => _scopeAccessor.AmbientScope; + private IDatabaseScope? AmbientScope => _scopeAccessor.AmbientScope; - public IEnumerable GetUsersNotifications(IEnumerable userIds, string action, IEnumerable nodeIds, Guid objectType) + public IEnumerable? GetUsersNotifications(IEnumerable userIds, string? action, IEnumerable nodeIds, Guid objectType) { var nodeIdsA = nodeIds.ToArray(); - var sql = AmbientScope.SqlContext.Sql() + var sql = AmbientScope?.SqlContext.Sql() .Select("DISTINCT umbracoNode.id nodeId, umbracoUser.id userId, umbracoNode.nodeObjectType, umbracoUser2NodeNotify.action") .From() .InnerJoin().On(left => left.NodeId, right => right.NodeId) @@ -35,17 +35,17 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .Where(x => x.Disabled == false) // only approved users .Where(x => x.Action == action); // on the specified action if (nodeIdsA.Length > 0) - sql + sql? .WhereIn(x => x.NodeId, nodeIdsA); // for the specified nodes - sql + sql? .OrderBy(x => x.Id) .OrderBy(dto => dto.NodeId); - return AmbientScope.Database.Fetch(sql).Select(x => new Notification(x.NodeId, x.UserId, x.Action, objectType)); + return AmbientScope?.Database.Fetch(sql).Select(x => new Notification(x.NodeId, x.UserId, x.Action, objectType)); } - public IEnumerable GetUserNotifications(IUser user) + public IEnumerable? GetUserNotifications(IUser user) { - var sql = AmbientScope.SqlContext.Sql() + var sql = AmbientScope?.SqlContext.Sql() .Select("DISTINCT umbracoNode.id AS nodeId, umbracoUser2NodeNotify.userId, umbracoNode.nodeObjectType, umbracoUser2NodeNotify.action") .From() .InnerJoin() @@ -53,9 +53,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .Where(dto => dto.UserId == (int)user.Id) .OrderBy(dto => dto.NodeId); - var dtos = AmbientScope.Database.Fetch(sql); + var dtos = AmbientScope?.Database.Fetch(sql); //need to map the results - return dtos.Select(d => new Notification(d.NodeId, d.UserId, d.Action, d.NodeObjectType)).ToList(); + return dtos?.Select(d => new Notification(d.NodeId, d.UserId, d.Action, d.NodeObjectType)).ToList(); } public IEnumerable SetNotifications(IUser user, IEntity entity, string[] actions) @@ -64,9 +64,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return actions.Select(action => CreateNotification(user, entity, action)).ToList(); } - public IEnumerable GetEntityNotifications(IEntity entity) + public IEnumerable? GetEntityNotifications(IEntity entity) { - var sql = AmbientScope.SqlContext.Sql() + var sql = AmbientScope?.SqlContext.Sql() .Select("DISTINCT umbracoNode.id as nodeId, umbracoUser2NodeNotify.userId, umbracoNode.nodeObjectType, umbracoUser2NodeNotify.action") .From() .InnerJoin() @@ -74,34 +74,34 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .Where(dto => dto.NodeId == entity.Id) .OrderBy(dto => dto.NodeId); - var dtos = AmbientScope.Database.Fetch(sql); + var dtos = AmbientScope?.Database.Fetch(sql); //need to map the results - return dtos.Select(d => new Notification(d.NodeId, d.UserId, d.Action, d.NodeObjectType)).ToList(); + return dtos?.Select(d => new Notification(d.NodeId, d.UserId, d.Action, d.NodeObjectType)).ToList(); } public int DeleteNotifications(IEntity entity) { - return AmbientScope.Database.Delete("WHERE nodeId = @nodeId", new { nodeId = entity.Id }); + return AmbientScope?.Database.Delete("WHERE nodeId = @nodeId", new { nodeId = entity.Id }) ?? 0; } public int DeleteNotifications(IUser user) { - return AmbientScope.Database.Delete("WHERE userId = @userId", new { userId = user.Id }); + return AmbientScope?.Database.Delete("WHERE userId = @userId", new { userId = user.Id }) ?? 0; } public int DeleteNotifications(IUser user, IEntity entity) { // delete all settings on the node for this user - return AmbientScope.Database.Delete("WHERE userId = @userId AND nodeId = @nodeId", new { userId = user.Id, nodeId = entity.Id }); + return AmbientScope?.Database.Delete("WHERE userId = @userId AND nodeId = @nodeId", new { userId = user.Id, nodeId = entity.Id }) ?? 0; } public Notification CreateNotification(IUser user, IEntity entity, string action) { - var sql = AmbientScope.SqlContext.Sql() + var sql = AmbientScope?.SqlContext.Sql() .Select("DISTINCT nodeObjectType") .From() .Where(nodeDto => nodeDto.NodeId == entity.Id); - var nodeType = AmbientScope.Database.ExecuteScalar(sql); + var nodeType = AmbientScope?.Database.ExecuteScalar(sql); var dto = new User2NodeNotifyDto { @@ -109,7 +109,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement NodeId = entity.Id, UserId = user.Id }; - AmbientScope.Database.Insert(dto); + AmbientScope?.Database.Insert(dto); return new Notification(dto.NodeId, dto.UserId, dto.Action, nodeType); } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewRepository.cs index 751c84ac56..65bd56e7f6 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewRepository.cs @@ -16,18 +16,22 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { } - protected PartialViewRepository(IFileSystem fileSystem) + protected PartialViewRepository(IFileSystem? fileSystem) : base(fileSystem) { } protected virtual PartialViewType ViewType => PartialViewType.PartialView; - public override IPartialView Get(string id) + public override IPartialView? Get(string? id) { + if (FileSystem is null) + { + return null; + } // get the relative path within the filesystem // (though... id should be relative already) - var path = FileSystem.GetRelativePath(id); + var path = FileSystem.GetRelativePath(id!); if (FileSystem.FileExists(path) == false) return null; @@ -67,16 +71,20 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement partialView.GetFileContent = file => GetFileContent(file.OriginalPath); } - public override IEnumerable GetMany(params string[] ids) + public override IEnumerable GetMany(params string[]? ids) { //ensure they are de-duplicated, easy win if people don't do this as this can cause many excess queries - ids = ids.Distinct().ToArray(); + ids = ids?.Distinct().ToArray(); - if (ids.Any()) + if (ids?.Any() ?? false) { foreach (var id in ids) { - yield return Get(id); + var partialView = Get(id); + if (partialView is not null) + { + yield return partialView; + } } } else @@ -84,18 +92,22 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var files = FindAllFiles("", "*.*"); foreach (var file in files) { - yield return Get(file); + var partialView = Get(file); + if (partialView is not null) + { + yield return partialView; + } } } } - public Stream GetFileContentStream(string filepath) + public Stream? GetFileContentStream(string filepath) { - if (FileSystem.FileExists(filepath) == false) return null; + if (FileSystem?.FileExists(filepath) == false) return null; try { - return FileSystem.OpenFile(filepath); + return FileSystem?.OpenFile(filepath); } catch { @@ -105,7 +117,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement public void SetFileContent(string filepath, Stream content) { - FileSystem.AddFile(filepath, content, true); + FileSystem?.AddFile(filepath, content, true); } /// diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs index afcefdee2c..24a18380ac 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs @@ -142,7 +142,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// This will first clear the permissions for this user and entities and recreate them /// - public void ReplacePermissions(int groupId, IEnumerable permissions, params int[] entityIds) + public void ReplacePermissions(int groupId, IEnumerable? permissions, params int[] entityIds) { if (entityIds.Length == 0) { @@ -340,7 +340,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected override ContentPermissionSet PerformGet(int id) => throw new InvalidOperationException("This method won't be implemented."); - protected override IEnumerable PerformGetAll(params int[] ids) => + protected override IEnumerable PerformGetAll(params int[]? ids) => throw new InvalidOperationException("This method won't be implemented."); protected override IEnumerable PerformGetByQuery(IQuery query) => diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs index dbddb56b68..c7f7724d6d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs @@ -27,17 +27,17 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return new FullDataSetRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false); } - protected override PublicAccessEntry PerformGet(Guid id) + protected override PublicAccessEntry? PerformGet(Guid id) { //return from GetAll - this will be cached as a collection - return GetMany().FirstOrDefault(x => x.Key == id); + return GetMany()?.FirstOrDefault(x => x.Key == id); } - protected override IEnumerable PerformGetAll(params Guid[] ids) + protected override IEnumerable PerformGetAll(params Guid[]? ids) { var sql = GetBaseQuery(false); - if (ids.Any()) + if (ids?.Any() ?? false) { sql.WhereIn(x => x.Id, ids); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs index 5a15cc5b3d..a2686464f7 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs @@ -23,12 +23,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { } - public IRedirectUrl Get(string url, Guid contentKey, string culture) + public IRedirectUrl? Get(string url, Guid contentKey, string? culture) { var urlHash = url.GenerateHash(); Sql sql = GetBaseQuery(false).Where(x => x.Url == url && x.UrlHash == urlHash && x.ContentKey == contentKey && x.Culture == culture); - RedirectUrlDto dto = Database.Fetch(sql).FirstOrDefault(); + RedirectUrlDto? dto = Database.Fetch(sql).FirstOrDefault(); return dto == null ? null : Map(dto); } @@ -39,18 +39,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement public void Delete(Guid id) => Database.Delete(id); - public IRedirectUrl GetMostRecentUrl(string url) + public IRedirectUrl? GetMostRecentUrl(string url) { var urlHash = url.GenerateHash(); Sql sql = GetBaseQuery(false) .Where(x => x.Url == url && x.UrlHash == urlHash) .OrderByDescending(x => x.CreateDateUtc); List dtos = Database.Fetch(sql); - RedirectUrlDto dto = dtos.FirstOrDefault(); + RedirectUrlDto? dto = dtos.FirstOrDefault(); return dto == null ? null : Map(dto); } - public IRedirectUrl GetMostRecentUrl(string url, string culture) + public IRedirectUrl? GetMostRecentUrl(string url, string culture) { if (string.IsNullOrWhiteSpace(culture)) { @@ -63,7 +63,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement (x.Culture == culture.ToLower() || x.Culture == string.Empty)) .OrderByDescending(x => x.CreateDateUtc); List dtos = Database.Fetch(sql); - RedirectUrlDto dto = dtos.FirstOrDefault(f => f.Culture == culture.ToLower()); + RedirectUrlDto? dto = dtos.FirstOrDefault(f => f.Culture == culture.ToLower()); if (dto == null) { @@ -79,7 +79,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .Where(x => x.ContentKey == contentKey) .OrderByDescending(x => x.CreateDateUtc); List dtos = Database.Fetch(sql); - return dtos.Select(Map); + return dtos.Select(Map).WhereNotNull(); } public IEnumerable GetAllUrls(long pageIndex, int pageSize, out long total) @@ -88,7 +88,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .OrderByDescending(x => x.CreateDateUtc); Page result = Database.Page(pageIndex + 1, pageSize, sql); total = Convert.ToInt32(result.TotalItems); - return result.Items.Select(Map); + return result.Items.Select(Map).WhereNotNull(); } public IEnumerable GetAllUrls(int rootContentId, long pageIndex, int pageSize, out long total) @@ -101,7 +101,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement Page result = Database.Page(pageIndex + 1, pageSize, sql); total = Convert.ToInt32(result.TotalItems); - IEnumerable rules = result.Items.Select(Map); + IEnumerable rules = result.Items.Select(Map).WhereNotNull(); return rules; } @@ -116,7 +116,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement Page result = Database.Page(pageIndex + 1, pageSize, sql); total = Convert.ToInt32(result.TotalItems); - IEnumerable rules = result.Items.Select(Map); + IEnumerable rules = result.Items.Select(Map).WhereNotNull(); return rules; } @@ -125,16 +125,16 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected override bool PerformExists(Guid id) => PerformGet(id) != null; - protected override IRedirectUrl PerformGet(Guid id) + protected override IRedirectUrl? PerformGet(Guid id) { Sql sql = GetBaseQuery(false).Where(x => x.Id == id); - RedirectUrlDto dto = Database.Fetch(sql.SelectTop(1)).FirstOrDefault(); + RedirectUrlDto? dto = Database.Fetch(sql.SelectTop(1)).FirstOrDefault(); return dto == null ? null : Map(dto); } - protected override IEnumerable PerformGetAll(params Guid[] ids) + protected override IEnumerable PerformGetAll(params Guid[]? ids) { - if (ids.Length > Constants.Sql.MaxParameterCount) + if (ids?.Length > Constants.Sql.MaxParameterCount) { throw new NotSupportedException( $"This repository does not support more than {Constants.Sql.MaxParameterCount} ids."); @@ -142,7 +142,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement Sql sql = GetBaseQuery(false).WhereIn(x => x.Id, ids); List dtos = Database.Fetch(sql); - return dtos.WhereNotNull().Select(Map); + return dtos.WhereNotNull().Select(Map).WhereNotNull(); } protected override IEnumerable PerformGetByQuery(IQuery query) => @@ -177,18 +177,21 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID"); protected override void PersistNewItem(IRedirectUrl entity) { - RedirectUrlDto dto = Map(entity); + RedirectUrlDto? dto = Map(entity); Database.Insert(dto); entity.Id = entity.Key.GetHashCode(); } protected override void PersistUpdatedItem(IRedirectUrl entity) { - RedirectUrlDto dto = Map(entity); - Database.Update(dto); + RedirectUrlDto? dto = Map(entity); + if (dto is not null) + { + Database.Update(dto); + } } - private static RedirectUrlDto Map(IRedirectUrl redirectUrl) + private static RedirectUrlDto? Map(IRedirectUrl redirectUrl) { if (redirectUrl == null) { @@ -206,7 +209,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID"); }; } - private static IRedirectUrl Map(RedirectUrlDto dto) + private static IRedirectUrl? Map(RedirectUrlDto dto) { if (dto == null) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs index 718ea04f63..38c3335a1a 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs @@ -37,7 +37,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Overrides of RepositoryBase - protected override IRelation PerformGet(int id) + protected override IRelation? PerformGet(int id) { var sql = GetBaseQuery(false); sql.Where(GetBaseWhereClause(), new { id }); @@ -53,10 +53,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return DtoToEntity(dto, relationType); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { var sql = GetBaseQuery(false); - if (ids.Length > 0) + if (ids?.Length > 0) sql.WhereIn(x => x.Id, ids); sql.OrderBy(x => x.RelationType); var dtos = Database.Fetch(sql); @@ -80,7 +80,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return dtos.Select(x => DtoToEntity(x, _relationTypeRepository.Get(x.RelationType))).ToList(); } - private static IRelation DtoToEntity(RelationDto dto, IRelationType relationType) + private static IRelation DtoToEntity(RelationDto dto, IRelationType? relationType) { var entity = RelationFactory.BuildEntity(dto, relationType); @@ -279,7 +279,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } } - public IEnumerable GetPagedRelationsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, Ordering ordering) + public IEnumerable GetPagedRelationsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, Ordering? ordering) { var sql = GetBaseQuery(false); @@ -297,12 +297,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var dtos = page.Items; totalRecords = page.TotalItems; - var relTypes = _relationTypeRepository.GetMany(dtos.Select(x => x.RelationType).Distinct().ToArray()) + var relTypes = _relationTypeRepository.GetMany(dtos.Select(x => x.RelationType).Distinct().ToArray())? .ToDictionary(x => x.Id, x => x); var result = dtos.Select(r => { - if (!relTypes.TryGetValue(r.RelationType, out var relType)) + if (relTypes is null || !relTypes.TryGetValue(r.RelationType, out var relType)) throw new InvalidOperationException(string.Format("RelationType with Id: {0} doesn't exist", r.RelationType)); return DtoToEntity(r, relType); }).ToList(); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationTypeRepository.cs index f50e307cfa..5c89ecf2a7 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationTypeRepository.cs @@ -33,16 +33,16 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Overrides of RepositoryBase - protected override IRelationType PerformGet(int id) + protected override IRelationType? PerformGet(int id) { // use the underlying GetAll which will force cache all content types - return GetMany().FirstOrDefault(x => x.Id == id); + return GetMany()?.FirstOrDefault(x => x.Id == id); } - public IRelationType Get(Guid id) + public IRelationType? Get(Guid id) { // use the underlying GetAll which will force cache all content types - return GetMany().FirstOrDefault(x => x.Key == id); + return GetMany()?.FirstOrDefault(x => x.Key == id); } public bool Exists(Guid id) @@ -50,7 +50,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return Get(id) != null; } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { var sql = GetBaseQuery(false); @@ -59,10 +59,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return dtos.Select(x => DtoToEntity(x)); } - public IEnumerable GetMany(params Guid[] ids) + public IEnumerable? GetMany(params Guid[]? ids) { // should not happen due to the cache policy - if (ids.Any()) + if (ids?.Any() ?? false) throw new NotImplementedException(); return GetMany(new int[0]); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBase.cs index 4f82603710..e3fda464f7 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBase.cs @@ -39,7 +39,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { get { - IDatabaseScope scope = ScopeAccessor.AmbientScope; + IDatabaseScope? scope = ScopeAccessor.AmbientScope; if (scope == null) { throw new InvalidOperationException("Cannot run a repository without an ambient scope."); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs index 711a43f716..e50f29fd87 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs @@ -20,8 +20,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Implementation of IRepository - public override IScript Get(string id) + public override IScript? Get(string? id) { + if (id is null || FileSystem is null) + { + return null; + } // get the relative path within the filesystem // (though... id should be relative already) var path = FileSystem.GetRelativePath(id); @@ -63,16 +67,20 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement script.GetFileContent = file => GetFileContent(file.OriginalPath); } - public override IEnumerable GetMany(params string[] ids) + public override IEnumerable GetMany(params string[]? ids) { //ensure they are de-duplicated, easy win if people don't do this as this can cause many excess queries - ids = ids.Distinct().ToArray(); + ids = ids?.Distinct().ToArray(); - if (ids.Any()) + if (ids?.Any() ?? false) { foreach (var id in ids) { - yield return Get(id); + IScript? script = Get(id); + if (script is not null) + { + yield return script; + } } } else @@ -80,7 +88,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var files = FindAllFiles("", "*.*"); foreach (var file in files) { - yield return Get(file); + IScript? script = Get(file); + if (script is not null) + { + yield return script; + } } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs index 4d1ef3fa88..2a0bc9bfa1 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs @@ -47,16 +47,16 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected override bool PerformExists(int id) { // use the underlying GetAll which force-caches all registrations - return GetMany().Any(x => x.Id == id); + return GetMany()?.Any(x => x.Id == id) ?? false; } - protected override IServerRegistration PerformGet(int id) + protected override IServerRegistration? PerformGet(int id) { // use the underlying GetAll which force-caches all registrations - return GetMany().FirstOrDefault(x => x.Id == id); + return GetMany()?.FirstOrDefault(x => x.Id == id); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { return Database.Fetch("WHERE id > 0") .Select(x => ServerRegistrationFactory.BuildEntity(x)); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs index 116ec356b7..7021bab9d7 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs @@ -10,9 +10,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement internal class SimilarNodeName { public int Id { get; set; } - public string Name { get; set; } + public string? Name { get; set; } - public static string GetUniqueName(IEnumerable names, int nodeId, string nodeName) + public static string? GetUniqueName(IEnumerable names, int nodeId, string? nodeName) { var items = names .Where(x => x.Id != nodeId) // ignore same node @@ -23,11 +23,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return uniqueName; } - public static string GetUniqueName(IEnumerable names, string name) + public static string? GetUniqueName(IEnumerable names, string? name) { var model = new StructuredName(name); var items = names - .Where(x => x.InvariantStartsWith(model.Text)) // ignore non-matching names + .Where(x => x?.InvariantStartsWith(model.Text) ?? false) // ignore non-matching names .Select(x => new StructuredName(x)); // name is empty, and there are no other names with suffixes, so just return " (1)" @@ -174,7 +174,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } } - internal StructuredName(string name) + internal StructuredName(string? name) { if (string.IsNullOrWhiteSpace(name)) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimpleGetRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimpleGetRepository.cs index 2b7257ff8e..bf798b2845 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimpleGetRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimpleGetRepository.cs @@ -26,7 +26,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { } protected abstract TEntity ConvertToEntity(TDto dto); - protected abstract object GetBaseWhereClauseArguments(TId id); + protected abstract object GetBaseWhereClauseArguments(TId? id); protected abstract string GetWhereInClauseForGetAll(); protected virtual IEnumerable PerformFetch(Sql sql) @@ -34,7 +34,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return Database.Fetch(sql); } - protected override TEntity PerformGet(TId id) + protected override TEntity? PerformGet(TId? id) { var sql = GetBaseQuery(false); sql.Where(GetBaseWhereClause(), GetBaseWhereClauseArguments(id)); @@ -54,11 +54,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return entity; } - protected override IEnumerable PerformGetAll(params TId[] ids) + protected override IEnumerable PerformGetAll(params TId[]? ids) { var sql = Sql().From(); - if (ids.Any()) + if (ids?.Any() ?? false) { sql.Where(GetWhereInClauseForGetAll(), new { /*ids =*/ ids }); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs index 9c0aa6f92a..d22e54e76c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs @@ -19,8 +19,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Overrides of FileRepository - public override IStylesheet Get(string id) + public override IStylesheet? Get(string? id) { + if (id is null || FileSystem is null) + { + return null; + } // get the relative path within the filesystem // (though... id should be relative already) var path = FileSystem.GetRelativePath(id); @@ -73,19 +77,23 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement stylesheet.GetFileContent = file => GetFileContent(file.OriginalPath); } - public override IEnumerable GetMany(params string[] ids) + public override IEnumerable GetMany(params string[]? ids) { //ensure they are de-duplicated, easy win if people don't do this as this can cause many excess queries - ids = ids + ids = ids? .Select(x => x.EnsureEndsWith(".css")) .Distinct() .ToArray(); - if (ids.Any()) + if (ids?.Any() ?? false) { foreach (var id in ids) { - yield return Get(id); + IStylesheet? stylesheet = Get(id); + if (stylesheet is not null) + { + yield return stylesheet; + } } } else @@ -93,7 +101,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var files = FindAllFiles("", "*.css"); foreach (var file in files) { - yield return Get(file); + IStylesheet? stylesheet = Get(file); + if (stylesheet is not null) + { + yield return stylesheet; + } } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs index 900ff2934b..b53f976e22 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs @@ -28,19 +28,19 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Manage Tag Entities /// - protected override ITag PerformGet(int id) + protected override ITag? PerformGet(int id) { Sql sql = Sql().Select().From().Where(x => x.Id == id); - TagDto dto = Database.Fetch(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault(); + TagDto? dto = Database.Fetch(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault(); return dto == null ? null : TagFactory.BuildEntity(dto); } /// - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { - IEnumerable dtos = ids.Length == 0 + IEnumerable dtos = ids?.Length == 0 ? Database.Fetch(Sql().Select().From()) - : Database.FetchByGroups(ids, Constants.Sql.MaxParameterCount, + : Database.FetchByGroups(ids!, Constants.Sql.MaxParameterCount, batch => Sql().Select().From().WhereIn(x => x.Id, batch)); return dtos.Select(TagFactory.BuildEntity).ToList(); @@ -237,7 +237,7 @@ WHERE r.tagId IS NULL"; // used to run Distinct() on tags private class TagComparer : IEqualityComparer { - public bool Equals(ITag x, ITag y) => + public bool Equals(ITag? x, ITag? y) => ReferenceEquals(x, y) // takes care of both being null || (x != null && y != null && x.Text == y.Text && x.Group == y.Group && x.LanguageId == y.LanguageId); @@ -245,8 +245,8 @@ WHERE r.tagId IS NULL"; { unchecked { - var h = obj.Text.GetHashCode(); - h = (h * 397) ^ obj.Group.GetHashCode(); + var h = obj.Text?.GetHashCode() ?? 1; + h = (h * 397) ^ obj.Group?.GetHashCode() ?? 0; h = (h * 397) ^ (obj.LanguageId?.GetHashCode() ?? 0); return h; } @@ -265,17 +265,17 @@ WHERE r.tagId IS NULL"; private class TaggedEntityDto { public int NodeId { get; set; } - public string PropertyTypeAlias { get; set; } + public string? PropertyTypeAlias { get; set; } public int PropertyTypeId { get; set; } public int TagId { get; set; } - public string TagText { get; set; } - public string TagGroup { get; set; } + public string? TagText { get; set; } + public string? TagGroup { get; set; } public int? TagLanguage { get; set; } } // ReSharper restore UnusedAutoPropertyAccessor.Local /// - public TaggedEntity GetTaggedEntityByKey(Guid key) + public TaggedEntity? GetTaggedEntityByKey(Guid key) { Sql sql = GetTaggedEntitiesSql(TaggableObjectTypes.All, "*"); @@ -286,7 +286,7 @@ WHERE r.tagId IS NULL"; } /// - public TaggedEntity GetTaggedEntityById(int id) + public TaggedEntity? GetTaggedEntityById(int id) { Sql sql = GetTaggedEntitiesSql(TaggableObjectTypes.All, "*"); @@ -298,7 +298,7 @@ WHERE r.tagId IS NULL"; /// public IEnumerable GetTaggedEntitiesByTagGroup(TaggableObjectTypes objectType, string group, - string culture = null) + string? culture = null) { Sql sql = GetTaggedEntitiesSql(objectType, culture); @@ -310,7 +310,7 @@ WHERE r.tagId IS NULL"; /// public IEnumerable GetTaggedEntitiesByTag(TaggableObjectTypes objectType, string tag, - string group = null, string? culture = null) + string? group = null, string? culture = null) { Sql sql = GetTaggedEntitiesSql(objectType, culture); @@ -326,7 +326,7 @@ WHERE r.tagId IS NULL"; return Map(Database.Fetch(sql)); } - private Sql GetTaggedEntitiesSql(TaggableObjectTypes objectType, string culture) + private Sql GetTaggedEntitiesSql(TaggableObjectTypes objectType, string? culture) { Sql sql = Sql() .Select(x => Alias(x.NodeId, "NodeId")) @@ -368,7 +368,7 @@ WHERE r.tagId IS NULL"; { var taggedProperties = dtosForNode.GroupBy(x => x.PropertyTypeId).Select(dtosForProperty => { - string propertyTypeAlias = null; + string? propertyTypeAlias = null; var tags = dtosForProperty.Select(dto => { propertyTypeAlias = dto.PropertyTypeAlias; @@ -381,8 +381,8 @@ WHERE r.tagId IS NULL"; }).ToList(); /// - public IEnumerable GetTagsForEntityType(TaggableObjectTypes objectType, string group = null, - string culture = null) + public IEnumerable GetTagsForEntityType(TaggableObjectTypes objectType, string? group = null, + string? culture = null) { Sql sql = GetTagsSql(culture, true); @@ -408,7 +408,7 @@ WHERE r.tagId IS NULL"; } /// - public IEnumerable GetTagsForEntity(int contentId, string group = null, string? culture = null) + public IEnumerable GetTagsForEntity(int contentId, string? group = null, string? culture = null) { Sql sql = GetTagsSql(culture); @@ -427,7 +427,7 @@ WHERE r.tagId IS NULL"; } /// - public IEnumerable GetTagsForEntity(Guid contentId, string group = null, string? culture = null) + public IEnumerable GetTagsForEntity(Guid contentId, string? group = null, string? culture = null) { Sql sql = GetTagsSql(culture); @@ -446,8 +446,8 @@ WHERE r.tagId IS NULL"; } /// - public IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string group = null, - string culture = null) + public IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string? group = null, + string? culture = null) { Sql sql = GetTagsSql(culture); @@ -469,8 +469,8 @@ WHERE r.tagId IS NULL"; } /// - public IEnumerable GetTagsForProperty(Guid contentId, string propertyTypeAlias, string group = null, - string culture = null) + public IEnumerable GetTagsForProperty(Guid contentId, string propertyTypeAlias, string? group = null, + string? culture = null) { Sql sql = GetTagsSql(culture); @@ -491,7 +491,7 @@ WHERE r.tagId IS NULL"; return ExecuteTagsQuery(sql); } - private Sql GetTagsSql(string culture, bool withGrouping = false) + private Sql GetTagsSql(string? culture, bool withGrouping = false) { Sql sql = Sql() .Select(); @@ -518,7 +518,7 @@ WHERE r.tagId IS NULL"; return sql; } - private Sql AddTagsSqlWhere(Sql sql, string culture) + private Sql AddTagsSqlWhere(Sql sql, string? culture) { if (culture == null) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs index f318d4d31e..ec8b3854a2 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs @@ -28,7 +28,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { private readonly IIOHelper _ioHelper; private readonly IShortStringHelper _shortStringHelper; - private readonly IFileSystem _viewsFileSystem; + private readonly IFileSystem? _viewsFileSystem; private readonly IViewHelper _viewHelper; public TemplateRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, FileSystems fileSystems, IIOHelper ioHelper, IShortStringHelper shortStringHelper, IViewHelper viewHelper) @@ -45,15 +45,15 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Overrides of RepositoryBase - protected override ITemplate PerformGet(int id) => + protected override ITemplate? PerformGet(int id) => //use the underlying GetAll which will force cache all templates - base.GetMany().FirstOrDefault(x => x.Id == id); + base.GetMany()?.FirstOrDefault(x => x.Id == id); - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { Sql sql = GetBaseQuery(false); - if (ids.Any()) + if (ids?.Any() ?? false) { sql.Where("umbracoNode.id in (@ids)", new { ids }); } @@ -71,7 +71,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement //look up the simple template definitions that have a master template assigned, this is used // later to populate the template item's properties - IUmbracoEntity[] childIds = (ids.Any() + IUmbracoEntity[] childIds = (ids?.Any() ?? false ? GetAxisDefinitions(dtos.ToArray()) : dtos.Select(x => new EntitySlim { @@ -159,7 +159,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement int o = Database.IsNew(nodeDto) ? Convert.ToInt32(Database.Insert(nodeDto)) : Database.Update(nodeDto); //Update with new correct path - ITemplate parent = Get(template.MasterTemplateId.Value); + ITemplate? parent = Get(template.MasterTemplateId!.Value); if (parent != null) { nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId); @@ -195,19 +195,19 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement EnsureValidAlias(entity); //store the changed alias if there is one for use with updating files later - string originalAlias = entity.Alias; + string? originalAlias = entity.Alias; if (entity.IsPropertyDirty("Alias")) { //we need to check what it currently is before saving and remove that file - ITemplate current = Get(entity.Id); - originalAlias = current.Alias; + ITemplate? current = Get(entity.Id); + originalAlias = current?.Alias; } var template = (Template)entity; if (entity.IsPropertyDirty("MasterTemplateId")) { - ITemplate parent = Get(template.MasterTemplateId.Value); + ITemplate? parent = Get(template.MasterTemplateId!.Value); if (parent != null) { entity.Path = string.Concat(parent.Path, ",", entity.Id); @@ -245,9 +245,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } } - private void SaveFile(Template template, string originalAlias = null) + private void SaveFile(Template template, string? originalAlias = null) { - string content; + string? content; if (template is TemplateOnDisk templateOnDisk && templateOnDisk.IsOnDisk) { @@ -292,7 +292,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } string viewName = string.Concat(entity.Alias, ".cshtml"); - _viewsFileSystem.DeleteFile(viewName); + _viewsFileSystem?.DeleteFile(viewName); entity.DeleteDate = DateTime.Now; } @@ -338,7 +338,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement if (dto.NodeDto.ParentId > 0) { - IUmbracoEntity masterTemplate = axisDefinitions.FirstOrDefault(x => x.Id == dto.NodeDto.ParentId); + IUmbracoEntity? masterTemplate = axisDefinitions.FirstOrDefault(x => x.Id == dto.NodeDto.ParentId); if (masterTemplate != null) { template.MasterTemplateAlias = masterTemplate.Name; @@ -363,13 +363,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { // we need to discover the path path = string.Concat(template.Alias, ".cshtml"); - if (_viewsFileSystem.FileExists(path)) + if (_viewsFileSystem?.FileExists(path) ?? false) { template.VirtualPath = _viewsFileSystem.GetUrl(path); return; } path = string.Concat(template.Alias, ".vbhtml"); - if (_viewsFileSystem.FileExists(path)) + if (_viewsFileSystem?.FileExists(path) ?? false) { template.VirtualPath = _viewsFileSystem.GetUrl(path); return; @@ -378,26 +378,26 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement else { // we know the path already - template.VirtualPath = _viewsFileSystem.GetUrl(path); + template.VirtualPath = _viewsFileSystem?.GetUrl(path); } template.VirtualPath = string.Empty; // file not found... } - private string GetFileContent(ITemplate template, bool init) + private string? GetFileContent(ITemplate template, bool init) { string path = template.OriginalPath; if (string.IsNullOrWhiteSpace(path)) { // we need to discover the path path = string.Concat(template.Alias, ".cshtml"); - if (_viewsFileSystem.FileExists(path)) + if (_viewsFileSystem?.FileExists(path) ?? false) { return GetFileContent(template, _viewsFileSystem, path, init); } path = string.Concat(template.Alias, ".vbhtml"); - if (_viewsFileSystem.FileExists(path)) + if (_viewsFileSystem?.FileExists(path) ?? false) { return GetFileContent(template, _viewsFileSystem, path, init); } @@ -413,11 +413,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return string.Empty; } - private string GetFileContent(ITemplate template, IFileSystem fs, string filename, bool init) + private string? GetFileContent(ITemplate template, IFileSystem? fs, string filename, bool init) { // do not update .UpdateDate as that would make it dirty (side-effect) // unless initializing, because we have to do it once - if (init) + if (init && fs is not null) { template.UpdateDate = fs.GetLastModified(filename).UtcDateTime; } @@ -429,31 +429,39 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // template.UpdateDate = fs.GetLastModified(filename).UtcDateTime; // xtemplate.EnableChangeTracking(); - template.VirtualPath = fs.GetUrl(filename); + template.VirtualPath = fs?.GetUrl(filename); return init ? null : GetFileContent(fs, filename); } - private string GetFileContent(IFileSystem fs, string filename) + private string? GetFileContent(IFileSystem? fs, string filename) { - using (Stream stream = fs.OpenFile(filename)) - using (var reader = new StreamReader(stream, Encoding.UTF8, true)) + if (fs is null) { + return null; + } + + using Stream? stream = fs.OpenFile(filename); + if (stream is not null) + { + using var reader = new StreamReader(stream, Encoding.UTF8, true); return reader.ReadToEnd(); } + + return null; } - public Stream GetFileContentStream(string filepath) + public Stream? GetFileContentStream(string filepath) { - IFileSystem fileSystem = GetFileSystem(filepath); - if (fileSystem.FileExists(filepath) == false) + IFileSystem? fileSystem = GetFileSystem(filepath); + if (fileSystem?.FileExists(filepath) == false) { return null; } try { - return fileSystem.OpenFile(filepath); + return fileSystem!.OpenFile(filepath); } catch { @@ -461,19 +469,19 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } } - public void SetFileContent(string filepath, Stream content) => GetFileSystem(filepath).AddFile(filepath, content, true); + public void SetFileContent(string filepath, Stream content) => GetFileSystem(filepath)?.AddFile(filepath, content, true); public long GetFileSize(string filename) { - IFileSystem fileSystem = GetFileSystem(filename); - if (fileSystem.FileExists(filename) == false) + IFileSystem? fileSystem = GetFileSystem(filename); + if (fileSystem?.FileExists(filename) == false) { return -1; } try { - return fileSystem.GetSize(filename); + return fileSystem!.GetSize(filename); } catch { @@ -481,10 +489,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } } - private IFileSystem GetFileSystem(string filepath) + private IFileSystem? GetFileSystem(string filepath) { string ext = Path.GetExtension(filepath); - IFileSystem fs; + IFileSystem? fs; switch (ext) { case ".cshtml": @@ -499,9 +507,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Implementation of ITemplateRepository - public ITemplate Get(string alias) => GetAll(alias).FirstOrDefault(); + public ITemplate? Get(string? alias) => GetAll(alias)?.FirstOrDefault(); - public IEnumerable GetAll(params string[] aliases) + public IEnumerable? GetAll(params string?[] aliases) { //We must call the base (normal) GetAll method // which is cached. This is a specialized method and unfortunately with the params[] it @@ -512,37 +520,37 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } //return from base.GetAll, this is all cached - return base.GetMany().Where(x => aliases.InvariantContains(x.Alias)); + return base.GetMany()?.Where(x => aliases.WhereNotNull().InvariantContains(x.Alias)); } - public IEnumerable GetChildren(int masterTemplateId) + public IEnumerable? GetChildren(int masterTemplateId) { //return from base.GetAll, this is all cached - ITemplate[] all = base.GetMany().ToArray(); + ITemplate[]? all = base.GetMany()?.ToArray(); if (masterTemplateId <= 0) { - return all.Where(x => x.MasterTemplateAlias.IsNullOrWhiteSpace()); + return all?.Where(x => x.MasterTemplateAlias.IsNullOrWhiteSpace()); } - ITemplate parent = all.FirstOrDefault(x => x.Id == masterTemplateId); + ITemplate? parent = all?.FirstOrDefault(x => x.Id == masterTemplateId); if (parent == null) { return Enumerable.Empty(); } - IEnumerable children = all.Where(x => x.MasterTemplateAlias.InvariantEquals(parent.Alias)); + IEnumerable? children = all?.Where(x => x.MasterTemplateAlias.InvariantEquals(parent.Alias)); return children; } public IEnumerable GetDescendants(int masterTemplateId) { //return from base.GetAll, this is all cached - ITemplate[] all = base.GetMany().ToArray(); + ITemplate[]? all = base.GetMany()?.ToArray(); var descendants = new List(); if (masterTemplateId > 0) { - ITemplate parent = all.FirstOrDefault(x => x.Id == masterTemplateId); + ITemplate? parent = all?.FirstOrDefault(x => x.Id == masterTemplateId); if (parent == null) { return Enumerable.Empty(); @@ -553,11 +561,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } else { - descendants.AddRange(all.Where(x => x.MasterTemplateAlias.IsNullOrWhiteSpace())); - foreach (ITemplate parent in descendants) + if (all is not null) { - //recursively add all children with a level - AddChildren(all, descendants, parent.Alias); + descendants.AddRange(all.Where(x => x.MasterTemplateAlias.IsNullOrWhiteSpace())); + foreach (ITemplate parent in descendants) + { + //recursively add all children with a level + AddChildren(all, descendants, parent.Alias); + } } } @@ -565,14 +576,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return descendants; } - private void AddChildren(ITemplate[] all, List descendants, string masterAlias) + private void AddChildren(ITemplate[]? all, List descendants, string masterAlias) { - ITemplate[] c = all.Where(x => x.MasterTemplateAlias.InvariantEquals(masterAlias)).ToArray(); - descendants.AddRange(c); - if (c.Any() == false) + ITemplate[]? c = all?.Where(x => x.MasterTemplateAlias.InvariantEquals(masterAlias)).ToArray(); + if (c is null || c.Any() == false) { return; } + descendants.AddRange(c); //recurse through all children foreach (ITemplate child in c) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TwoFactorLoginRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TwoFactorLoginRepository.cs index 4b3ccb4d6a..b74063df9b 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TwoFactorLoginRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TwoFactorLoginRepository.cs @@ -42,18 +42,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected override IEnumerable GetDeleteClauses() => Enumerable.Empty(); - protected override ITwoFactorLogin PerformGet(int id) + protected override ITwoFactorLogin? PerformGet(int id) { var sql = GetBaseQuery(false).Where(x => x.Id == id); var dto = Database.Fetch(sql).FirstOrDefault(); return dto == null ? null : Map(dto); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { var sql = GetBaseQuery(false).WhereIn(x => x.Id, ids); var dtos = Database.Fetch(sql); - return dtos.WhereNotNull().Select(Map); + return dtos.WhereNotNull().Select(Map).WhereNotNull(); } protected override IEnumerable PerformGetByQuery(IQuery query) @@ -61,7 +61,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var sqlClause = GetBaseQuery(false); var translator = new SqlTranslator(sqlClause, query); var sql = translator.Translate(); - return Database.Fetch(sql).Select(Map); + return Database.Fetch(sql).Select(Map).WhereNotNull(); } protected override void PersistNewItem(ITwoFactorLogin entity) @@ -73,10 +73,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement protected override void PersistUpdatedItem(ITwoFactorLogin entity) { var dto = Map(entity); - Database.Update(dto); + if (dto is not null) + { + Database.Update(dto); + } } - private static TwoFactorLoginDto Map(ITwoFactorLogin entity) + private static TwoFactorLoginDto? Map(ITwoFactorLogin entity) { if (entity == null) return null; @@ -89,7 +92,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement }; } - private static ITwoFactorLogin Map(TwoFactorLoginDto dto) + private static ITwoFactorLogin? Map(TwoFactorLoginDto dto) { if (dto == null) return null; @@ -107,7 +110,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return await DeleteUserLoginsAsync(userOrMemberKey, null); } - public async Task DeleteUserLoginsAsync(Guid userOrMemberKey, string providerName) + public async Task DeleteUserLoginsAsync(Guid userOrMemberKey, string? providerName) { var sql = Sql() .Delete() @@ -131,7 +134,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .From() .Where(x => x.UserOrMemberKey == userOrMemberKey); var dtos = await Database.FetchAsync(sql); - return dtos.WhereNotNull().Select(Map); + return dtos.WhereNotNull().Select(Map).WhereNotNull(); } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs index b27f42858a..d19c896690 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs @@ -42,7 +42,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return CacheKeys.UserGroupGetByAliasCacheKeyPrefix + alias; } - public IUserGroup Get(string alias) + public IUserGroup? Get(string alias) { try { @@ -88,7 +88,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return Database.Fetch(sql).Select(x => UserGroupFactory.BuildEntity(_shortStringHelper, x)); } - public void AddOrUpdateGroupWithUsers(IUserGroup userGroup, int[] userIds) + public void AddOrUpdateGroupWithUsers(IUserGroup userGroup, int[]? userIds) { _userGroupWithUsersRepository.Save(new UserGroupWithUsers(userGroup, userIds)); } @@ -138,7 +138,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement // a struct of the nodeid + groupid so then we don't actually allocate this class just to check if it's not // going to be included in the result! - var defaultPermission = new EntityPermission(group.Id, nodeId, group.Permissions.ToArray(), isDefaultPermissions: true); + var defaultPermission = new EntityPermission(group.Id, nodeId, group.Permissions?.ToArray() ?? Array.Empty(), isDefaultPermissions: true); //Since this is a hashset, this will not add anything that already exists by group/node combination result.Add(defaultPermission); } @@ -154,7 +154,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// Id of group /// Permissions as enumerable list of If nothing is specified all permissions are removed. /// Specify the nodes to replace permissions for. - public void ReplaceGroupPermissions(int groupId, IEnumerable permissions, params int[] entityIds) + public void ReplaceGroupPermissions(int groupId, IEnumerable? permissions, params int[] entityIds) { _permissionRepository.ReplacePermissions(groupId, permissions, entityIds); } @@ -172,7 +172,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Overrides of RepositoryBase - protected override IUserGroup PerformGet(int id) + protected override IUserGroup? PerformGet(int id) { var sql = GetBaseQuery(QueryType.Single); sql.Where(GetBaseWhereClause(), new { id = id }); @@ -189,11 +189,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return userGroup; } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { var sql = GetBaseQuery(QueryType.Many); - if (ids.Any()) + if (ids?.Any() ?? false) sql.WhereIn(x => x.Id, ids); else sql.Where(x => x.Id >= 0); @@ -346,7 +346,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// private class UserGroupWithUsers : EntityBase { - public UserGroupWithUsers(IUserGroup userGroup, int[] userIds) + public UserGroupWithUsers(IUserGroup userGroup, int[]? userIds) { UserGroup = userGroup; UserIds = userIds; @@ -355,7 +355,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement public override bool HasIdentity => UserGroup.HasIdentity; public IUserGroup UserGroup { get; } - public int[] UserIds { get; } + public int[]? UserIds { get; } } /// @@ -378,7 +378,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement throw new InvalidOperationException("This method won't be implemented."); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { throw new InvalidOperationException("This method won't be implemented."); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs index b4724b8885..7027c83e1d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs @@ -34,7 +34,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private readonly UserPasswordConfigurationSettings _passwordConfiguration; private readonly IJsonSerializer _jsonSerializer; private readonly IRuntimeState _runtimeState; - private string _passwordConfigJson; + private string? _passwordConfigJson; private bool _passwordConfigInitialized; /// @@ -74,7 +74,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Returns a serialized dictionary of the password configuration that is stored against the user in the database /// - private string DefaultPasswordConfigJson + private string? DefaultPasswordConfigJson { get { @@ -96,7 +96,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement #region Overrides of RepositoryBase - protected override IUser PerformGet(int id) + protected override IUser? PerformGet(int id) { // This will never resolve to a user, yet this is asked // for all of the time (especially in cases of members). @@ -141,7 +141,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// A non cached instance /// - public IUser GetByUsername(string username, bool includeSecurityData) + public IUser? GetByUsername(string username, bool includeSecurityData) { return GetWith(sql => sql.Where(x => x.Login == username), includeSecurityData); } @@ -157,18 +157,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// A non cached instance /// - public IUser Get(int? id, bool includeSecurityData) + public IUser? Get(int? id, bool includeSecurityData) { return GetWith(sql => sql.Where(x => x.Id == id), includeSecurityData); } - public IProfile GetProfile(string username) + public IProfile? GetProfile(string username) { var dto = GetDtoWith(sql => sql.Where(x => x.Login == username), false); return dto == null ? null : new UserProfile(dto.Id, dto.UserName); } - public IProfile GetProfile(int id) + public IProfile? GetProfile(int id) { var dto = GetDtoWith(sql => sql.Where(x => x.Id == id), false); return dto == null ? null : new UserProfile(dto.Id, dto.UserName); @@ -269,9 +269,9 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 .Where(x => x.SessionId == sessionId)); } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[]? ids) { - var dtos = ids.Length == 0 + var dtos = ids?.Length == 0 ? GetDtosWith(null, true) : GetDtosWith(sql => sql.WhereIn(x => x.Id, ids), true); var users = new IUser[dtos.Count]; @@ -284,7 +284,7 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 protected override IEnumerable PerformGetByQuery(IQuery query) { var dtos = GetDtosWith(sql => new SqlTranslator(sql, query).Translate(), true) - .LegacyDistinctBy(x => x.Id) + .LegacyDistinctBy(x => x!.Id) .ToList(); var users = new IUser[dtos.Count]; @@ -294,19 +294,19 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 return users; } - private IUser GetWith(Action> with, bool includeReferences) + private IUser? GetWith(Action> with, bool includeReferences) { var dto = GetDtoWith(with, includeReferences); return dto == null ? null : UserFactory.BuildEntity(_globalSettings, dto); } - private UserDto GetDtoWith(Action> with, bool includeReferences) + private UserDto? GetDtoWith(Action> with, bool includeReferences) { var dtos = GetDtosWith(with, includeReferences); return dtos.FirstOrDefault(); } - private List GetDtosWith(Action> with, bool includeReferences) + private List GetDtosWith(Action>? with, bool includeReferences) { var sql = SqlContext.Sql() .Select() @@ -630,8 +630,12 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 entity.ResetDirtyProperties(); } - private void AddingOrUpdateStartNodes(IEntity entity, IEnumerable current, UserStartNodeDto.StartNodeTypeValue startNodeType, int[] entityStartIds) + private void AddingOrUpdateStartNodes(IEntity entity, IEnumerable current, UserStartNodeDto.StartNodeTypeValue startNodeType, int[]? entityStartIds) { + if (entityStartIds is null) + { + return; + } var assignedIds = current.Where(x => x.StartNodeType == (int)startNodeType).Select(x => x.StartNode).ToArray(); //remove the ones not assigned to the entity @@ -757,13 +761,13 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 /// /// The query supplied will ONLY work with data specifically on the umbracoUser table because we are using NPoco paging (SQL paging) /// - public IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, - Expression> orderBy, Direction orderDirection = Direction.Ascending, - string[] includeUserGroups = null, string[] excludeUserGroups = null, UserState[] userState = null, IQuery filter = null) + public IEnumerable GetPagedResultsByQuery(IQuery? query, long pageIndex, int pageSize, out long totalRecords, + Expression> orderBy, Direction orderDirection = Direction.Ascending, + string[]? includeUserGroups = null, string[]? excludeUserGroups = null, UserState[]? userState = null, IQuery? filter = null) { if (orderBy == null) throw new ArgumentNullException(nameof(orderBy)); - Sql filterSql = null; + Sql? filterSql = null; var customFilterWheres = filter?.GetWhereClauses().ToArray(); var hasCustomFilter = customFilterWheres != null && customFilterWheres.Length > 0; if (hasCustomFilter @@ -774,8 +778,8 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 if (hasCustomFilter) { - foreach (var clause in customFilterWheres) - filterSql.Append($"AND ({clause.Item1})", clause.Item2); + foreach (var clause in customFilterWheres!) + filterSql?.Append($"AND ({clause.Item1})", clause.Item2); } if (includeUserGroups != null && includeUserGroups.Length > 0) @@ -785,7 +789,7 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 INNER JOIN umbracoUser2UserGroup ON umbracoUser2UserGroup.userId = umbracoUser.id INNER JOIN umbracoUserGroup ON umbracoUserGroup.id = umbracoUser2UserGroup.userGroupId WHERE umbracoUserGroup.userGroupAlias IN (@userGroups)))"; - filterSql.Append(subQuery, new { userGroups = includeUserGroups }); + filterSql?.Append(subQuery, new { userGroups = includeUserGroups }); } if (excludeUserGroups != null && excludeUserGroups.Length > 0) @@ -795,7 +799,7 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 INNER JOIN umbracoUser2UserGroup ON umbracoUser2UserGroup.userId = umbracoUser.id INNER JOIN umbracoUserGroup ON umbracoUserGroup.id = umbracoUser2UserGroup.userGroupId WHERE umbracoUserGroup.userGroupAlias IN (@userGroups)))"; - filterSql.Append(subQuery, new { userGroups = excludeUserGroups }); + filterSql?.Append(subQuery, new { userGroups = excludeUserGroups }); } if (userState != null && userState.Length > 0) @@ -837,7 +841,7 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 } sb.Append(")"); - filterSql.Append("AND " + sb); + filterSql?.Append("AND " + sb); } } @@ -862,7 +866,7 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 return pagedResult.Items.Select(x => UserFactory.BuildEntity(_globalSettings, x)); } - private Sql ApplyFilter(Sql sql, Sql filterSql, bool hasWhereClause) + private Sql ApplyFilter(Sql sql, Sql? filterSql, bool hasWhereClause) { if (filterSql == null) return sql; @@ -877,13 +881,13 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 return sql; } - private Sql ApplySort(Sql sql, Expression> orderBy, Direction orderDirection) + private Sql ApplySort(Sql sql, Expression> orderBy, Direction orderDirection) { if (orderBy == null) return sql; var expressionMember = ExpressionHelper.GetMemberInfo(orderBy); var mapper = _mapperCollection[typeof(IUser)]; - var mappedField = mapper.Map(expressionMember.Name); + var mappedField = mapper.Map(expressionMember?.Name); if (mappedField.IsNullOrWhiteSpace()) throw new ArgumentException("Could not find a mapping for the column specified in the orderBy clause"); @@ -923,7 +927,7 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 var ids = Database.Page(1, count, idsQuery).Items.ToArray(); // now get the actual users and ensure they are ordered properly (same clause) - return ids.Length == 0 ? Enumerable.Empty() : GetMany(ids).OrderBy(x => x.Id); + return ids.Length == 0 ? Enumerable.Empty() : GetMany(ids)?.OrderBy(x => x.Id) ?? Enumerable.Empty(); } #endregion diff --git a/src/Umbraco.Infrastructure/Persistence/SqlContext.cs b/src/Umbraco.Infrastructure/Persistence/SqlContext.cs index f1f3233a45..6eb903c1f5 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlContext.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlContext.cs @@ -22,7 +22,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// The Poco data factory. /// The database type. /// The mappers. - public SqlContext(ISqlSyntaxProvider sqlSyntax, DatabaseType databaseType, IPocoDataFactory pocoDataFactory, IMapperCollection mappers = null) + public SqlContext(ISqlSyntaxProvider sqlSyntax, DatabaseType databaseType, IPocoDataFactory pocoDataFactory, IMapperCollection? mappers = null) { // for tests Mappers = mappers; @@ -55,6 +55,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence public IPocoDataFactory PocoDataFactory { get; } /// - public IMapperCollection Mappers { get; } + public IMapperCollection? Mappers { get; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/SqlContextExtensions.cs b/src/Umbraco.Infrastructure/Persistence/SqlContextExtensions.cs index 867daf7941..22252b5463 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlContextExtensions.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlContextExtensions.cs @@ -51,7 +51,7 @@ namespace Umbraco.Extensions /// An optional table alias for the first DTO. /// An optional table alias for the second DTO. /// A SQL statement, and arguments, corresponding to the expression. - public static (string Sql, object[] Args) VisitDto(this ISqlContext sqlContext, Expression> expression, string? alias1 = null, string? alias2 = null) + public static (string Sql, object[] Args) VisitDto(this ISqlContext sqlContext, Expression> expression, string? alias1 = null, string? alias2 = null) { var visitor = new PocoToSqlExpressionVisitor(sqlContext, alias1, alias2); var visited = visitor.Visit(expression); diff --git a/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs index c16e5a75ab..8dd45283e7 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs @@ -20,7 +20,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence _globalSettings = globalSettings; } - public DbProviderFactory CreateFactory(string providerName) + public DbProviderFactory? CreateFactory(string? providerName) { if (string.IsNullOrEmpty(providerName)) return null; diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/ColumnInfo.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/ColumnInfo.cs index 46d21e5894..f177a25bc4 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/ColumnInfo.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/ColumnInfo.cs @@ -24,7 +24,7 @@ public string TableName { get; set; } public string ColumnName { get; set; } public int Ordinal { get; set; } - public string ColumnDefault { get; set; } + public string? ColumnDefault { get; set; } public bool IsNullable { get; set; } public string DataType { get; set; } } diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/ISqlSyntaxProvider.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/ISqlSyntaxProvider.cs index 9a8b61f9ec..e3de457894 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/ISqlSyntaxProvider.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/ISqlSyntaxProvider.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Diagnostics.CodeAnalysis; using System.Text.RegularExpressions; using NPoco; using Umbraco.Cms.Core.Persistence; @@ -130,7 +131,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax /// in which case the function may return true, but is /// unspecified. /// - bool TryGetDefaultConstraint(IDatabase db, string? tableName, string columnName, out string constraintName); + bool TryGetDefaultConstraint(IDatabase db, string? tableName, string columnName, [MaybeNullWhen(false)] out string constraintName); void ReadLock(IDatabase db, TimeSpan timeout, int lockId); void WriteLock(IDatabase db, TimeSpan timeout, int lockId); diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs index f045f379e4..c9b05dd9a0 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs @@ -29,18 +29,18 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax public override string AddColumn => "ALTER TABLE {0} ADD {1}"; - public override string GetQuotedTableName(string tableName) + public override string GetQuotedTableName(string? tableName) { - if (tableName.Contains(".") == false) + if (tableName?.Contains(".") == false) return $"[{tableName}]"; - var tableNameParts = tableName.Split(Constants.CharArrays.Period, 2); - return $"[{tableNameParts[0]}].[{tableNameParts[1]}]"; + var tableNameParts = tableName?.Split(Constants.CharArrays.Period, 2); + return $"[{tableNameParts?[0]}].[{tableNameParts?[1]}]"; } - public override string GetQuotedColumnName(string columnName) => $"[{columnName}]"; + public override string GetQuotedColumnName(string? columnName) => $"[{columnName}]"; - public override string GetQuotedName(string name) => $"[{name}]"; + public override string GetQuotedName(string? name) => $"[{name}]"; public override string GetStringColumnEqualComparison(string column, int paramIndex, TextColumnType columnType) { diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs index 2db603ad1a..bffda81bd0 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.Data.SqlClient; using Microsoft.Extensions.Logging; @@ -28,7 +29,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax public override string ProviderName => Cms.Core.Constants.DatabaseProviders.SqlServer; - public ServerVersionInfo ServerVersion { get; private set; } + public ServerVersionInfo? ServerVersion { get; private set; } public enum VersionName { @@ -75,14 +76,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax ProductLevel = productLevel; } - public string Edition { get; } - public string InstanceName { get; } - public string ProductVersion { get; } + public string? Edition { get; } + public string? InstanceName { get; } + public string? ProductVersion { get; } public VersionName ProductVersionName { get; } public EngineEdition EngineEdition { get; } public bool IsAzure => EngineEdition == EngineEdition.Azure; - public string MachineName { get; } - public string ProductLevel { get; } + public string? MachineName { get; } + public string? ProductLevel { get; } } private static VersionName MapProductVersion(string productVersion) @@ -115,7 +116,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax } } - internal ServerVersionInfo GetSetVersion(string connectionString, string providerName, ILogger logger) + internal ServerVersionInfo GetSetVersion(string? connectionString, string? providerName, ILogger logger) { //var factory = DbProviderFactories.GetFactory(providerName); var factory = SqlClientFactory.Instance; @@ -190,7 +191,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax return items.Select(x => new Tuple(x.TableName, x.ColumnName, x.Name, x.Definition)); } - public override string DbProvider => ServerVersion.IsAzure ? "SqlAzure" : "SqlServer"; + public override string DbProvider => ServerVersion?.IsAzure ?? false ? "SqlAzure" : "SqlServer"; public override IEnumerable GetTablesInSchema(IDatabase db) { @@ -246,7 +247,7 @@ order by T.name, I.name"); } /// - public override bool TryGetDefaultConstraint(IDatabase db, string tableName, string columnName, out string constraintName) + public override bool TryGetDefaultConstraint(IDatabase db, string? tableName, string columnName, [MaybeNullWhen(false)] out string constraintName) { constraintName = db.Fetch(@"select con.[name] as [constraintName] from sys.default_constraints con @@ -367,12 +368,12 @@ where tbl.[name]=@0 and col.[name]=@1;", tableName, columnName) } } - public override string FormatColumnRename(string tableName, string oldName, string newName) + public override string FormatColumnRename(string? tableName, string? oldName, string? newName) { return string.Format(RenameColumn, tableName, oldName, newName); } - public override string FormatTableRename(string oldName, string newName) + public override string FormatTableRename(string? oldName, string? newName) { return string.Format(RenameTable, oldName, newName); } @@ -392,7 +393,7 @@ where tbl.[name]=@0 and col.[name]=@1;", tableName, columnName) return "IDENTITY(1,1)"; } - protected override string FormatSystemMethods(SystemMethods systemMethod) + protected override string? FormatSystemMethods(SystemMethods systemMethod) { switch (systemMethod) { diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs index 5dbf97021d..86dd570b43 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Text; @@ -161,17 +162,17 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax return "concat(" + string.Join(",", args) + ")"; } - public virtual string GetQuotedTableName(string tableName) + public virtual string GetQuotedTableName(string? tableName) { return $"\"{tableName}\""; } - public virtual string GetQuotedColumnName(string columnName) + public virtual string GetQuotedColumnName(string? columnName) { return $"\"{columnName}\""; } - public virtual string GetQuotedName(string name) + public virtual string GetQuotedName(string? name) { return $"\"{name}\""; } @@ -241,7 +242,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax public abstract IEnumerable> GetDefinedIndexes(IDatabase db); - public abstract bool TryGetDefaultConstraint(IDatabase db, string tableName, string columnName, out string constraintName); + public abstract bool TryGetDefaultConstraint(IDatabase db, string? tableName, string columnName, [MaybeNullWhen(false)] out string constraintName); public abstract void ReadLock(IDatabase db, params int[] lockIds); public abstract void WriteLock(IDatabase db, params int[] lockIds); @@ -431,7 +432,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax columns); } - public virtual string FormatColumnRename(string tableName, string oldName, string newName) + public virtual string FormatColumnRename(string? tableName, string? oldName, string? newName) { return string.Format(RenameColumn, GetQuotedTableName(tableName), @@ -439,7 +440,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax GetQuotedColumnName(newName)); } - public virtual string FormatTableRename(string oldName, string newName) + public virtual string FormatTableRename(string? oldName, string? newName) { return string.Format(RenameTable, GetQuotedTableName(oldName), GetQuotedTableName(newName)); } @@ -540,7 +541,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax return string.IsNullOrEmpty(method) ? string.Empty : string.Format(DefaultValueFormat, method); } - return string.Format(DefaultValueFormat, GetQuotedValue(column.DefaultValue.ToString())); + return string.Format(DefaultValueFormat, GetQuotedValue(column.DefaultValue.ToString()!)); } protected virtual string FormatPrimaryKey(ColumnDefinition column) @@ -548,7 +549,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax return string.Empty; } - protected abstract string FormatSystemMethods(SystemMethods systemMethod); + protected abstract string? FormatSystemMethods(SystemMethods systemMethod); protected abstract string FormatIdentity(ColumnDefinition column); diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntaxExtensions.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntaxExtensions.cs index 43606686cd..7f66b75880 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlSyntaxExtensions.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntaxExtensions.cs @@ -35,7 +35,7 @@ namespace Umbraco.Extensions /// An expression specifying the field. /// An optional table alias. /// - public static string GetFieldName(this ISqlSyntaxProvider sqlSyntax, Expression> fieldSelector, string? tableAlias = null) + public static string GetFieldName(this ISqlSyntaxProvider sqlSyntax, Expression> fieldSelector, string? tableAlias = null) { var field = ExpressionHelper.FindProperty(fieldSelector).Item1 as PropertyInfo; var fieldName = field?.GetColumnName(); diff --git a/src/Umbraco.Infrastructure/Persistence/SqlTemplate.cs b/src/Umbraco.Infrastructure/Persistence/SqlTemplate.cs index 8939a44cbe..716b24bb07 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlTemplate.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlTemplate.cs @@ -11,17 +11,17 @@ namespace Umbraco.Cms.Infrastructure.Persistence { private readonly ISqlContext _sqlContext; private readonly string _sql; - private readonly Dictionary _args; + private readonly Dictionary? _args; // these are created in PocoToSqlExpressionVisitor internal class TemplateArg { - public TemplateArg(string name) + public TemplateArg(string? name) { Name = name; } - public string Name { get; } + public string? Name { get; } public override string ToString() { @@ -36,7 +36,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence if (args.Length > 0) _args = new Dictionary(); for (var i = 0; i < args.Length; i++) - _args[i] = args[i]; + _args![i] = args[i]; } public Sql Sql() @@ -54,7 +54,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence if (args.Length == 1 && args[0].GetType().Name.Contains("<")) return SqlNamed(args[0]); - if (args.Length != _args.Count) + if (args.Length != _args?.Count) throw new ArgumentException("Invalid number of arguments.", nameof(args)); if (args.Length == 0) @@ -69,23 +69,23 @@ namespace Umbraco.Cms.Infrastructure.Persistence public Sql SqlNamed(object nargs) { var isBuilt = true; - var args = new object[_args.Count]; + var args = new object[_args?.Count ?? 0]; var properties = nargs.GetType().GetProperties().ToDictionary(x => x.Name, x => x.GetValue(nargs)); - for (var i = 0; i < _args.Count; i++) + for (var i = 0; i < _args?.Count; i++) { - object value; + object? value; if (_args[i] is TemplateArg templateArg) { - if (!properties.TryGetValue(templateArg.Name, out value)) + if (!properties.TryGetValue(templateArg.Name ?? string.Empty, out value)) throw new InvalidOperationException($"Missing argument \"{templateArg.Name}\"."); - properties.Remove(templateArg.Name); + properties.Remove(templateArg.Name!); } else { value = _args[i]; } - args[i] = value; + args[i] = value!; // if value is enumerable then we'll need to expand arguments if (value is IEnumerable) @@ -98,7 +98,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence internal string ToText() { - var sql = new Sql(_sqlContext, _sql, _args.Values.ToArray()); + var sql = new Sql(_sqlContext, _sql, _args?.Values.ToArray()); return sql.ToText(); } @@ -110,12 +110,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// /// Gets a WHERE expression argument. /// - public static T Arg(string name) => default; + public static T? Arg(string name) => default; /// /// Gets a WHERE IN expression argument. /// - public static IEnumerable ArgIn(string name) + public static IEnumerable ArgIn(string name) { // don't return an empty enumerable, as it breaks NPoco return new[] { default (T) }; diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs index 1529d6c575..30a97313da 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs @@ -25,13 +25,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence public class UmbracoDatabase : Database, IUmbracoDatabase { private readonly ILogger _logger; - private readonly IBulkSqlInsertProvider _bulkSqlInsertProvider; - private readonly DatabaseSchemaCreatorFactory _databaseSchemaCreatorFactory; + private readonly IBulkSqlInsertProvider? _bulkSqlInsertProvider; + private readonly DatabaseSchemaCreatorFactory? _databaseSchemaCreatorFactory; private readonly RetryPolicy? _connectionRetryPolicy; private readonly RetryPolicy? _commandRetryPolicy; private readonly IEnumerable? _mapperCollection; private readonly Guid _instanceGuid = Guid.NewGuid(); - private List _commands; + private List? _commands; #region Ctor @@ -47,7 +47,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence ISqlContext sqlContext, DbProviderFactory provider, ILogger logger, - IBulkSqlInsertProvider bulkSqlInsertProvider, + IBulkSqlInsertProvider? bulkSqlInsertProvider, DatabaseSchemaCreatorFactory databaseSchemaCreatorFactory, RetryPolicy? connectionRetryPolicy = null, RetryPolicy? commandRetryPolicy = null, @@ -128,7 +128,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence private int _spid = -1; private const bool EnableSqlTraceDefault = true; #else - private string _instanceId; + private string? _instanceId; private const bool EnableSqlTraceDefault = false; #endif @@ -194,19 +194,19 @@ namespace Umbraco.Cms.Infrastructure.Persistence set => _commands = value ? new List() : null; } - internal IEnumerable Commands => _commands; + internal IEnumerable? Commands => _commands; - public int BulkInsertRecords(IEnumerable records) => _bulkSqlInsertProvider.BulkInsertRecords(this, records); + public int BulkInsertRecords(IEnumerable records) => _bulkSqlInsertProvider?.BulkInsertRecords(this, records) ?? 0; /// /// Returns the for the database /// public DatabaseSchemaResult ValidateSchema() { - var dbSchema = _databaseSchemaCreatorFactory.Create(this); - var databaseSchemaValidationResult = dbSchema.ValidateSchema(); + var dbSchema = _databaseSchemaCreatorFactory?.Create(this); + var databaseSchemaValidationResult = dbSchema?.ValidateSchema(); - return databaseSchemaValidationResult; + return databaseSchemaValidationResult ?? new DatabaseSchemaResult(); } /// @@ -270,12 +270,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence base.OnException(ex); } - private DbCommand _cmd; + private DbCommand? _cmd; protected override void OnExecutingCommand(DbCommand cmd) { // if no timeout is specified, and the connection has a longer timeout, use it - if (OneTimeCommandTimeout == 0 && CommandTimeout == 0 && cmd.Connection.ConnectionTimeout > 30) + if (OneTimeCommandTimeout == 0 && CommandTimeout == 0 && cmd.Connection?.ConnectionTimeout > 30) cmd.CommandTimeout = cmd.Connection.ConnectionTimeout; if (EnableSqlTrace) @@ -293,9 +293,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence base.OnExecutingCommand(cmd); } - private string CommandToString(DbCommand cmd) => CommandToString(cmd.CommandText, cmd.Parameters.Cast().Select(x => x.Value).ToArray()); + private string CommandToString(DbCommand cmd) => CommandToString(cmd.CommandText, cmd.Parameters.Cast().Select(x => x.Value).WhereNotNull().ToArray()); - private string CommandToString(string sql, object[] args) + private string CommandToString(string? sql, object[]? args) { var text = new StringBuilder(); #if DEBUG_DATABASES @@ -350,7 +350,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence } public string Name { get; } - public object Value { get; } + public object? Value { get; } public DbType DbType { get; } public int Size { get; } } diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseExtensions.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseExtensions.cs index ae2a17dc7c..fff81a322d 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseExtensions.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseExtensions.cs @@ -24,7 +24,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// Gets a dictionary of key/values directly from the database, no scope, nothing. /// /// Used by to determine the runtime state. - public static IReadOnlyDictionary GetFromKeyValueTable(this IUmbracoDatabase database, string keyPrefix) + public static IReadOnlyDictionary? GetFromKeyValueTable(this IUmbracoDatabase database, string keyPrefix) { if (database is null) return null; @@ -41,7 +41,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence .Where(whereParam, keyPrefix + sqlSyntax.GetWildcardPlaceholder()); return database.Fetch(sql) - .ToDictionary(x => x.Key, x => x.Value); + .ToDictionary(x => x.Key!, x => x.Value); } diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs index 5fcccb21a3..799c4f5729 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs @@ -41,16 +41,16 @@ namespace Umbraco.Cms.Infrastructure.Persistence private object _lock = new object(); - private DatabaseFactory _npocoDatabaseFactory; - private IPocoDataFactory _pocoDataFactory; - private string _providerName; - private DatabaseType _databaseType; - private ISqlSyntaxProvider _sqlSyntax; - private IBulkSqlInsertProvider _bulkSqlInsertProvider; - private RetryPolicy _connectionRetryPolicy; - private RetryPolicy _commandRetryPolicy; - private NPoco.MapperCollection _pocoMappers; - private SqlContext _sqlContext; + private DatabaseFactory? _npocoDatabaseFactory; + private IPocoDataFactory? _pocoDataFactory; + private string? _providerName; + private DatabaseType? _databaseType; + private ISqlSyntaxProvider? _sqlSyntax; + private IBulkSqlInsertProvider? _bulkSqlInsertProvider; + private RetryPolicy? _connectionRetryPolicy; + private RetryPolicy? _commandRetryPolicy; + private NPoco.MapperCollection? _pocoMappers; + private SqlContext? _sqlContext; private bool _upgrading; private bool _initialized; @@ -150,10 +150,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence public bool Initialized => Volatile.Read(ref _initialized); /// - public string ConnectionString { get; private set; } + public string? ConnectionString { get; private set; } /// - public string ProviderName => _providerName; + public string? ProviderName => _providerName; /// public bool CanConnect => @@ -170,7 +170,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence if (setting.IsNullOrWhiteSpace() || !setting.StartsWith("SqlServer.") || !Enum.TryParse(setting.Substring("SqlServer.".Length), out var versionName, true)) { - versionName = ((SqlServerSyntaxProvider) _sqlSyntax).GetSetVersion(ConnectionString, _providerName, _logger).ProductVersionName; + versionName = ((SqlServerSyntaxProvider?) _sqlSyntax)!.GetSetVersion(ConnectionString, _providerName, _logger).ProductVersionName; } else { @@ -197,7 +197,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence } /// - public ISqlContext SqlContext + public ISqlContext? SqlContext { get { @@ -209,7 +209,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence } /// - public IBulkSqlInsertProvider BulkSqlInsertProvider + public IBulkSqlInsertProvider? BulkSqlInsertProvider { get { @@ -224,7 +224,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence public void ConfigureForUpgrade() => _upgrading = true; /// - public void Configure(string connectionString, string providerName) + public void Configure(string? connectionString, string? providerName) { if (connectionString.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(connectionString)); if (providerName.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(providerName)); @@ -262,8 +262,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence throw new Exception($"Can't find a provider factory for provider name \"{_providerName}\"."); } - _connectionRetryPolicy = RetryPolicyFactory.GetDefaultSqlConnectionRetryPolicyByConnectionString(ConnectionString); - _commandRetryPolicy = RetryPolicyFactory.GetDefaultSqlCommandRetryPolicyByConnectionString(ConnectionString); + _connectionRetryPolicy = RetryPolicyFactory.GetDefaultSqlConnectionRetryPolicyByConnectionString(ConnectionString!); + _commandRetryPolicy = RetryPolicyFactory.GetDefaultSqlCommandRetryPolicyByConnectionString(ConnectionString!); _databaseType = DatabaseType.Resolve(DbProviderFactory.GetType().Name, _providerName); if (_databaseType == null) @@ -271,13 +271,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence throw new Exception($"Can't find an NPoco database type for provider name \"{_providerName}\"."); } - _sqlSyntax = _dbProviderFactoryCreator.GetSqlSyntaxProvider(_providerName); + _sqlSyntax = _dbProviderFactoryCreator.GetSqlSyntaxProvider(_providerName!); if (_sqlSyntax == null) { throw new Exception($"Can't find a sql syntax provider for provider name \"{_providerName}\"."); } - _bulkSqlInsertProvider = _dbProviderFactoryCreator.CreateBulkSqlInsertProvider(_providerName); + _bulkSqlInsertProvider = _dbProviderFactoryCreator.CreateBulkSqlInsertProvider(_providerName!); if (_databaseType.IsSqlServer()) { @@ -290,7 +290,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence // add all registered mappers for NPoco _pocoMappers.AddRange(_npocoMappers); - _pocoMappers.AddRange(_dbProviderFactoryCreator.ProviderSpecificMappers(_providerName)); + _pocoMappers.AddRange(_dbProviderFactoryCreator.ProviderSpecificMappers(_providerName!)); var factory = new FluentPocoDataFactory(GetPocoDataFactoryResolver, _pocoMappers); _pocoDataFactory = factory; @@ -312,11 +312,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence } /// - public IUmbracoDatabase CreateDatabase() + public IUmbracoDatabase? CreateDatabase() { // must be initialized to create a database EnsureInitialized(); - return (IUmbracoDatabase) _npocoDatabaseFactory.GetDatabase(); + return (IUmbracoDatabase?) _npocoDatabaseFactory?.GetDatabase(); } // gets initialized poco data builders @@ -326,8 +326,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence // method used by NPoco's UmbracoDatabaseFactory to actually create the database instance - private UmbracoDatabase CreateDatabaseInstance() - => new UmbracoDatabase( + private UmbracoDatabase? CreateDatabaseInstance() + { + if (ConnectionString is null || SqlContext is null || DbProviderFactory is null) + { + return null; + } + return new UmbracoDatabase( ConnectionString, SqlContext, DbProviderFactory, @@ -337,7 +342,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence _connectionRetryPolicy, _commandRetryPolicy, _pocoMappers - ); + ); + } + protected override void DisposeResources() { diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoPocoDataBuilder.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoPocoDataBuilder.cs index 0b874a80c2..753563faff 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoPocoDataBuilder.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoPocoDataBuilder.cs @@ -22,7 +22,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence { private readonly bool _upgrading; - public UmbracoPocoDataBuilder(Type type, MapperCollection mapper, bool upgrading) + public UmbracoPocoDataBuilder(Type type, MapperCollection? mapper, bool upgrading) : base(type, mapper) { _upgrading = upgrading; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs index af407f6b00..cd5919acf3 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs @@ -216,7 +216,7 @@ namespace Umbraco.Cms.Core.PropertyEditors foreach (var prop in row.PropertyValues) { // Fetch the property types prevalue - var propConfiguration = _dataTypeService.GetDataType(prop.Value.PropertyType.DataTypeId).Configuration; + var propConfiguration = _dataTypeService.GetDataType(prop.Value.PropertyType.DataTypeId)?.Configuration; // Lookup the property editor var propEditor = _propertyEditors[prop.Value.PropertyType.PropertyEditorAlias]; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs index 7b4ca284a8..67ac2c05e7 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs @@ -75,7 +75,7 @@ namespace Umbraco.Cms.Core.PropertyEditors try { var o = _jsonSerializer.Deserialize(item.Value); - o.SortOrder = sortOrder; + o!.SortOrder = sortOrder; return o; } catch diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs index 19f48b4ac3..c4d7b1dd43 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs @@ -210,7 +210,7 @@ namespace Umbraco.Cms.Core.PropertyEditors return val; // more magic here ;-( - var configuration = _dataTypeService.GetDataType(propertyType.DataTypeId).ConfigurationAs(); + var configuration = _dataTypeService.GetDataType(propertyType.DataTypeId)?.ConfigurationAs(); var crops = configuration?.Crops ?? Array.Empty(); return JsonConvert.SerializeObject(new diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs index b65dcb0ec9..32ff2de20c 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs @@ -146,10 +146,14 @@ namespace Umbraco.Cms.Core.PropertyEditors } else { - // New JSON format - foreach (var dto in jsonSerializer.Deserialize>(rawJson)) + var dtos = jsonSerializer.Deserialize>(rawJson); + if (dtos is not null) { - yield return dto; + // New JSON format + foreach (var dto in dtos) + { + yield return dto; + } } } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs index 13a9f562cf..0e13fca028 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs @@ -119,7 +119,7 @@ namespace Umbraco.Cms.Core.PropertyEditors var propEditor = _propertyEditors[prop.Value.PropertyType.PropertyEditorAlias]; if (propEditor == null) continue; - var tempConfig = _dataTypeService.GetDataType(prop.Value.PropertyType.DataTypeId).Configuration; + var tempConfig = _dataTypeService.GetDataType(prop.Value.PropertyType.DataTypeId)?.Configuration; var valEditor = propEditor.GetValueEditor(tempConfig); var convValue = valEditor.ConvertDbToString(prop.Value.PropertyType, prop.Value.Value); @@ -190,7 +190,7 @@ namespace Umbraco.Cms.Core.PropertyEditors var dataTypeId = prop.Value.PropertyType.DataTypeId; if (!valEditors.TryGetValue(dataTypeId, out var valEditor)) { - var tempConfig = _dataTypeService.GetDataType(dataTypeId).Configuration; + var tempConfig = _dataTypeService.GetDataType(dataTypeId)?.Configuration; valEditor = propEditor.GetValueEditor(tempConfig); valEditors.Add(dataTypeId, valEditor); @@ -238,7 +238,7 @@ namespace Umbraco.Cms.Core.PropertyEditors foreach(var prop in row.PropertyValues.ToList()) { // Fetch the property types prevalue - var propConfiguration = _dataTypeService.GetDataType(prop.Value.PropertyType.DataTypeId).Configuration; + var propConfiguration = _dataTypeService.GetDataType(prop.Value.PropertyType.DataTypeId)?.Configuration; // Lookup the property editor var propEditor = _propertyEditors[prop.Value.PropertyType.PropertyEditorAlias]; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiUrlPickerValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiUrlPickerValueConverter.cs index 9ea9e82836..17a423923d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiUrlPickerValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiUrlPickerValueConverter.cs @@ -59,6 +59,10 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters var links = new List(); var dtos = _jsonSerializer.Deserialize>(inter.ToString()!); var publishedSnapshot = _publishedSnapshotAccessor.GetRequiredPublishedSnapshot(); + if (dtos is null) + { + return links; + } foreach (var dto in dtos) { var type = LinkType.External; diff --git a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs index fe09336f4a..36041d2c47 100644 --- a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs +++ b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs @@ -238,14 +238,14 @@ namespace Umbraco.Cms.Infrastructure.Runtime // no scope, no service - just directly accessing the database using (var database = databaseFactory.CreateDatabase()) { - if (!database.IsUmbracoInstalled()) + if (!database!.IsUmbracoInstalled()) { return UmbracoDatabaseState.NotInstalled; } // Make ONE SQL call to determine Umbraco upgrade vs package migrations state. // All will be prefixed with the same key. - IReadOnlyDictionary keyValues = database.GetFromKeyValueTable(Constants.Conventions.Migrations.KeyValuePrefix); + IReadOnlyDictionary? keyValues = database!.GetFromKeyValueTable(Constants.Conventions.Migrations.KeyValuePrefix); // This could need both an upgrade AND package migrations to execute but // we will process them one at a time, first the upgrade, then the package migrations. @@ -277,14 +277,16 @@ namespace Umbraco.Cms.Infrastructure.Runtime } } - private bool DoesUmbracoRequireUpgrade(IReadOnlyDictionary keyValues) + private bool DoesUmbracoRequireUpgrade(IReadOnlyDictionary? keyValues) { var upgrader = new Upgrader(new UmbracoPlan(_umbracoVersion)); var stateValueKey = upgrader.StateValueKey; - _ = keyValues.TryGetValue(stateValueKey, out var value); + if(keyValues?.TryGetValue(stateValueKey, out var value) ?? false) + { + CurrentMigrationState = value; + } - CurrentMigrationState = value; FinalMigrationState = upgrader.Plan.FinalState; _logger.LogDebug("Final upgrade state is {FinalMigrationState}, database contains {DatabaseState}", FinalMigrationState, CurrentMigrationState ?? ""); diff --git a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs index e4e05817eb..64f83eee35 100644 --- a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs +++ b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs @@ -101,7 +101,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime return true; } - if (!(_dbFactory.SqlContext.SqlSyntax is SqlServerSyntaxProvider sqlServerSyntaxProvider)) + if (!(_dbFactory.SqlContext?.SqlSyntax is SqlServerSyntaxProvider sqlServerSyntaxProvider)) { throw new NotSupportedException("SqlMainDomLock is only supported for Sql Server"); } @@ -119,7 +119,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime db = _dbFactory.CreateDatabase(); - _hasTable = db.HasTable(Cms.Core.Constants.DatabaseSchema.Tables.KeyValue); + _hasTable = db!.HasTable(Cms.Core.Constants.DatabaseSchema.Tables.KeyValue); if (!_hasTable) { _logger.LogDebug("The DB does not contain the required table so we must be in an install state. We have no choice but to assume we can acquire."); @@ -127,7 +127,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime return true; } - db.BeginTransaction(IsolationLevel.ReadCommitted); + db!.BeginTransaction(IsolationLevel.ReadCommitted); try { @@ -241,7 +241,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime { // re-check if its still false, we don't want to re-query once we know its there since this // loop needs to use minimal resources - _hasTable = db.HasTable(Cms.Core.Constants.DatabaseSchema.Tables.KeyValue); + _hasTable = db!.HasTable(Cms.Core.Constants.DatabaseSchema.Tables.KeyValue); if (!_hasTable) { // the Db does not contain the required table, we just keep looping since we can't query the db @@ -253,10 +253,10 @@ namespace Umbraco.Cms.Infrastructure.Runtime if (_acquireWhenTablesNotAvailable) { _acquireWhenTablesNotAvailable = false; - InsertLockRecord(_lockId, db); + InsertLockRecord(_lockId, db!); } - db.BeginTransaction(IsolationLevel.ReadCommitted); + db!.BeginTransaction(IsolationLevel.ReadCommitted); // get a read lock _sqlServerSyntax.ReadLock(db, Cms.Core.Constants.Locks.MainDom); @@ -316,13 +316,13 @@ namespace Umbraco.Cms.Infrastructure.Runtime // local testing shows the actual query to be executed from client/server is approx 300ms but would change depending on environment/IO Thread.Sleep(1000); - var acquired = TryAcquire(db, tempId, updatedTempId); + var acquired = TryAcquire(db!, tempId, updatedTempId); if (acquired.HasValue) return acquired.Value; if (watch.ElapsedMilliseconds >= millisecondsTimeout) { - return AcquireWhenMaxWaitTimeElapsed(db); + return AcquireWhenMaxWaitTimeElapsed(db!); } } } @@ -366,7 +366,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime _logger.LogDebug("Acquired with ID {LockId}", _lockId); return true; } - else if (mainDomRows.Count == 1 && !mainDomRows[0].Value.StartsWith(tempId)) + else if (mainDomRows.Count == 1 && (!mainDomRows[0].Value?.StartsWith(tempId) ?? false)) { // in this case, the prefixed ID is different which means // another new AppDomain has come online and is wanting to take over. In that case, we will not @@ -502,7 +502,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime try { db = _dbFactory.CreateDatabase(); - db.BeginTransaction(IsolationLevel.ReadCommitted); + db!.BeginTransaction(IsolationLevel.ReadCommitted); // get a write lock _sqlServerSyntax.WriteLock(db, Cms.Core.Constants.Locks.MainDom); diff --git a/src/Umbraco.Infrastructure/Scoping/Scope.cs b/src/Umbraco.Infrastructure/Scoping/Scope.cs index d89fa8fb47..6429d9109a 100644 --- a/src/Umbraco.Infrastructure/Scoping/Scope.cs +++ b/src/Umbraco.Infrastructure/Scoping/Scope.cs @@ -396,13 +396,13 @@ namespace Umbraco.Cms.Core.Scoping // enter a transaction, as a scope implies a transaction, always try { - _database.BeginTransaction(IsolationLevel); + _database!.BeginTransaction(IsolationLevel); EnsureDbLocks(); return _database; } catch { - _database.Dispose(); + _database?.Dispose(); _database = null; throw; } diff --git a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs index a453b3fcbd..c3d7f028c7 100644 --- a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs +++ b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs @@ -60,9 +60,9 @@ namespace Umbraco.Cms.Core.Scoping public IUmbracoDatabaseFactory DatabaseFactory { get; } - public ISqlContext SqlContext => DatabaseFactory.SqlContext; + public ISqlContext? SqlContext => DatabaseFactory.SqlContext; - public IQuery CreateQuery() => SqlContext.Query(); + public IQuery? CreateQuery() => SqlContext?.Query(); #region Context diff --git a/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs b/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs index 25f39cca07..20eea6a3df 100644 --- a/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs @@ -472,7 +472,7 @@ namespace Umbraco.Cms.Core.Security && user.Name != identityUser.Name && identityUser.Name.IsNullOrWhiteSpace() == false) { anythingChanged = true; - user.Name = identityUser.Name; + user.Name = identityUser.Name ?? string.Empty; } if (identityUser.IsPropertyDirty(nameof(BackOfficeIdentityUser.Email)) diff --git a/src/Umbraco.Infrastructure/Security/UmbracoUserManager.cs b/src/Umbraco.Infrastructure/Security/UmbracoUserManager.cs index 0504ddb85b..3a75511fb7 100644 --- a/src/Umbraco.Infrastructure/Security/UmbracoUserManager.cs +++ b/src/Umbraco.Infrastructure/Security/UmbracoUserManager.cs @@ -110,7 +110,7 @@ namespace Umbraco.Cms.Core.Security var isValid = true; foreach (IPasswordValidator v in PasswordValidators) { - IdentityResult result = await v.ValidateAsync(this, null, password); + IdentityResult result = await v.ValidateAsync(this, null!, password); if (!result.Succeeded) { if (result.Errors.Any()) diff --git a/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs b/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs index 2b856ec98f..e779161f06 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs @@ -35,7 +35,7 @@ namespace Umbraco.Cms.Core.Services.Implement } } - public IEnumerable GetLogs(int objectId) + public IEnumerable? GetLogs(int objectId) { using (var scope = ScopeProvider.CreateScope()) { @@ -200,7 +200,7 @@ namespace Umbraco.Cms.Core.Services.Implement } // TODO: Currently used in testing only, not part of the interface, need to add queryable methods to the interface instead - internal IEnumerable GetAll() + internal IEnumerable? GetAll() { if (_isAvailable.Value == false) return Enumerable.Empty(); diff --git a/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs b/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs index 54c171a1a6..cfdd7fcc04 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs @@ -104,7 +104,7 @@ namespace Umbraco.Cms.Core.Services.Implement } } - public EntityContainer GetContainer(Guid containerId) + public EntityContainer? GetContainer(Guid containerId) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { @@ -120,7 +120,7 @@ namespace Umbraco.Cms.Core.Services.Implement } } - public IEnumerable GetContainers(IDataType dataType) + public IEnumerable? GetContainers(IDataType dataType) { var ancestorIds = dataType.Path.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries) .Select(x => @@ -134,7 +134,7 @@ namespace Umbraco.Cms.Core.Services.Implement return GetContainers(ancestorIds); } - public IEnumerable GetContainers(int[] containerIds) + public IEnumerable? GetContainers(int[] containerIds) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { @@ -188,7 +188,7 @@ namespace Umbraco.Cms.Core.Services.Implement // 'container' here does not know about its children, so we need // to get it again from the entity repository, as a light entity var entity = _entityRepository.Get(container.Id); - if (entity.HasChildren) + if (entity?.HasChildren ?? false) { scope.Complete(); return Attempt.Fail(new OperationResult(OperationResultType.FailedCannot, evtMsgs)); @@ -258,7 +258,7 @@ namespace Umbraco.Cms.Core.Services.Implement { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { - var dataType = _dataTypeRepository.Get(Query().Where(x => x.Name == name)).FirstOrDefault(); + var dataType = _dataTypeRepository.Get(Query().Where(x => x.Name == name))?.FirstOrDefault(); ConvertMissingEditorOfDataTypeToLabel(dataType); return dataType; } @@ -289,7 +289,7 @@ namespace Umbraco.Cms.Core.Services.Implement using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query().Where(x => x.Key == id); - var dataType = _dataTypeRepository.Get(query).FirstOrDefault(); + var dataType = _dataTypeRepository.Get(query)?.FirstOrDefault(); ConvertMissingEditorOfDataTypeToLabel(dataType); return dataType; } @@ -300,12 +300,16 @@ namespace Umbraco.Cms.Core.Services.Implement /// /// Alias of the property editor /// Collection of objects with a matching control id - public IEnumerable GetByEditorAlias(string propertyEditorAlias) + public IEnumerable? GetByEditorAlias(string propertyEditorAlias) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query().Where(x => x.EditorAlias == propertyEditorAlias); var dataType = _dataTypeRepository.Get(query); + if (dataType is null) + { + return null; + } ConvertMissingEditorsOfDataTypesToLabels(dataType); return dataType; } @@ -316,11 +320,16 @@ namespace Umbraco.Cms.Core.Services.Implement /// /// Optional array of Ids /// An enumerable list of objects - public IEnumerable GetAll(params int[] ids) + public IEnumerable? GetAll(params int[] ids) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var dataTypes = _dataTypeRepository.GetMany(ids); + if (dataTypes is null) + { + return null; + } + ConvertMissingEditorsOfDataTypesToLabels(dataTypes); return dataTypes; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs index db81c3f79f..2d795c734a 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs @@ -52,9 +52,9 @@ namespace Umbraco.Cms.Core.Services.Implement ((ServerRegistrationRepository) _serverRegistrationRepository).ClearCache(); // ensure we have up-to-date cache - var regs = _serverRegistrationRepository.GetMany().ToArray(); - var hasSchedulingPublisher = regs.Any(x => ((ServerRegistration) x).IsSchedulingPublisher); - var server = regs.FirstOrDefault(x => x.ServerIdentity?.InvariantEquals(serverIdentity) ?? false); + var regs = _serverRegistrationRepository.GetMany()?.ToArray(); + var hasSchedulingPublisher = regs?.Any(x => ((ServerRegistration) x).IsSchedulingPublisher); + var server = regs?.FirstOrDefault(x => x.ServerIdentity?.InvariantEquals(serverIdentity) ?? false); if (server == null) { @@ -75,11 +75,11 @@ namespace Umbraco.Cms.Core.Services.Implement // reload - cheap, cached - regs = _serverRegistrationRepository.GetMany().ToArray(); + regs = _serverRegistrationRepository.GetMany()?.ToArray(); // default role is single server, but if registrations contain more // than one active server, then role is scheduling publisher or subscriber - _currentServerRole = regs.Count(x => x.IsActive) > 1 + _currentServerRole = regs?.Count(x => x.IsActive) > 1 ? (server.IsSchedulingPublisher ? ServerRole.SchedulingPublisher : ServerRole.Subscriber) : ServerRole.Single; @@ -101,7 +101,7 @@ namespace Umbraco.Cms.Core.Services.Implement ((ServerRegistrationRepository) _serverRegistrationRepository).ClearCache(); // ensure we have up-to-date cache // ensure we have up-to-date cache - var server = _serverRegistrationRepository.GetMany().FirstOrDefault(x => x.ServerIdentity?.InvariantEquals(serverIdentity) ?? false); + var server = _serverRegistrationRepository.GetMany()?.FirstOrDefault(x => x.ServerIdentity?.InvariantEquals(serverIdentity) ?? false); if (server == null) return; server.IsActive = server.IsSchedulingPublisher = false; _serverRegistrationRepository.Save(server); // will trigger a cache reload // will trigger a cache reload @@ -133,13 +133,13 @@ namespace Umbraco.Cms.Core.Services.Implement /// time the current server is touched, and the period depends on the configuration. Use the /// parameter to force a cache refresh and reload active servers /// from the database. - public IEnumerable GetActiveServers(bool refresh = false) + public IEnumerable? GetActiveServers(bool refresh = false) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Cms.Core.Constants.Locks.Servers); if (refresh) ((ServerRegistrationRepository) _serverRegistrationRepository).ClearCache(); - return _serverRegistrationRepository.GetMany().Where(x => x.IsActive).ToArray(); // fast, cached // fast, cached + return _serverRegistrationRepository.GetMany()?.Where(x => x.IsActive).ToArray(); // fast, cached // fast, cached } }