Exemplo n.º 1
0
        /// <summary>
        /// Import an item from a <see cref="TModel"/>.
        /// </summary>
        /// <param name="item">The model to be imported.</param>
        /// <param name="silent">Whether the user should be notified fo the import.</param>
        /// <param name="archive">An optional archive to use for model population.</param>
        public TModel Import(TModel item, bool silent = false, ArchiveReader archive = null)
        {
            delayEvents();

            try
            {
                Logger.Log($"Importing {item}...", LoggingTarget.Database);

                using (var write = ContextFactory.GetForWrite()) // used to share a context for full import. keep in mind this will block all writes.
                {
                    try
                    {
                        if (!write.IsTransactionLeader)
                        {
                            throw new InvalidOperationException($"Ensure there is no parent transaction so errors can correctly be handled by {this}");
                        }

                        var existing = CheckForExisting(item);

                        if (existing != null)
                        {
                            Undelete(existing);
                            Logger.Log($"Found existing {typeof(TModel)} for {item} (ID {existing.ID}). Skipping import.", LoggingTarget.Database);
                            handleEvent(() => ItemAdded?.Invoke(existing, true, silent));
                            return(existing);
                        }

                        if (archive != null)
                        {
                            item.Files = createFileInfos(archive, Files);
                        }

                        Populate(item, archive);

                        // import to store
                        ModelStore.Add(item, silent);
                    }
                    catch (Exception e)
                    {
                        write.Errors.Add(e);
                        throw;
                    }
                }

                Logger.Log($"Import of {item} successfully completed!", LoggingTarget.Database);
            }
            catch (Exception e)
            {
                Logger.Error(e, $"Import of {item} failed and has been rolled back.", LoggingTarget.Database);
                item = null;
            }
            finally
            {
                // we only want to flush events after we've confirmed the write context didn't have any errors.
                flushEvents(item != null);
            }

            return(item);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Import a beatmap from an <see cref="ArchiveReader"/>.
        /// </summary>
        /// <param name="archive">The beatmap to be imported.</param>
        public BeatmapSetInfo Import(ArchiveReader archive)
        {
            using (contextFactory.GetForWrite()) // used to share a context for full import. keep in mind this will block all writes.
            {
                // create a new set info (don't yet add to database)
                var beatmapSet = createBeatmapSetInfo(archive);

                // check if this beatmap has already been imported and exit early if so
                var existingHashMatch = beatmaps.BeatmapSets.FirstOrDefault(b => b.Hash == beatmapSet.Hash);
                if (existingHashMatch != null)
                {
                    Undelete(existingHashMatch);
                    return(existingHashMatch);
                }

                // check if a set already exists with the same online id
                if (beatmapSet.OnlineBeatmapSetID != null)
                {
                    var existingOnlineId = beatmaps.BeatmapSets.FirstOrDefault(b => b.OnlineBeatmapSetID == beatmapSet.OnlineBeatmapSetID);
                    if (existingOnlineId != null)
                    {
                        Delete(existingOnlineId);
                        beatmaps.Cleanup(s => s.ID == existingOnlineId.ID);
                    }
                }

                beatmapSet.Files    = createFileInfos(archive, files);
                beatmapSet.Beatmaps = createBeatmapDifficulties(archive);

                // remove metadata from difficulties where it matches the set
                foreach (BeatmapInfo b in beatmapSet.Beatmaps)
                {
                    if (beatmapSet.Metadata.Equals(b.Metadata))
                    {
                        b.Metadata = null;
                    }
                }

                // import to beatmap store
                Import(beatmapSet);
                return(beatmapSet);
            }
        }
        /// <summary>
        /// Import an item from an <see cref="ArchiveReader"/>.
        /// </summary>
        /// <param name="archive">The archive to be imported.</param>
        public TModel Import(ArchiveReader archive)
        {
            using (ContextFactory.GetForWrite()) // used to share a context for full import. keep in mind this will block all writes.
            {
                // create a new model (don't yet add to database)
                var item = CreateModel(archive);

                var existing = CheckForExisting(item);

                if (existing != null)
                {
                    return(existing);
                }

                item.Files = createFileInfos(archive, Files);

                Populate(item, archive);

                // import to store
                ModelStore.Add(item);

                return(item);
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Refresh an instance potentially from a different thread with a local context-tracked instance.
        /// </summary>
        /// <param name="obj">The object to use as a reference when negotiating a local instance.</param>
        /// <param name="lookupSource">An optional lookup source which will be used to query and populate a freshly retrieved replacement. If not provided, the refreshed object will still be returned but will not have any includes.</param>
        /// <typeparam name="T">A valid EF-stored type.</typeparam>
        protected virtual void Refresh <T>(ref T obj, IQueryable <T> lookupSource = null) where T : class, IHasPrimaryKey
        {
            using (var usage = ContextFactory.GetForWrite())
            {
                var context = usage.Context;

                if (context.Entry(obj).State != EntityState.Detached)
                {
                    return;
                }

                int id          = obj.ID;
                var foundObject = lookupSource?.SingleOrDefault(t => t.ID == id) ?? context.Find <T>(id);
                if (foundObject != null)
                {
                    obj = foundObject;
                }
                else
                {
                    context.Add(obj);
                }
            }
        }