private IEnumerable <IMember> MapDtosToContent(List <MemberDto> dtos, bool withCache = false) { var temps = new List <TempContent <Member> >(); var contentTypes = new Dictionary <int, IMemberType?>(); var content = new Member[dtos.Count]; for (var i = 0; i < dtos.Count; i++) { MemberDto dto = dtos[i]; if (withCache) { // if the cache contains the (proper version of the) item, use it IMember?cached = IsolatedCache.GetCacheItem <IMember>(RepositoryCacheKeys.GetKey <IMember, int>(dto.NodeId)); if (cached != null && cached.VersionId == dto.ContentVersionDto.Id) { content[i] = (Member)cached; continue; } } // else, need to build it // 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) { contentTypes[contentTypeId] = contentType = _memberTypeRepository.Get(contentTypeId); } Member c = content[i] = ContentBaseFactory.BuildEntity(dto, contentType); // need properties var versionId = dto.ContentVersionDto.Id; temps.Add(new TempContent <Member>(dto.NodeId, versionId, 0, contentType, c)); } // load all properties for all documents from database in 1 query - indexed by version id IDictionary <int, PropertyCollection> properties = GetPropertyCollections(temps); // assign properties foreach (TempContent <Member> temp in temps) { if (temp.Content is not null) { temp.Content.Properties = properties[temp.VersionId]; // reset dirty initial properties (U4-1946) temp.Content.ResetDirtyProperties(false); } } return(content); }
private IMember MapDtoToContent(MemberDto dto) { var memberType = _memberTypeRepository.Get(dto.ContentDto.ContentTypeId); var member = ContentBaseFactory.BuildEntity(dto, memberType); // get properties - indexed by version id var versionId = dto.ContentVersionDto.Id; var temp = new TempContent <Member>(dto.ContentDto.NodeId, versionId, 0, memberType); var properties = GetPropertyCollections(new List <TempContent <Member> > { temp }); member.Properties = properties[versionId]; // reset dirty initial properties (U4-1946) member.ResetDirtyProperties(false); return(member); }
private IMedia MapDtoToContent(ContentDto dto) { IMediaType?contentType = _mediaTypeRepository.Get(dto.ContentTypeId); Core.Models.Media media = ContentBaseFactory.BuildEntity(dto, contentType); // get properties - indexed by version id var versionId = dto.ContentVersionDto.Id; var temp = new TempContent <Core.Models.Media>(dto.NodeId, versionId, 0, contentType); IDictionary <int, PropertyCollection> properties = GetPropertyCollections(new List <TempContent <Core.Models.Media> > { temp }); media.Properties = properties[versionId]; // reset dirty initial properties (U4-1946) media.ResetDirtyProperties(false); return(media); }
private void MigrateMediaPaths() { // this may not be the most efficient way to do it, compared to how it's done in v7, but this // migration should only run for v8 sites that are being developed, before v8 is released, so // no big sites and performances don't matter here - keep it simple var sql = Sql() .Select <PropertyDataDto>(x => x.VarcharValue, x => x.TextValue) .AndSelect <ContentVersionDto>(x => Alias(x.Id, "versionId")) .From <PropertyDataDto>() .InnerJoin <PropertyTypeDto>().On <PropertyDataDto, PropertyTypeDto>((left, right) => left.PropertyTypeId == right.Id) .InnerJoin <ContentVersionDto>().On <PropertyDataDto, ContentVersionDto>((left, right) => left.VersionId == right.Id) .InnerJoin <NodeDto>().On <ContentVersionDto, NodeDto>((left, right) => left.NodeId == right.NodeId) .Where <PropertyTypeDto>(x => x.Alias == "umbracoFile") .Where <NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Media); var paths = new List <MediaVersionDto>(); //using QUERY = a db cursor, we won't load this all into memory first, just row by row foreach (var row in Database.Query <dynamic>(sql)) { // if there's values then ensure there's a media path match and extract it string mediaPath = null; if ( (row.varcharValue != null && ContentBaseFactory.TryMatch((string)row.varcharValue, out mediaPath)) || (row.textValue != null && ContentBaseFactory.TryMatch((string)row.textValue, out mediaPath))) { paths.Add(new MediaVersionDto { Id = (int)row.versionId, Path = mediaPath }); } } // bulk insert Database.BulkInsertRecords(paths); }
protected override void PersistUpdatedItem(IMember entity) { // update entity.UpdatingEntity(); // ensure security stamp if missing if (entity.SecurityStamp.IsNullOrWhiteSpace()) { entity.SecurityStamp = Guid.NewGuid().ToString(); } // ensure that strings don't contain characters that are invalid in xml // TODO: do we really want to keep doing this here? entity.SanitizeEntityPropertiesForXmlStorage(); // if parent has changed, get path, level and sort order if (entity.IsPropertyDirty("ParentId")) { NodeDto parent = GetParentNodeDto(entity.ParentId); entity.Path = string.Concat(parent.Path, ",", entity.Id); entity.Level = parent.Level + 1; entity.SortOrder = GetNewChildSortOrder(entity.ParentId, 0); } // create the dto MemberDto memberDto = ContentBaseFactory.BuildDto(entity); // update the node dto NodeDto nodeDto = memberDto.ContentDto.NodeDto; Database.Update(nodeDto); // update the content dto Database.Update(memberDto.ContentDto); // update the content version dto Database.Update(memberDto.ContentVersionDto); // update the member dto // but only the changed columns, 'cos we cannot update password if empty var changedCols = new List <string>(); if (entity.IsPropertyDirty("SecurityStamp")) { changedCols.Add("securityStampToken"); } if (entity.IsPropertyDirty("Email")) { changedCols.Add("Email"); } if (entity.IsPropertyDirty("Username")) { changedCols.Add("LoginName"); } // this can occur from an upgrade if (memberDto.PasswordConfig.IsNullOrWhiteSpace()) { memberDto.PasswordConfig = DefaultPasswordConfigJson; changedCols.Add("passwordConfig"); } else if (memberDto.PasswordConfig == Constants.Security.UnknownPasswordConfigJson) { changedCols.Add("passwordConfig"); } // do NOT update the password if it has not changed or if it is null or empty if (entity.IsPropertyDirty("RawPasswordValue") && !string.IsNullOrWhiteSpace(entity.RawPasswordValue)) { changedCols.Add("Password"); // If the security stamp hasn't already updated we need to force it if (entity.IsPropertyDirty("SecurityStamp") == false) { memberDto.SecurityStampToken = entity.SecurityStamp = Guid.NewGuid().ToString(); changedCols.Add("securityStampToken"); } // check if we have a user config else use the default memberDto.PasswordConfig = entity.PasswordConfiguration ?? DefaultPasswordConfigJson; changedCols.Add("passwordConfig"); } // If userlogin or the email has changed then need to reset security stamp if (changedCols.Contains("Email") || changedCols.Contains("LoginName")) { memberDto.EmailConfirmedDate = null; changedCols.Add("emailConfirmedDate"); // If the security stamp hasn't already updated we need to force it if (entity.IsPropertyDirty("SecurityStamp") == false) { memberDto.SecurityStampToken = entity.SecurityStamp = Guid.NewGuid().ToString(); changedCols.Add("securityStampToken"); } } if (changedCols.Count > 0) { Database.Update(memberDto, changedCols); } ReplacePropertyValues(entity, entity.VersionId, 0, out _, out _); SetEntityTags(entity, _tagRepository, _jsonSerializer); PersistRelations(entity); OnUowRefreshedEntity(new MemberRefreshNotification(entity, new EventMessages())); entity.ResetDirtyProperties(); }
protected override void PersistNewItem(IMember entity) { entity.AddingEntity(); // ensure security stamp if missing if (entity.SecurityStamp.IsNullOrWhiteSpace()) { entity.SecurityStamp = Guid.NewGuid().ToString(); } // ensure that strings don't contain characters that are invalid in xml // TODO: do we really want to keep doing this here? entity.SanitizeEntityPropertiesForXmlStorage(); // create the dto MemberDto memberDto = ContentBaseFactory.BuildDto(entity); // check if we have a user config else use the default memberDto.PasswordConfig = entity.PasswordConfiguration ?? DefaultPasswordConfigJson; // derive path and level from parent NodeDto parent = GetParentNodeDto(entity.ParentId); var level = parent.Level + 1; // get sort order var sortOrder = GetNewChildSortOrder(entity.ParentId, 0); // persist the node dto NodeDto nodeDto = memberDto.ContentDto.NodeDto; nodeDto.Path = parent.Path; nodeDto.Level = Convert.ToInt16(level); nodeDto.SortOrder = sortOrder; // see if there's a reserved identifier for this unique id // and then either update or insert the node dto var id = GetReservedId(nodeDto.UniqueId); if (id > 0) { nodeDto.NodeId = id; nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId); nodeDto.ValidatePathWithException(); Database.Update(nodeDto); } else { Database.Insert(nodeDto); // update path, now that we have an id nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId); nodeDto.ValidatePathWithException(); Database.Update(nodeDto); } // update entity entity.Id = nodeDto.NodeId; entity.Path = nodeDto.Path; entity.SortOrder = sortOrder; entity.Level = level; // persist the content dto ContentDto contentDto = memberDto.ContentDto; contentDto.NodeId = nodeDto.NodeId; Database.Insert(contentDto); // persist the content version dto // assumes a new version id and version date (modified date) has been set ContentVersionDto contentVersionDto = memberDto.ContentVersionDto; contentVersionDto.NodeId = nodeDto.NodeId; contentVersionDto.Current = true; Database.Insert(contentVersionDto); entity.VersionId = contentVersionDto.Id; // persist the member dto memberDto.NodeId = nodeDto.NodeId; // if the password is empty, generate one with the special prefix // this will hash the guid with a salt so should be nicely random if (entity.RawPasswordValue.IsNullOrWhiteSpace()) { memberDto.Password = Constants.Security.EmptyPasswordPrefix + _passwordHasher.HashPassword(Guid.NewGuid().ToString("N")); entity.RawPasswordValue = memberDto.Password; } Database.Insert(memberDto); // persist the property data InsertPropertyValues(entity, 0, out _, out _); SetEntityTags(entity, _tagRepository, _jsonSerializer); PersistRelations(entity); OnUowRefreshedEntity(new MemberRefreshNotification(entity, new EventMessages())); entity.ResetDirtyProperties(); }
protected override void PersistUpdatedItem(IMember entity) { var member = (Member)entity; // update member.UpdatingEntity(); // ensure that strings don't contain characters that are invalid in xml // TODO: do we really want to keep doing this here? entity.SanitizeEntityPropertiesForXmlStorage(); // if parent has changed, get path, level and sort order if (entity.IsPropertyDirty("ParentId")) { var parent = GetParentNodeDto(entity.ParentId); entity.Path = string.Concat(parent.Path, ",", entity.Id); entity.Level = parent.Level + 1; entity.SortOrder = GetNewChildSortOrder(entity.ParentId, 0); } // create the dto var dto = ContentBaseFactory.BuildDto(entity); // update the node dto var nodeDto = dto.ContentDto.NodeDto; Database.Update(nodeDto); // update the content dto Database.Update(dto.ContentDto); // update the content version dto Database.Update(dto.ContentVersionDto); // update the member dto // but only the changed columns, 'cos we cannot update password if empty var changedCols = new List <string>(); if (entity.IsPropertyDirty("Email")) { changedCols.Add("Email"); } if (entity.IsPropertyDirty("Username")) { changedCols.Add("LoginName"); } // do NOT update the password if it has not changed or if it is null or empty if (entity.IsPropertyDirty("RawPasswordValue") && !string.IsNullOrWhiteSpace(entity.RawPasswordValue)) { changedCols.Add("Password"); } if (changedCols.Count > 0) { Database.Update(dto, changedCols); } // replace the property data var deletePropertyDataSql = SqlContext.Sql().Delete <PropertyDataDto>().Where <PropertyDataDto>(x => x.VersionId == member.VersionId); Database.Execute(deletePropertyDataSql); var propertyDataDtos = PropertyFactory.BuildDtos(member.ContentType.Variations, member.VersionId, 0, entity.Properties, LanguageRepository, out _, out _); foreach (var propertyDataDto in propertyDataDtos) { Database.Insert(propertyDataDto); } SetEntityTags(entity, _tagRepository); OnUowRefreshedEntity(new ScopedEntityEventArgs(AmbientScope, entity)); entity.ResetDirtyProperties(); }
protected override void PersistNewItem(IMember entity) { if (entity.ProviderUserKey == null) { entity.ProviderUserKey = entity.Key; } entity.AddingEntity(); var member = (Member)entity; // ensure that strings don't contain characters that are invalid in xml // TODO: do we really want to keep doing this here? entity.SanitizeEntityPropertiesForXmlStorage(); // create the dto var dto = ContentBaseFactory.BuildDto(entity); // derive path and level from parent var parent = GetParentNodeDto(entity.ParentId); var level = parent.Level + 1; // get sort order var sortOrder = GetNewChildSortOrder(entity.ParentId, 0); // persist the node dto var nodeDto = dto.ContentDto.NodeDto; nodeDto.Path = parent.Path; nodeDto.Level = Convert.ToInt16(level); nodeDto.SortOrder = sortOrder; // see if there's a reserved identifier for this unique id // and then either update or insert the node dto var id = GetReservedId(nodeDto.UniqueId); if (id > 0) { nodeDto.NodeId = id; nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId); nodeDto.ValidatePathWithException(); Database.Update(nodeDto); } else { Database.Insert(nodeDto); // update path, now that we have an id nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId); nodeDto.ValidatePathWithException(); Database.Update(nodeDto); } // update entity entity.Id = nodeDto.NodeId; entity.Path = nodeDto.Path; entity.SortOrder = sortOrder; entity.Level = level; // persist the content dto var contentDto = dto.ContentDto; contentDto.NodeId = nodeDto.NodeId; Database.Insert(contentDto); // persist the content version dto // assumes a new version id and version date (modified date) has been set var contentVersionDto = dto.ContentVersionDto; contentVersionDto.NodeId = nodeDto.NodeId; contentVersionDto.Current = true; Database.Insert(contentVersionDto); member.VersionId = contentVersionDto.Id; // persist the member dto dto.NodeId = nodeDto.NodeId; // if the password is empty, generate one with the special prefix // this will hash the guid with a salt so should be nicely random if (entity.RawPasswordValue.IsNullOrWhiteSpace()) { var aspHasher = new PasswordHasher(); dto.Password = Constants.Security.EmptyPasswordPrefix + aspHasher.HashPassword(Guid.NewGuid().ToString("N")); entity.RawPasswordValue = dto.Password; } Database.Insert(dto); // persist the property data var propertyDataDtos = PropertyFactory.BuildDtos(member.ContentType.Variations, member.VersionId, 0, entity.Properties, LanguageRepository, out _, out _); foreach (var propertyDataDto in propertyDataDtos) { Database.Insert(propertyDataDto); } SetEntityTags(entity, _tagRepository); OnUowRefreshedEntity(new ScopedEntityEventArgs(AmbientScope, entity)); entity.ResetDirtyProperties(); }
protected override void PersistUpdatedItem(IMedia entity) { // update entity.UpdatingEntity(); // Check if this entity is being moved as a descendant as part of a bulk moving operations. // In this case we can bypass a lot of the below operations which will make this whole operation go much faster. // When moving we don't need to create new versions, etc... because we cannot roll this operation back anyways. var isMoving = entity.IsMoving(); if (!isMoving) { // ensure unique name on the same level 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? entity.SanitizeEntityPropertiesForXmlStorage(); // if parent has changed, get path, level and sort order if (entity.IsPropertyDirty(nameof(entity.ParentId))) { var parent = GetParentNodeDto(entity.ParentId); entity.Path = string.Concat(parent.Path, ",", entity.Id); entity.Level = parent.Level + 1; entity.SortOrder = GetNewChildSortOrder(entity.ParentId, 0); } } // create the dto var dto = ContentBaseFactory.BuildDto(_mediaUrlGenerators, entity); // update the node dto var nodeDto = dto.ContentDto.NodeDto; nodeDto.ValidatePathWithException(); Database.Update(nodeDto); if (!isMoving) { // update the content dto Database.Update(dto.ContentDto); // update the content & media version dtos var contentVersionDto = dto.MediaVersionDto.ContentVersionDto; var mediaVersionDto = dto.MediaVersionDto; contentVersionDto.Current = true; Database.Update(contentVersionDto); Database.Update(mediaVersionDto); // replace the property data ReplacePropertyValues(entity, entity.VersionId, 0, out _, out _); SetEntityTags(entity, _tagRepository, _serializer); PersistRelations(entity); } OnUowRefreshedEntity(new MediaRefreshNotification(entity, new EventMessages())); entity.ResetDirtyProperties(); }
protected override void PersistNewItem(IMedia entity) { entity.AddingEntity(); // ensure unique name on the same level 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? entity.SanitizeEntityPropertiesForXmlStorage(); // create the dto var dto = ContentBaseFactory.BuildDto(_mediaUrlGenerators, entity); // derive path and level from parent var parent = GetParentNodeDto(entity.ParentId); var level = parent.Level + 1; // get sort order var sortOrder = GetNewChildSortOrder(entity.ParentId, 0); // persist the node dto var nodeDto = dto.ContentDto.NodeDto; nodeDto.Path = parent.Path; nodeDto.Level = Convert.ToInt16(level); nodeDto.SortOrder = sortOrder; // see if there's a reserved identifier for this unique id // and then either update or insert the node dto var id = GetReservedId(nodeDto.UniqueId); if (id > 0) { nodeDto.NodeId = id; } else { Database.Insert(nodeDto); } nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId); nodeDto.ValidatePathWithException(); Database.Update(nodeDto); // update entity entity.Id = nodeDto.NodeId; entity.Path = nodeDto.Path; entity.SortOrder = sortOrder; entity.Level = level; // persist the content dto var contentDto = dto.ContentDto; contentDto.NodeId = nodeDto.NodeId; Database.Insert(contentDto); // persist the content version dto // assumes a new version id and version date (modified date) has been set var contentVersionDto = dto.MediaVersionDto.ContentVersionDto; contentVersionDto.NodeId = nodeDto.NodeId; contentVersionDto.Current = true; Database.Insert(contentVersionDto); entity.VersionId = contentVersionDto.Id; // persist the media version dto var mediaVersionDto = dto.MediaVersionDto; mediaVersionDto.Id = entity.VersionId; Database.Insert(mediaVersionDto); // persist the property data InsertPropertyValues(entity, 0, out _, out _); // set tags SetEntityTags(entity, _tagRepository, _serializer); PersistRelations(entity); OnUowRefreshedEntity(new MediaRefreshNotification(entity, new EventMessages())); entity.ResetDirtyProperties(); }
protected override void PersistUpdatedItem(IMedia entity) { var media = (Models.Media)entity; // update media.UpdatingEntity(); // ensure unique name on the same level 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? entity.SanitizeEntityPropertiesForXmlStorage(); // if parent has changed, get path, level and sort order if (entity.IsPropertyDirty("ParentId")) { var parent = GetParentNodeDto(entity.ParentId); entity.Path = string.Concat(parent.Path, ",", entity.Id); entity.Level = parent.Level + 1; entity.SortOrder = GetNewChildSortOrder(entity.ParentId, 0); } // create the dto var dto = ContentBaseFactory.BuildDto(entity); // update the node dto var nodeDto = dto.ContentDto.NodeDto; nodeDto.ValidatePathWithException(); Database.Update(nodeDto); // update the content dto Database.Update(dto.ContentDto); // update the content & media version dtos var contentVersionDto = dto.MediaVersionDto.ContentVersionDto; var mediaVersionDto = dto.MediaVersionDto; contentVersionDto.Current = true; Database.Update(contentVersionDto); Database.Update(mediaVersionDto); // replace the property data var deletePropertyDataSql = SqlContext.Sql().Delete <PropertyDataDto>().Where <PropertyDataDto>(x => x.VersionId == media.VersionId); Database.Execute(deletePropertyDataSql); var propertyDataDtos = PropertyFactory.BuildDtos(media.ContentType.Variations, media.VersionId, 0, entity.Properties, LanguageRepository, out _, out _); foreach (var propertyDataDto in propertyDataDtos) { Database.Insert(propertyDataDto); } SetEntityTags(entity, _tagRepository); OnUowRefreshedEntity(new ScopedEntityEventArgs(AmbientScope, entity)); entity.ResetDirtyProperties(); }
protected override void PersistNewItem(IMedia entity) { var media = (Models.Media)entity; media.AddingEntity(); // ensure unique name on the same level entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name); // ensure that strings don't contain characters that are invalid in xml // fixme - do we really want to keep doing this here? entity.SanitizeEntityPropertiesForXmlStorage(); // create the dto var dto = ContentBaseFactory.BuildDto(entity); // derive path and level from parent var parent = GetParentNodeDto(entity.ParentId); var level = parent.Level + 1; // get sort order var sortOrder = GetNewChildSortOrder(entity.ParentId, 0); // persist the node dto var nodeDto = dto.ContentDto.NodeDto; nodeDto.Path = parent.Path; nodeDto.Level = Convert.ToInt16(level); nodeDto.SortOrder = sortOrder; // see if there's a reserved identifier for this unique id // and then either update or insert the node dto var id = GetReservedId(nodeDto.UniqueId); if (id > 0) { nodeDto.NodeId = id; } else { Database.Insert(nodeDto); } nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId); nodeDto.ValidatePathWithException(); Database.Update(nodeDto); // update entity entity.Id = nodeDto.NodeId; entity.Path = nodeDto.Path; entity.SortOrder = sortOrder; entity.Level = level; // persist the content dto var contentDto = dto.ContentDto; contentDto.NodeId = nodeDto.NodeId; Database.Insert(contentDto); // persist the content version dto // assumes a new version id and version date (modified date) has been set var contentVersionDto = dto.MediaVersionDto.ContentVersionDto; contentVersionDto.NodeId = nodeDto.NodeId; contentVersionDto.Current = true; Database.Insert(contentVersionDto); media.VersionId = contentVersionDto.Id; // persist the media version dto var mediaVersionDto = dto.MediaVersionDto; mediaVersionDto.Id = media.VersionId; Database.Insert(mediaVersionDto); // persist the property data var propertyDataDtos = PropertyFactory.BuildDtos(media.ContentType.Variations, media.VersionId, 0, entity.Properties, LanguageRepository, out _, out _); foreach (var propertyDataDto in propertyDataDtos) { Database.Insert(propertyDataDto); } // set tags SetEntityTags(entity, _tagRepository); OnUowRefreshedEntity(new ScopedEntityEventArgs(AmbientScope, entity)); entity.ResetDirtyProperties(); }
protected override void PersistUpdatedItem(IMember entity) { var member = (Member)entity; // update member.UpdatingEntity(); // ensure that strings don't contain characters that are invalid in xml // TODO: do we really want to keep doing this here? entity.SanitizeEntityPropertiesForXmlStorage(); // if parent has changed, get path, level and sort order if (entity.IsPropertyDirty("ParentId")) { var parent = GetParentNodeDto(entity.ParentId); entity.Path = string.Concat(parent.Path, ",", entity.Id); entity.Level = parent.Level + 1; entity.SortOrder = GetNewChildSortOrder(entity.ParentId, 0); } // create the dto var dto = ContentBaseFactory.BuildDto(entity); // update the node dto var nodeDto = dto.ContentDto.NodeDto; Database.Update(nodeDto); // update the content dto Database.Update(dto.ContentDto); // update the content version dto Database.Update(dto.ContentVersionDto); // update the member dto // but only the changed columns, 'cos we cannot update password if empty var changedCols = new List <string>(); if (entity.IsPropertyDirty("Email")) { changedCols.Add("Email"); } if (entity.IsPropertyDirty("Username")) { changedCols.Add("LoginName"); } // do NOT update the password if it has not changed or if it is null or empty if (entity.IsPropertyDirty("RawPasswordValue") && !string.IsNullOrWhiteSpace(entity.RawPasswordValue)) { changedCols.Add("Password"); } if (changedCols.Count > 0) { Database.Update(dto, changedCols); } // Replace the property data // Lookup the data to update with a UPDLOCK (using ForUpdate()) this is because we have another method that doesn't take an explicit WriteLock // in SetLastLogin which is called very often and we want to avoid the lock timeout for the explicit lock table but we still need to ensure atomic // operations between that method and this one. var propDataSql = SqlContext.Sql().Select("*").From <PropertyDataDto>().Where <PropertyDataDto>(x => x.VersionId == member.VersionId).ForUpdate(); var existingPropData = Database.Fetch <PropertyDataDto>(propDataSql).ToDictionary(x => x.PropertyTypeId); var propertyDataDtos = PropertyFactory.BuildDtos(member.ContentType.Variations, member.VersionId, 0, entity.Properties, LanguageRepository, out _, out _); foreach (var propertyDataDto in propertyDataDtos) { // Check if this already exists and update, else insert a new one if (existingPropData.TryGetValue(propertyDataDto.PropertyTypeId, out var propData)) { propertyDataDto.Id = propData.Id; Database.Update(propertyDataDto); } else { Database.Insert(propertyDataDto); } } SetEntityTags(entity, _tagRepository); PersistRelations(entity); OnUowRefreshedEntity(new ScopedEntityEventArgs(AmbientScope, entity)); entity.ResetDirtyProperties(); }