//private void ExtendSaveContentTypes(IEnumerable<ContentType> contentTypes) // => Storage.DoWhileQueueingRelationships(() => contentTypes.ToList().ForEach(ExtendSaveContentTypes)); ///// <summary> ///// Import an AttributeSet with all Attributes and AttributeMetaData ///// </summary> //private void ExtendSaveContentTypes(ContentType contentType) //{ // // initialize destinationSet - create or test existing if ok // var foundSet = _dbDeepAccess.ContentType.GetOrCreateContentType(contentType); // if (foundSet == null) // something went wrong, skip this import // return; // var contentTypeId = foundSet.Value; // // append all Attributes // foreach (var newAtt in contentType.Attributes.Cast<AttributeDefinition>()) // { // var destAttribId = _dbDeepAccess.AttributesDefinition.GetOrCreateAttributeDefinition(contentTypeId, newAtt); // // save additional entities containing AttributeMetaData for this attribute // if (newAtt.InternalAttributeMetaData != null) // SaveAttributeMetadata(destAttribId, newAtt.InternalAttributeMetaData); // } // // optionally re-order the attributes if specified in import // if (contentType.OnSaveSortAttributes) // _dbDeepAccess.ContentType.SortAttributes(contentTypeId, contentType); //} ///// <summary> ///// Save additional entities describing the attribute ///// </summary> ///// <param name="attributeId"></param> ///// <param name="metadata"></param> //private void SaveAttributeMetadata(int attributeId, List<Entity> metadata) //{ // var entities = new List<IEntity>(); // foreach (var entity in metadata) // { // var md = (Metadata) entity.Metadata; // // Validate Entity // md.TargetType = Constants.MetadataForAttribute; // // Set KeyNumber // if (attributeId == 0 || attributeId < 0) // < 0 is ef-core temp id // throw new Exception($"trying to add metadata to attribute {attributeId} but attribute isn't saved yet");//_dbDeepAccess.SqlDb.SaveChanges(); // md.KeyNumber = attributeId; // //// Get guid of previously existing assignment - if it exists // //var existingMetadata = _dbDeepAccess.Entities // // .GetAssignedEntities(Constants.MetadataForAttribute, keyNumber: attributeId) // // .FirstOrDefault(e => e.AttributeSetId == attributeId); // //if (existingMetadata != null) // // entity.SetGuid(existingMetadata.EntityGuid); // //entities.Add(CreateMergedForSaving(entity, _entireApp, SaveOptions)); // entities.Add(entity); // } // Storage.Save(entities, SaveOptions.Build(ZoneId)); // don't use the standard save options, as this is attributes only //} private void MergeContentTypeUpdateWithExisting(IContentType contentType) { var existing = _entireApp.ContentTypes.Values.FirstOrDefault(ct => ct.StaticName == contentType.StaticName); if (existing == null) { return; } foreach (var newAttrib in contentType.Attributes) { var existAttrib = existing.Attributes.FirstOrDefault(a => a.Name == newAttrib.Name); if (existAttrib == null) { continue; } var impMeta = ((AttributeDefinition)newAttrib).Items; var newMetaList = new List <IEntity>(); foreach (var newMd in impMeta) { var existingMetadata = _entireApp.GetMetadata(Constants.MetadataForAttribute, existAttrib.AttributeId, newMd.Type.StaticName).FirstOrDefault(); if (existingMetadata == null) { newMetaList.Add(newMd); } else { newMetaList.Add(EntitySaver.CreateMergedForSaving(existingMetadata, newMd, SaveOptions) as Entity); } } ((AttributeDefinition)newAttrib).AddItems(newMetaList); } }
/// <summary> /// Update an entity /// </summary> /// <param name="id"></param> /// <param name="values"></param> public void UpdateParts(int id, Dictionary <string, object> values) { var saveOptions = SaveOptions.Build(_appManager.ZoneId); saveOptions.PreserveUntouchedAttributes = true; saveOptions.PreserveUnknownLanguages = true; var orig = _appManager.Cache.List[id]; var tempEnt = new Entity(_appManager.AppId, 0, "", values); var saveEnt = EntitySaver.CreateMergedForSaving(orig, tempEnt, saveOptions); Save(saveEnt, saveOptions); }
public void TestContravariance() { ISave <User> saver = new GenericSaver <Entity>(); ISave <User> userSaver = new EntitySaver(); var user = new User(); saver.Save(user); #region contravariance delegates Action <Entity> entityAction = entity => entity.Name = "123"; Action <User> userAction = entityAction; #endregion }
/// <summary> /// Import an Entity with all values /// </summary> private Entity CreateMergedForSaving(Entity update, AppDataPackage appDataPackage, SaveOptions saveOptions) { #region try to get AttributeSet or otherwise cancel & log error var dbAttrSet = appDataPackage.ContentTypes.Values .FirstOrDefault(ct => String.Equals(ct.StaticName, update.Type.StaticName, StringComparison.InvariantCultureIgnoreCase)); if (dbAttrSet == null) // AttributeSet not Found { Storage.Log.Add(new LogItem(EventLogEntryType.Error, "ContentType not found for " + update.Type.StaticName)); return(null); } #endregion // Find existing Enties - meaning both draft and non-draft List <IEntity> existingEntities = null; if (update.EntityGuid != Guid.Empty) { existingEntities = appDataPackage.List.Where(e => e.EntityGuid == update.EntityGuid).ToList(); } #region Simplest case - nothing existing to update: return entity if (existingEntities == null || !existingEntities.Any()) { return(update); } #endregion Storage.Log.Add(new LogItem(EventLogEntryType.Information, $"FYI: Entity {update.EntityId} already exists for guid {update.EntityGuid}")); // now update (main) entity id from existing - since it already exists var original = existingEntities.First(); update.ChangeIdForSaving(original.EntityId); return(EntitySaver.CreateMergedForSaving(original, update, saveOptions) as Entity); }
private void SaveChangedLists(Dictionary <string, List <int?> > values) { // ensure that there are never more presentations than values if (values.ContainsKey(AppConstants.Presentation)) { var contentCount = Content.Count; if (values.ContainsKey(AppConstants.Content)) { contentCount = values[AppConstants.Content].Count; } if (values[AppConstants.Presentation].Count > contentCount) { throw new Exception("Presentation may not contain more items than Content."); } } // 2017-04-01 2dm centralizing eav access var dicObj = values.ToDictionary(x => x.Key, x => x.Value as object); var newEnt = new Entity(_appId, 0, _contentGroupEntity.Type, dicObj); var saveOpts = SaveOptions.Build(_zoneId); saveOpts.PreserveUntouchedAttributes = true; var saveEnt = new EntitySaver(Log).CreateMergedForSaving(_contentGroupEntity, newEnt, saveOpts); if (_versioningEnabled) { // Force saving as draft if needed (if versioning is enabled) ((Entity)saveEnt).PlaceDraftInBranch = true; ((Entity)saveEnt).IsPublished = false; } new AppManager(_zoneId, _appId).Entities.Save(saveEnt, saveOpts); // Refresh content group entity (ensures contentgroup is up to date) _contentGroupEntity = new ContentGroupManager(_zoneId, _appId, _showDrafts, _versioningEnabled, Log).GetContentGroup(_contentGroupEntity.EntityGuid)._contentGroupEntity; }
/// <inheritdoc /> protected override void HandleEvent(SessionStatusChangeEventArgs args) { //The reason this system is so simple is basically the other threads just need a way to queue up //cleanup on the main thread. The reasoning being that GameObject destruction needs to occur //as well as collection modification needs to happen, and the main thread is where the majority if collection //iteration should be taking place. //it's possible that we're attempting to clean up an entity for a connection //that doesn't have one. This can happen if they disconnect during claim or before claim. if (!ConnectionToEntityMap.ContainsKey(args.Details.ConnectionId)) { if (Logger.IsInfoEnabled) { Logger.Info($"ConnectionId: {args.Details.ConnectionId} had entity exit cleanup but contained no entity. This is not an error."); } //We may be in this method, handling cleanup for an entity that has a claim going on //in the claim handler, but is still awaiting a response for character data from the gameserver. MEANING we could end up with hanging entites. //This is not mitgated here, but inside the player entery factory //which SHOULD make a check for the connection still being valid AFTER creation //Not before because we still want to create, and then deconstruct. Reasoning being that gameserver session //will still be claimed unless we go through th cleanup process. return; } NetworkEntityGuid entityGuid = ConnectionToEntityMap[args.Details.ConnectionId]; //First we need to save the entity data since it DOES own an entity. UnityExtended.UnityMainThreadContext.PostAsync(async() => { //Nothing should really be taking a write lock, except session entry I guess. //This could be bad //We no longer do a read lock because Player Entry is actually trying to //aquire a write lock and this could block if for a LONG time. KILLING the server basically //So, we just assume it's safe to save entity data. Even if it's changing mid save like this. //using(await LockingPolicy.ReaderLockAsync(null, CancellationToken.None)) { //We know that an entity exists, so we must save it. Before we even queue it up for removal. await EntitySaver.SaveAsync(entityGuid) .ConfigureAwait(true); } //At this point we MUST write lock, since we are actually modifying entity collections and entries using (await LockingPolicy.WriterLockAsync(null, CancellationToken.None)) //we can use async await since we're in a async context too!! Which is good. { SessionDestructor.Destroy(new PlayerSessionDeconstructionContext(args.Details.ConnectionId)); } //TODO: We have a big problem if this fails, we need to handle it properly. Otherwise the player cannot log in again.\ ProjectVersionStage.AssertBeta(); //We need to async send the release request, a very important part of session cleanup. //if this failes we have BIG problems. BIG BIG BIG. await ZoneClientGameService.ReleaseActiveSession(entityGuid.EntityId) .ConfigureAwait(false); if (Logger.IsInfoEnabled) { Logger.Info($"Cleaned up Entity Player Session for ConnectionId: {args.Details.ConnectionId} Guid: {entityGuid} {entityGuid.EntityType}:{entityGuid.EntityId}"); } }); }