Exemple #1
0
        /// <summary>
        /// Runs the algorithm on the network with the provided details, using the given parameters.
        /// </summary>
        /// <param name="networkId">The ID of the network on which to run the algorithm.</param>
        /// <param name="serviceProvider">The application service provider.</param>
        /// <param name="token">The cancellation token for the task.</param>
        /// <returns></returns>
        public static async Task Run(string networkId, IServiceProvider serviceProvider, CancellationToken token)
        {
            // Define the required data.
            var data                  = new List <NetworkEdgeInputModel>();
            var databaseTypeName      = string.Empty;
            var nodeDatabaseIds       = new List <string>();
            var edgeDatabaseIds       = new List <string>();
            var databaseNodeFieldIds  = new List <string>();
            var databaseEdgeFieldIds  = new List <string>();
            var seedNodeCollectionIds = new List <string>();

            // Use a new scope.
            using (var scope = serviceProvider.CreateScope())
            {
                // Use a new context instance.
                using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                // Reload the network.
                var network = context.Networks
                              .FirstOrDefault(item => item.Id == networkId);
                // Check if there was no item found.
                if (network == null)
                {
                    // Return.
                    return;
                }
                // Get the related data.
                var databaseTypes = context.NetworkDatabases
                                    .Where(item => item.Network == network)
                                    .Select(item => item.Database.DatabaseType);
                // Check if there was any error in retrieving related data from the database.
                if (databaseTypes == null)
                {
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog("There was an error in retrieving related data from the database.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Check if there weren't any database types found.
                if (!databaseTypes.Any())
                {
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog("No database types corresponding to the network databases could be found.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Check if the database types are different.
                if (databaseTypes.Distinct().Count() > 1)
                {
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog("The database types corresponding to the network databases are different.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Get the database type name.
                databaseTypeName = databaseTypes.Select(item => item.Name).First();
                // Try to deserialize the data.
                if (!network.Data.TryDeserializeJsonObject <List <NetworkEdgeInputModel> >(out data) || data == null)
                {
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog("The seed data corresponding to the network could not be deserialized.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Get the related entities.
                nodeDatabaseIds = context.NetworkDatabases
                                  .Where(item => item.Network == network)
                                  .Where(item => item.Type == NetworkDatabaseType.Node)
                                  .Select(item => item.Database)
                                  .Distinct()
                                  .Select(item => item.Id)
                                  .ToList();
                edgeDatabaseIds = context.NetworkDatabases
                                  .Where(item => item.Network == network)
                                  .Where(item => item.Type == NetworkDatabaseType.Edge)
                                  .Select(item => item.Database)
                                  .Distinct()
                                  .Select(item => item.Id)
                                  .ToList();
                databaseNodeFieldIds = context.NetworkDatabases
                                       .Where(item => item.Network == network)
                                       .Where(item1 => item1.Type == NetworkDatabaseType.Node)
                                       .Select(item1 => item1.Database)
                                       .Select(item1 => item1.DatabaseNodeFields)
                                       .SelectMany(item1 => item1)
                                       .Distinct()
                                       .Select(item => item.Id)
                                       .ToList();
                databaseEdgeFieldIds = context.NetworkDatabases
                                       .Where(item => item.Network == network)
                                       .Where(item => item.Type == NetworkDatabaseType.Edge)
                                       .Select(item => item.Database)
                                       .Select(item => item.DatabaseEdgeFields)
                                       .SelectMany(item => item)
                                       .Distinct()
                                       .Select(item => item.Id)
                                       .ToList();
                seedNodeCollectionIds = context.NetworkNodeCollections
                                        .Where(item => item.Network == network)
                                        .Where(item => item.Type == NetworkNodeCollectionType.Seed)
                                        .Select(item => item.NodeCollection)
                                        .Distinct()
                                        .Select(item => item.Id)
                                        .ToList();
            }
            // Get the related data.
            var nodeTitle = databaseTypeName == "PPI" ? "Protein" : "Node";
            var edgeTitle = databaseTypeName == "PPI" ? "Interaction" : "Edge";
            // Get the seed edges from the data.
            var seedEdges = data
                            .Where(item => item.Edge != null)
                            .Select(item => item.Edge)
                            .Where(item => item.EdgeNodes != null)
                            .Select(item => (item.EdgeNodes.FirstOrDefault(item1 => item1.Type == "Source"), item.EdgeNodes.FirstOrDefault(item1 => item1.Type == "Target")))
                            .Where(item => item.Item1 != null && item.Item2 != null)
                            .Select(item => (item.Item1.Node, item.Item2.Node))
                            .Where(item => item.Item1 != null && item.Item2 != null)
                            .Select(item => (item.Item1.Id, item.Item2.Id))
                            .Where(item => !string.IsNullOrEmpty(item.Item1) && !string.IsNullOrEmpty(item.Item2))
                            .Distinct();

            // Check if there haven't been any edges found.
            if (seedEdges == null || !seedEdges.Any())
            {
                // Use a new scope.
                using (var scope = serviceProvider.CreateScope())
                {
                    // Use a new context instance.
                    using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                    // Reload the network.
                    var network = context.Networks
                                  .FirstOrDefault(item => item.Id == networkId);
                    // Check if there was no item found.
                    if (network == null)
                    {
                        // Return.
                        return;
                    }
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog($"The seed data corresponding to the network does not contain any valid {edgeTitle.ToLower()}s.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);
                }
                // End the function.
                return;
            }
            // Get the seed nodes from the seed edges.
            var seedNodes = seedEdges
                            .Select(item => item.Item1)
                            .Concat(seedEdges.Select(item => item.Item2))
                            .Distinct();
            // Define the related entities.
            var networkNodes = new List <NetworkNode>();
            var networkEdges = new List <NetworkEdge>();

            // Check the database type.
            if (databaseTypeName == "Generic")
            {
                // Define the related entities.
                networkNodes = seedNodes
                               .Select(item => new NetworkNode
                {
                    Node = new Node
                    {
                        DateTimeCreated = DateTime.UtcNow,
                        Name            = item,
                        Description     = $"This is an automatically generated {nodeTitle.ToLower()} for the network \"{networkId}\".",
                        DatabaseNodes   = nodeDatabaseIds
                                          .Select(item1 => new DatabaseNode
                        {
                            DatabaseId = item1,
                        })
                                          .ToList(),
                        DatabaseNodeFieldNodes = databaseNodeFieldIds
                                                 .Select(item1 => new DatabaseNodeFieldNode
                        {
                            DatabaseNodeFieldId = item1,
                            Value = item
                        })
                                                 .ToList()
                    },
                    Type = NetworkNodeType.None
                })
                               .ToList();
                networkEdges = seedEdges
                               .Select(item => new NetworkEdge
                {
                    Edge = new Edge
                    {
                        DateTimeCreated = DateTime.UtcNow,
                        Name            = $"{item.Item1} - {item.Item2}",
                        Description     = $"This is an automatically generated {edgeTitle.ToLower()} for the network \"{networkId}\".",
                        DatabaseEdges   = edgeDatabaseIds
                                          .Select(item1 => new DatabaseEdge
                        {
                            DatabaseId = item1,
                        })
                                          .ToList(),
                        DatabaseEdgeFieldEdges = databaseEdgeFieldIds
                                                 .Select(item1 => new DatabaseEdgeFieldEdge
                        {
                            DatabaseEdgeFieldId = item1,
                            Value = $"{item.Item1} - {item.Item2}"
                        })
                                                 .ToList(),
                        EdgeNodes = new List <EdgeNode>
                        {
                            new EdgeNode
                            {
                                Node = networkNodes
                                       .FirstOrDefault(item1 => item1.Node.Name == item.Item1)?.Node,
                                Type = EdgeNodeType.Source
                            },
                            new EdgeNode
                            {
                                Node = networkNodes
                                       .FirstOrDefault(item1 => item1.Node.Name == item.Item2)?.Node,
                                Type = EdgeNodeType.Target
                            }
                        }
                        .Where(item1 => item1.Node != null)
                        .ToList()
                    }
                })
                               .ToList();
            }
            else
            {
                // Define the required data.
                var seedNodeIds      = new List <string>();
                var seedEdgesWithIds = new List <(string, string)>();
                // Use a new scope.
                using (var scope = serviceProvider.CreateScope())
                {
                    // Use a new context instance.
                    using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                    // Reload the network.
                    var network = context.Networks
                                  .FirstOrDefault(item => item.Id == networkId);
                    // Check if there was no item found.
                    if (network == null)
                    {
                        // Return.
                        return;
                    }
                    // Get the available nodes.
                    var availableNodes = context.Nodes
                                         .Where(item => item.DatabaseNodes.Any(item1 => nodeDatabaseIds.Contains(item1.Database.Id)));
                    // Check if there haven't been any available nodes found.
                    if (availableNodes == null || !availableNodes.Any())
                    {
                        // Update the status of the item.
                        network.Status = NetworkStatus.Error;
                        // Add a message to the log.
                        network.Log = network.AppendToLog($"No available {nodeTitle.ToLower()}s could be found in the selected databases.");
                        // Edit the network.
                        await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                        // End the function.
                        return;
                    }
                    // Get the available edges.
                    var availableEdges = context.Edges
                                         .Where(item => item.DatabaseEdges.Any(item1 => edgeDatabaseIds.Contains(item1.Database.Id)))
                                         .Where(item => item.EdgeNodes.All(item1 => availableNodes.Contains(item1.Node)));
                    // Check if there haven't been any available edges found.
                    if (availableEdges == null || !availableEdges.Any())
                    {
                        // Update the status of the item.
                        network.Status = NetworkStatus.Error;
                        // Add a message to the log.
                        network.Log = network.AppendToLog($"No available {edgeTitle.ToLower()}s could be found in the selected databases.");
                        // Edit the network.
                        await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                        // End the function.
                        return;
                    }
                    // Get the seed nodes.
                    var seedNodesByIdentifier = availableNodes
                                                .Where(item => seedNodes.Contains(item.Id) || item.DatabaseNodeFieldNodes.Any(item1 => item1.DatabaseNodeField.IsSearchable && seedNodes.Contains(item1.Value)));
                    var seedNodesByNodeCollection = availableNodes
                                                    .Where(item => item.NodeCollectionNodes.Any(item1 => seedNodeCollectionIds.Contains(item1.NodeCollection.Id)));
                    var seedNodeItems = seedNodesByIdentifier
                                        .Concat(seedNodesByNodeCollection)
                                        .Distinct()
                                        .Select(item => new
                    {
                        Id     = item.Id,
                        Values = item.DatabaseNodeFieldNodes
                                 .Where(item1 => databaseNodeFieldIds.Contains(item1.DatabaseNodeField.Id))
                                 .Where(item1 => item1.DatabaseNodeField.IsSearchable)
                                 .Select(item1 => item1.Value)
                                 .ToList()
                    })
                                        .ToList();
                    // Check if there haven't been any seed nodes found.
                    if (seedNodeItems == null || !seedNodeItems.Any())
                    {
                        // Update the status of the item.
                        network.Status = NetworkStatus.Error;
                        // Add a message to the log.
                        network.Log = network.AppendToLog($"No seed {nodeTitle.ToLower()}s could be found with the provided seed data.");
                        // Edit the network.
                        await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                        // End the function.
                        return;
                    }
                    // Get the seed node IDs.
                    seedNodeIds = seedNodeItems
                                  .Select(item => item.Id)
                                  .ToList();
                    // Define the list to store the updated edges.
                    seedEdgesWithIds = seedEdges
                                       .Select(item => (
                                                   seedNodeItems
                                                   .Where(item1 => item1.Values.Contains(item.Item1))
                                                   .Select(item1 => item1.Id)
                                                   .FirstOrDefault(),
                                                   seedNodeItems
                                                   .Where(item1 => item1.Values.Contains(item.Item2))
                                                   .Select(item1 => item1.Id)
                                                   .FirstOrDefault()))
                                       .Where(item => !string.IsNullOrEmpty(item.Item1) && !string.IsNullOrEmpty(item.Item2))
                                       .ToList();
                    // Check if there haven't been any seed nodes found.
                    if (seedEdgesWithIds == null || !seedEdgesWithIds.Any())
                    {
                        // Update the status of the item.
                        network.Status = NetworkStatus.Error;
                        // Add a message to the log.
                        network.Log = network.AppendToLog($"No seed {edgeTitle.ToLower()}s with valid {nodeTitle.ToLower()}s could be found with the provided seed data.");
                        // Edit the network.
                        await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                        // End the function.
                        return;
                    }
                }
                // Define the list to store the edges.
                var currentEdgeList = new List <EdgeItemModel>();
                // Use a new scope.
                using (var scope = serviceProvider.CreateScope())
                {
                    // Use a new context instance.
                    using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                    // Define the edges of the network.
                    currentEdgeList = context.Edges
                                      .Where(item => item.DatabaseEdges.Any(item1 => edgeDatabaseIds.Contains(item1.Database.Id)))
                                      .Where(item => item.EdgeNodes.All(item1 => seedNodeIds.Contains(item1.Node.Id)))
                                      .Select(item => new EdgeItemModel
                    {
                        EdgeId       = item.Id,
                        SourceNodeId = item.EdgeNodes
                                       .Where(item1 => item1.Type == EdgeNodeType.Source)
                                       .Select(item1 => item1.Node.Id)
                                       .FirstOrDefault(),
                        TargetNodeId = item.EdgeNodes
                                       .Where(item => item.Type == EdgeNodeType.Target)
                                       .Select(item => item.Node.Id)
                                       .FirstOrDefault()
                    })
                                      .Where(item => !string.IsNullOrEmpty(item.EdgeId) && !string.IsNullOrEmpty(item.SourceNodeId) && !string.IsNullOrEmpty(item.TargetNodeId))
                                      .AsEnumerable()
                                      .Where(item => seedEdgesWithIds.Any(item1 => item1.Item1 == item.SourceNodeId && item1.Item2 == item.TargetNodeId))
                                      .ToList();
                }
                // Check if there haven't been any seed nodes found.
                if (currentEdgeList == null || !currentEdgeList.Any())
                {
                    // Use a new scope.
                    using (var scope = serviceProvider.CreateScope())
                    {
                        // Use a new context instance.
                        using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                        // Reload the network.
                        var network = context.Networks
                                      .FirstOrDefault(item => item.Id == networkId);
                        // Check if there was no item found.
                        if (network == null)
                        {
                            // Return.
                            return;
                        }
                        // Update the status of the item.
                        network.Status = NetworkStatus.Error;
                        // Add a message to the log.
                        network.Log = network.AppendToLog($"No seed {edgeTitle.ToLower()}s could be found with the provided seed data.");
                        // Edit the network.
                        await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);
                    }
                    // End the function.
                    return;
                }
                // Define the edges of the network.
                var edgeIds = currentEdgeList
                              .Select(item => item.EdgeId)
                              .Distinct()
                              .ToList();
                // Get all of the nodes used by the found edges.
                var nodeIds = currentEdgeList
                              .Select(item => item.SourceNodeId)
                              .Concat(currentEdgeList
                                      .Select(item => item.TargetNodeId))
                              .Distinct()
                              .ToList();
                // Update the seed node IDs.
                seedNodeIds = seedNodeIds
                              .Intersect(nodeIds)
                              .ToList();
                // Define the related entities.
                networkNodes = nodeIds
                               .Select(item => new NetworkNode
                {
                    NodeId = item,
                    Type   = NetworkNodeType.None
                })
                               .Concat(seedNodeIds
                                       .Select(item => new NetworkNode
                {
                    NodeId = item,
                    Type   = NetworkNodeType.Seed
                }))
                               .ToList();
                networkEdges = edgeIds
                               .Select(item => new NetworkEdge
                {
                    EdgeId = item
                })
                               .ToList();
            }
            // Use a new scope.
            using (var scope = serviceProvider.CreateScope())
            {
                // Use a new context instance.
                using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                // Reload the network.
                var network = context.Networks
                              .FirstOrDefault(item => item.Id == networkId);
                // Check if there was no item found.
                if (network == null)
                {
                    // Return.
                    return;
                }
                // Update the network.
                network.NetworkNodes = networkNodes;
                network.NetworkEdges = networkEdges;
                // Edit the network.
                await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);
            }
        }
        /// <summary>
        /// Edits the items in the database.
        /// </summary>
        /// <param name="serviceProvider">The application service provider.</param>
        /// <param name="token">The cancellation token for the task.</param>
        public async Task EditAsync(IServiceProvider serviceProvider, CancellationToken token)
        {
            // Check if there weren't any valid items found.
            if (Items == null)
            {
                // Throw an exception.
                throw new TaskException("No valid items could be found with the provided data.");
            }
            // Check if the exception item should be shown.
            var showExceptionItem = Items.Count() > 1;
            // Get the total number of batches.
            var count = Math.Ceiling((double)Items.Count() / ApplicationDbContext.BatchSize);

            // Go over each batch.
            for (var index = 0; index < count; index++)
            {
                // Check if the cancellation was requested.
                if (token.IsCancellationRequested)
                {
                    // Break.
                    break;
                }
                // Get the items in the current batch.
                var batchItems = Items
                                 .Skip(index * ApplicationDbContext.BatchSize)
                                 .Take(ApplicationDbContext.BatchSize);
                // Get the IDs of the items in the current batch.
                var batchIds = batchItems
                               .Where(item => !string.IsNullOrEmpty(item.Id))
                               .Select(item => item.Id);
                // Get the IDs of the related entities that appear in the current batch.
                var batchDatabaseIds = batchItems
                                       .Where(item => item.NodeCollectionDatabases != null)
                                       .Select(item => item.NodeCollectionDatabases)
                                       .SelectMany(item => item)
                                       .Where(item => item.Database != null)
                                       .Select(item => item.Database)
                                       .Where(item => !string.IsNullOrEmpty(item.Id))
                                       .Select(item => item.Id)
                                       .Distinct();
                var batchNodeIds = batchItems
                                   .Where(item => item.NodeCollectionNodes != null)
                                   .Select(item => item.NodeCollectionNodes)
                                   .SelectMany(item => item)
                                   .Where(item => item.Node != null)
                                   .Select(item => item.Node)
                                   .Where(item => !string.IsNullOrEmpty(item.Id))
                                   .Select(item => item.Id)
                                   .Distinct();
                // Define the list of items to get.
                var nodeCollections = new List <NodeCollection>();
                var databases       = new List <Database>();
                var nodes           = new List <Node>();
                // Use a new scope.
                using (var scope = serviceProvider.CreateScope())
                {
                    // Use a new context instance.
                    using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                    // Get the items with the provided IDs.
                    var items = context.NodeCollections
                                .Where(item => !item.NodeCollectionDatabases.Any(item1 => item1.Database.DatabaseType.Name == "Generic"))
                                .Where(item => batchIds.Contains(item.Id));
                    // Check if there were no items found.
                    if (items == null || !items.Any())
                    {
                        // Continue.
                        continue;
                    }
                    // Get the items found.
                    nodeCollections = items
                                      .ToList();
                    // Get the related entities that appear in the current batch.
                    databases = context.Databases
                                .Where(item => item.DatabaseType.Name != "Generic")
                                .Where(item => batchDatabaseIds.Contains(item.Id))
                                .Distinct()
                                .ToList();
                    nodes = context.Nodes
                            .Where(item => !item.DatabaseNodes.Any(item1 => item1.Database.DatabaseType.Name == "Generic"))
                            .Where(item => batchNodeIds.Contains(item.Id))
                            .ToList();
                }
                // Get the IDs of the items.
                var nodeCollectionIds = nodeCollections
                                        .Select(item => item.Id);
                // Save the items to edit.
                var nodeCollectionsToEdit = new List <NodeCollection>();
                // Go over each of the valid items.
                foreach (var batchItem in batchItems)
                {
                    // Get the corresponding item.
                    var nodeCollection = nodeCollections
                                         .FirstOrDefault(item => batchItem.Id == item.Id);
                    // Check if there was no item found.
                    if (nodeCollection == null)
                    {
                        // Continue.
                        continue;
                    }
                    // Check if there were no node collection databases provided.
                    if (batchItem.NodeCollectionDatabases == null || !batchItem.NodeCollectionDatabases.Any())
                    {
                        // Throw an exception.
                        throw new TaskException("There were no node collection databases provided.", showExceptionItem, batchItem);
                    }
                    // Get the node collection databases.
                    var nodeCollectionDatabases = batchItem.NodeCollectionDatabases
                                                  .Where(item => item.Database != null)
                                                  .Where(item => !string.IsNullOrEmpty(item.Database.Id))
                                                  .Select(item => item.Database.Id)
                                                  .Distinct()
                                                  .Where(item => databases.Any(item1 => item1.Id == item))
                                                  .Select(item => new NodeCollectionDatabase
                    {
                        DatabaseId = item
                    });
                    // Check if there were no node collection databases found.
                    if (nodeCollectionDatabases == null || !nodeCollectionDatabases.Any())
                    {
                        // Throw an exception.
                        throw new TaskException("There were no node collection databases found.", showExceptionItem, batchItem);
                    }
                    // Check if there were no node collection nodes provided.
                    if (batchItem.NodeCollectionNodes == null || !batchItem.NodeCollectionNodes.Any())
                    {
                        // Throw an exception.
                        throw new TaskException("There were no node collection nodes provided.", showExceptionItem, batchItem);
                    }
                    // Get the node collection nodes.
                    var nodeCollectionNodes = batchItem.NodeCollectionNodes
                                              .Where(item => item.Node != null)
                                              .Where(item => !string.IsNullOrEmpty(item.Node.Id))
                                              .Where(item => nodes.Any(item1 => item1.Id == item.Node.Id))
                                              .Select(item => new NodeCollectionNode
                    {
                        NodeId = item.Node.Id
                    });
                    // Check if there were no node collection nodes found.
                    if (nodeCollectionNodes == null || !nodeCollectionNodes.Any())
                    {
                        // Throw an exception.
                        throw new TaskException("There were no node collection nodes found.", showExceptionItem, batchItem);
                    }
                    // Check if there were no node collection types provided.
                    if (batchItem.NodeCollectionTypes == null || !batchItem.NodeCollectionTypes.Any())
                    {
                        // Throw an exception.
                        throw new TaskException("There were no node collection types provided.", showExceptionItem, batchItem);
                    }
                    // Get the node collection types.
                    var nodeCollectionTypes = batchItem.NodeCollectionTypes
                                              .Select(item => item.Type)
                                              .Select(item => (Enum.TryParse <EnumerationNodeCollectionType>(item, out var type), type))
                                              .Where(item => item.Item1)
                                              .Select(item => new NodeCollectionType
                    {
                        Type = item.Item2
                    });
                    // Check if there were no node collection types found.
                    if (nodeCollectionTypes == null || !nodeCollectionTypes.Any())
                    {
                        // Throw an exception.
                        throw new TaskException("There were no node collection types found.", showExceptionItem, batchItem);
                    }
                    // Update the node collection.
                    nodeCollection.Name                    = batchItem.Name;
                    nodeCollection.Description             = batchItem.Description;
                    nodeCollection.NodeCollectionTypes     = nodeCollectionTypes.ToList();
                    nodeCollection.NodeCollectionDatabases = nodeCollectionDatabases.ToList();
                    nodeCollection.NodeCollectionNodes     = nodeCollectionNodes.ToList();
                    // Add the node collection to the list.
                    nodeCollectionsToEdit.Add(nodeCollection);
                }
                // Delete the dependent entities.
                await NodeCollectionExtensions.DeleteDependentAnalysesAsync(nodeCollectionIds, serviceProvider, token);

                await NodeCollectionExtensions.DeleteDependentNetworksAsync(nodeCollectionIds, serviceProvider, token);

                // Delete the related entities.
                await NodeCollectionExtensions.DeleteRelatedEntitiesAsync <NodeCollectionType>(nodeCollectionIds, serviceProvider, token);

                await NodeCollectionExtensions.DeleteRelatedEntitiesAsync <NodeCollectionNode>(nodeCollectionIds, serviceProvider, token);

                await NodeCollectionExtensions.DeleteRelatedEntitiesAsync <NodeCollectionDatabase>(nodeCollectionIds, serviceProvider, token);

                // Update the items.
                await IEnumerableExtensions.EditAsync(nodeCollectionsToEdit, serviceProvider, token);
            }
        }
        /// <summary>
        /// Edits the items in the database.
        /// </summary>
        /// <param name="serviceProvider">The application service provider.</param>
        /// <param name="token">The cancellation token for the task.</param>
        public async Task EditAsync(IServiceProvider serviceProvider, CancellationToken token)
        {
            // Check if there weren't any valid items found.
            if (Items == null)
            {
                // Throw an exception.
                throw new TaskException("No valid items could be found with the provided data.");
            }
            // Check if the exception item should be shown.
            var showExceptionItem = Items.Count() > 1;
            // Get the total number of batches.
            var count = Math.Ceiling((double)Items.Count() / ApplicationDbContext.BatchSize);

            // Go over each batch.
            for (var index = 0; index < count; index++)
            {
                // Check if the cancellation was requested.
                if (token.IsCancellationRequested)
                {
                    // Break.
                    break;
                }
                // Get the items in the current batch.
                var batchItems = Items
                                 .Skip(index * ApplicationDbContext.BatchSize)
                                 .Take(ApplicationDbContext.BatchSize);
                // Get the IDs of the items in the current batch.
                var batchIds = batchItems
                               .Where(item => !string.IsNullOrEmpty(item.Id))
                               .Select(item => item.Id)
                               .Distinct();
                // Get the IDs of the related entities that appear in the current batch.
                var batchDatabaseNodeFieldIds = batchItems
                                                .Where(item => item.DatabaseNodeFieldNodes != null)
                                                .Select(item => item.DatabaseNodeFieldNodes)
                                                .SelectMany(item => item)
                                                .Where(item => item.DatabaseNodeField != null)
                                                .Select(item => item.DatabaseNodeField)
                                                .Where(item => !string.IsNullOrEmpty(item.Id))
                                                .Select(item => item.Id)
                                                .Distinct();
                // Define the list of items to get.
                var nodes = new List <Node>();
                var databaseNodeFields = new List <DatabaseNodeField>();
                // Define the dependent list of items to get.
                var analysisInputs = new List <AnalysisInputModel>();
                var networkInputs  = new List <NetworkInputModel>();
                var edgeInputs     = new List <EdgeInputModel>();
                // Use a new scope.
                using (var scope = serviceProvider.CreateScope())
                {
                    // Use a new context instance.
                    using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                    // Get the items with the provided IDs.
                    var items = context.Nodes
                                .Where(item => !item.DatabaseNodes.Any(item1 => item1.Database.DatabaseType.Name == "Generic"))
                                .Where(item => batchIds.Contains(item.Id));
                    // Check if there were no items found.
                    if (items == null || !items.Any())
                    {
                        // Continue.
                        continue;
                    }
                    // Get the items found.
                    nodes = items
                            .ToList();
                    // Get the related entities that appear in the current batch.
                    databaseNodeFields = context.DatabaseNodeFields
                                         .Include(item => item.Database)
                                         .Where(item => item.Database.DatabaseType.Name != "Generic")
                                         .Where(item => batchDatabaseNodeFieldIds.Contains(item.Id))
                                         .ToList();
                }
                // Get the IDs of the items.
                var nodeIds = nodes
                              .Select(item => item.Id);
                // Save the items to edit.
                var nodesToEdit = new List <Node>();
                // Go over each item in the current batch.
                foreach (var batchItem in batchItems)
                {
                    // Get the corresponding item.
                    var node = nodes
                               .FirstOrDefault(item => item.Id == batchItem.Id);
                    // Check if there was no item found.
                    if (node == null)
                    {
                        // Continue.
                        continue;
                    }
                    // Check if there are no database node field nodes provided.
                    if (batchItem.DatabaseNodeFieldNodes == null || !batchItem.DatabaseNodeFieldNodes.Any())
                    {
                        // Throw an exception.
                        throw new TaskException("There were no database node field nodes provided.", showExceptionItem, batchItem);
                    }
                    // Get the database node field nodes.
                    var databaseNodeFieldNodes = batchItem.DatabaseNodeFieldNodes
                                                 .Where(item => item.DatabaseNodeField != null)
                                                 .Where(item => !string.IsNullOrEmpty(item.DatabaseNodeField.Id))
                                                 .Where(item => !string.IsNullOrEmpty(item.Value))
                                                 .Select(item => (item.DatabaseNodeField.Id, item.Value))
                                                 .Distinct()
                                                 .Where(item => databaseNodeFields.Any(item1 => item1.Id == item.Item1))
                                                 .Select(item => new DatabaseNodeFieldNode
                    {
                        DatabaseNodeFieldId = item.Item1,
                        Value = item.Item2
                    });
                    // Check if there were no database node fields found.
                    if (databaseNodeFieldNodes == null)
                    {
                        // Throw an exception.
                        throw new TaskException("There were no database node fields found.", showExceptionItem, batchItem);
                    }
                    // Check if there were no searchable database node fields found.
                    var databaseNodeFieldIds = databaseNodeFieldNodes
                                               .Select(item => item.DatabaseNodeFieldId)
                                               .Distinct();
                    var currentDatabaseNodeFields = databaseNodeFields
                                                    .Where(item => databaseNodeFieldIds.Contains(item.Id));
                    if (!currentDatabaseNodeFields.Any(item => item.IsSearchable))
                    {
                        // Throw an exception.
                        throw new TaskException("There were no searchable database node fields found.", showExceptionItem, batchItem);
                    }
                    // Update the node.
                    node.Name = !string.IsNullOrEmpty(batchItem.Name) ? batchItem.Name :
                                (databaseNodeFieldNodes
                                 .FirstOrDefault(item => item.DatabaseNodeFieldId == currentDatabaseNodeFields
                                                 .FirstOrDefault(item => item.IsSearchable)?.Id)?.Value ??
                                 "Unnamed node");
                    node.Description            = batchItem.Description;
                    node.DatabaseNodeFieldNodes = databaseNodeFieldNodes.ToList();
                    node.DatabaseNodes          = currentDatabaseNodeFields
                                                  .Select(item => item.Database)
                                                  .Distinct()
                                                  .Select(item => new DatabaseNode
                    {
                        DatabaseId = item.Id
                    })
                                                  .ToList();
                    // Add the node to the list.
                    nodesToEdit.Add(node);
                }
                // Delete the dependent entities.
                await NodeExtensions.DeleteDependentAnalysesAsync(nodeIds, serviceProvider, token);

                await NodeExtensions.DeleteDependentNetworksAsync(nodeIds, serviceProvider, token);

                await NodeExtensions.DeleteDependentNodeCollectionsAsync(nodeIds, serviceProvider, token);

                await NodeExtensions.DeleteDependentEdgesAsync(nodeIds, serviceProvider, token);

                // Delete the related entities.
                await NodeExtensions.DeleteRelatedEntitiesAsync <DatabaseNodeFieldNode>(nodeIds, serviceProvider, token);

                await NodeExtensions.DeleteRelatedEntitiesAsync <DatabaseNode>(nodeIds, serviceProvider, token);

                // Edit the items.
                await IEnumerableExtensions.EditAsync(nodesToEdit, serviceProvider, token);
            }
        }
Exemple #4
0
        /// <summary>
        /// Edits the items in the database.
        /// </summary>
        /// <param name="serviceProvider">The application service provider.</param>
        /// <param name="token">The cancellation token for the task.</param>
        public async Task EditAsync(IServiceProvider serviceProvider, CancellationToken token)
        {
            // Check if there weren't any valid items found.
            if (Items == null)
            {
                // Throw an exception.
                throw new TaskException("No valid items could be found with the provided data.");
            }
            // Check if the exception item should be shown.
            var showExceptionItem = Items.Count() > 1;
            // Get the total number of batches.
            var count = Math.Ceiling((double)Items.Count() / ApplicationDbContext.BatchSize);

            // Go over each batch.
            for (var index = 0; index < count; index++)
            {
                // Check if the cancellation was requested.
                if (token.IsCancellationRequested)
                {
                    // Break.
                    break;
                }
                // Get the items in the current batch.
                var batchItems = Items
                                 .Skip(index * ApplicationDbContext.BatchSize)
                                 .Take(ApplicationDbContext.BatchSize);
                // Get the IDs of the items in the current batch.
                var batchIds = batchItems
                               .Where(item => !string.IsNullOrEmpty(item.Id))
                               .Select(item => item.Id)
                               .Distinct();
                var batchNames = batchItems
                                 .Where(item => !string.IsNullOrEmpty(item.Name))
                                 .Select(item => item.Name)
                                 .Distinct();
                // Define the list of items to get.
                var databaseEdgeFields         = new List <DatabaseEdgeField>();
                var existingDatabaseEdgeFields = new List <DatabaseEdgeField>();
                // Use a new scope.
                using (var scope = serviceProvider.CreateScope())
                {
                    // Use a new context instance.
                    using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                    // Get the items with the provided IDs.
                    var items = context.DatabaseEdgeFields
                                .Include(item => item.Database)
                                .ThenInclude(item => item.DatabaseType)
                                .Where(item => batchIds.Contains(item.Id));
                    // Check if there were no items found.
                    if (items == null || !items.Any())
                    {
                        // Continue.
                        continue;
                    }
                    // Get the items found.
                    databaseEdgeFields = items
                                         .ToList();
                    // Get the related entities that appear in the current batch.
                    existingDatabaseEdgeFields = context.DatabaseEdgeFields
                                                 .Where(item => batchNames.Contains(item.Name))
                                                 .ToList();
                }
                // Save the items to edit.
                var databaseEdgeFieldsToEdit = new List <DatabaseEdgeField>();
                // Go over each item in the current batch.
                foreach (var batchItem in batchItems)
                {
                    // Get the corresponding items.
                    var databaseEdgeField = databaseEdgeFields
                                            .FirstOrDefault(item => item.Id == batchItem.Id);
                    // Check if there was no item found.
                    if (databaseEdgeField == null)
                    {
                        // Continue.
                        continue;
                    }
                    // Check if the database edge field is generic.
                    if (databaseEdgeField.Database.DatabaseType.Name == "Generic")
                    {
                        // Throw an exception.
                        throw new TaskException("The generic database edge field can't be edited.", showExceptionItem, batchItem);
                    }
                    // Check if there is another database edge field with the same name.
                    if (existingDatabaseEdgeFields.Any(item => item.Id != databaseEdgeField.Id && item.Name == batchItem.Name) || databaseEdgeFieldsToEdit.Any(item => item.Name == batchItem.Name))
                    {
                        // Throw an exception.
                        throw new TaskException("A database edge field with the name already exists.", showExceptionItem, batchItem);
                    }
                    // Update the item.
                    databaseEdgeField.Name         = batchItem.Name;
                    databaseEdgeField.Description  = batchItem.Description;
                    databaseEdgeField.Url          = batchItem.Url;
                    databaseEdgeField.IsSearchable = batchItem.IsSearchable;
                    // Add the item to the list.
                    databaseEdgeFieldsToEdit.Add(databaseEdgeField);
                }
                // Edit the items.
                await IEnumerableExtensions.EditAsync(databaseEdgeFieldsToEdit, serviceProvider, token);
            }
        }
        /// <summary>
        /// Edits the items in the database.
        /// </summary>
        /// <param name="serviceProvider">The application service provider.</param>
        /// <param name="token">The cancellation token for the task.</param>
        public async Task EditAsync(IServiceProvider serviceProvider, CancellationToken token)
        {
            // Check if there weren't any valid items found.
            if (Items == null)
            {
                // Throw an exception.
                throw new TaskException("No valid items could be found with the provided data.");
            }
            // Check if the exception item should be shown.
            var showExceptionItem = Items.Count() > 1;
            // Get the total number of batches.
            var count = Math.Ceiling((double)Items.Count() / ApplicationDbContext.BatchSize);

            // Go over each batch.
            for (var index = 0; index < count; index++)
            {
                // Check if the cancellation was requested.
                if (token.IsCancellationRequested)
                {
                    // Break.
                    break;
                }
                // Get the items in the current batch.
                var batchItems = Items
                                 .Skip(index * ApplicationDbContext.BatchSize)
                                 .Take(ApplicationDbContext.BatchSize);
                // Get the IDs of the items in the current batch.
                var batchIds = batchItems
                               .Where(item => !string.IsNullOrEmpty(item.Id))
                               .Select(item => item.Id);
                // Get the IDs of the related entities that appear in the current batch.
                var batchDatabaseIds = batchItems
                                       .Where(item => item.DatabaseEdges != null)
                                       .Select(item => item.DatabaseEdges)
                                       .SelectMany(item => item)
                                       .Where(item => item.Database != null)
                                       .Select(item => item.Database)
                                       .Where(item => !string.IsNullOrEmpty(item.Id))
                                       .Select(item => item.Id)
                                       .Distinct();
                var batchDatabaseEdgeFieldIds = batchItems
                                                .Where(item => item.DatabaseEdgeFieldEdges != null)
                                                .Select(item => item.DatabaseEdgeFieldEdges)
                                                .SelectMany(item => item)
                                                .Where(item => item.DatabaseEdgeField != null)
                                                .Select(item => item.DatabaseEdgeField)
                                                .Where(item => !string.IsNullOrEmpty(item.Id))
                                                .Select(item => item.Id)
                                                .Distinct();
                var batchNodeIds = batchItems
                                   .Where(item => item.EdgeNodes != null)
                                   .Select(item => item.EdgeNodes)
                                   .SelectMany(item => item)
                                   .Where(item => item.Node != null)
                                   .Select(item => item.Node)
                                   .Where(item => !string.IsNullOrEmpty(item.Id))
                                   .Select(item => item.Id)
                                   .Distinct();
                // Define the list of items to get.
                var edges              = new List <Edge>();
                var databases          = new List <Database>();
                var databaseEdgeFields = new List <DatabaseEdgeField>();
                var nodes              = new List <Node>();
                // Use a new scope.
                using (var scope = serviceProvider.CreateScope())
                {
                    // Use a new context instance.
                    using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                    // Get the items with the provided IDs.
                    var items = context.Edges
                                .Where(item => !item.DatabaseEdges.Any(item1 => item1.Database.DatabaseType.Name == "Generic"))
                                .Where(item => batchIds.Contains(item.Id));
                    // Check if there were no items found.
                    if (items == null || !items.Any())
                    {
                        // Continue.
                        continue;
                    }
                    // Get the items found.
                    edges = items
                            .ToList();
                    // Get the related entities that appear in the current batch.
                    databaseEdgeFields = context.DatabaseEdgeFields
                                         .Where(item => item.Database.DatabaseType.Name != "Generic")
                                         .Where(item => batchDatabaseEdgeFieldIds.Contains(item.Id))
                                         .ToList();
                    databases = context.Databases
                                .Where(item => item.DatabaseType.Name != "Generic")
                                .Where(item => batchDatabaseIds.Contains(item.Id))
                                .Concat(context.DatabaseEdgeFields
                                        .Where(item => item.Database.DatabaseType.Name != "Generic")
                                        .Where(item => batchDatabaseEdgeFieldIds.Contains(item.Id))
                                        .Select(item => item.Database))
                                .Distinct()
                                .ToList();
                    nodes = context.Nodes
                            .Where(item => !item.DatabaseNodes.Any(item1 => item1.Database.DatabaseType.Name == "Generic"))
                            .Where(item => batchNodeIds.Contains(item.Id))
                            .ToList();
                }
                // Get the IDs of the items.
                var edgeIds = edges
                              .Select(item => item.Id);
                // Save the items to edit.
                var edgesToEdit = new List <Edge>();
                // Go over each of the valid items.
                foreach (var batchItem in batchItems)
                {
                    // Get the corresponding item.
                    var edge = edges
                               .FirstOrDefault(item => batchItem.Id == item.Id);
                    // Check if there was no item found.
                    if (edge == null)
                    {
                        // Continue.
                        continue;
                    }
                    // Check if there were no edge nodes provided.
                    if (batchItem.EdgeNodes == null || !batchItem.EdgeNodes.Any())
                    {
                        // Throw an exception.
                        throw new TaskException("There were no edge nodes provided.", showExceptionItem, batchItem);
                    }
                    // Get the edge nodes.
                    var edgeNodes = batchItem.EdgeNodes
                                    .Where(item => item.Node != null)
                                    .Where(item => !string.IsNullOrEmpty(item.Node.Id))
                                    .Where(item => item.Type == "Source" || item.Type == "Target")
                                    .Select(item => (item.Node.Id, item.Type))
                                    .Distinct()
                                    .Where(item => nodes.Any(item1 => item1.Id == item.Item1))
                                    .Select(item => new EdgeNode
                    {
                        NodeId = item.Item1,
                        Type   = EnumerationExtensions.GetEnumerationValue <EdgeNodeType>(item.Item2)
                    });
                    // Check if there were no edge nodes found.
                    if (edgeNodes == null || !edgeNodes.Any(item => item.Type == EdgeNodeType.Source) || !edgeNodes.Any(item => item.Type == EdgeNodeType.Target))
                    {
                        // Throw an exception.
                        throw new TaskException("There were no edge nodes found.", showExceptionItem, batchItem);
                    }
                    // Check if there were no database edges or database edge field edges provided.
                    if ((batchItem.DatabaseEdges == null || !batchItem.DatabaseEdges.Any()) && (batchItem.DatabaseEdgeFieldEdges == null || !batchItem.DatabaseEdgeFieldEdges.Any()))
                    {
                        // Throw an exception.
                        throw new TaskException("There were no database edges or database edge field edges provided.", showExceptionItem, batchItem);
                    }
                    // Get the database edge field edges.
                    var databaseEdgeFieldEdges = batchItem.DatabaseEdgeFieldEdges != null?
                                                 batchItem.DatabaseEdgeFieldEdges
                                                 .Where(item => item.DatabaseEdgeField != null)
                                                 .Where(item => !string.IsNullOrEmpty(item.DatabaseEdgeField.Id))
                                                 .Where(item => !string.IsNullOrEmpty(item.Value))
                                                 .Select(item => (item.DatabaseEdgeField.Id, item.Value))
                                                 .Distinct()
                                                 .Where(item => databaseEdgeFields.Any(item1 => item1.Id == item.Item1))
                                                 .Select(item => new DatabaseEdgeFieldEdge
                    {
                        DatabaseEdgeFieldId = item.Item1,
                        Value = item.Item2
                    }) :
                                                     Enumerable.Empty <DatabaseEdgeFieldEdge>();

                    // Get the database edges.
                    var databaseEdgeFieldIds = databaseEdgeFieldEdges
                                               .Select(item => item.DatabaseEdgeFieldId)
                                               .Distinct();
                    var currentDatabaseEdgeFields = databaseEdgeFields
                                                    .Where(item => databaseEdgeFieldIds.Contains(item.Id));
                    var databaseEdges = batchItem.DatabaseEdges != null?
                                        batchItem.DatabaseEdges
                                        .Where(item => item.Database != null)
                                        .Where(item => !string.IsNullOrEmpty(item.Database.Id))
                                        .Select(item => item.Database.Id)
                                        .Concat(currentDatabaseEdgeFields
                                                .Select(item => item.Database.Id))
                                        .Distinct()
                                        .Where(item => databases.Any(item1 => item1.Id == item))
                                        .Select(item => new DatabaseEdge
                    {
                        DatabaseId = item,
                    }) :
                                            Enumerable.Empty <DatabaseEdge>();

                    // Check if there were no database edges found.
                    if (databaseEdges == null || !databaseEdges.Any())
                    {
                        // Throw an exception.
                        throw new TaskException("There were no database edges found.", showExceptionItem, batchItem);
                    }
                    // Update the edge.
                    edge.Name        = string.Concat(nodes.First(item => item.Id == edgeNodes.First(item => item.Type == EdgeNodeType.Source).NodeId).Name, " - ", nodes.First(item => item.Id == edgeNodes.First(item => item.Type == EdgeNodeType.Target).NodeId).Name);
                    edge.Description = batchItem.Description;
                    edge.EdgeNodes   = new List <EdgeNode>
                    {
                        edgeNodes.First(item => item.Type == EdgeNodeType.Source),
                        edgeNodes.First(item => item.Type == EdgeNodeType.Target)
                    };
                    edge.DatabaseEdgeFieldEdges = databaseEdgeFieldEdges.ToList();
                    edge.DatabaseEdges          = databaseEdges.ToList();
                    // Add the edge to the list.
                    edgesToEdit.Add(edge);
                }
                // Delete the dependent entities.
                await EdgeExtensions.DeleteDependentAnalysesAsync(edgeIds, serviceProvider, token);

                await EdgeExtensions.DeleteDependentNetworksAsync(edgeIds, serviceProvider, token);

                // Delete the related entities.
                await EdgeExtensions.DeleteRelatedEntitiesAsync <EdgeNode>(edgeIds, serviceProvider, token);

                await EdgeExtensions.DeleteRelatedEntitiesAsync <DatabaseEdgeFieldEdge>(edgeIds, serviceProvider, token);

                await EdgeExtensions.DeleteRelatedEntitiesAsync <DatabaseEdge>(edgeIds, serviceProvider, token);

                // Update the items.
                await IEnumerableExtensions.EditAsync(edgesToEdit, serviceProvider, token);
            }
        }
        /// <summary>
        /// Runs the algorithm on the analysis with the provided details, using the given parameters.
        /// </summary>
        /// <param name="analysisId">The ID of the analysis which to run using the algorithm.</param>
        /// <param name="serviceProvider">The application service provider.</param>
        /// <param name="token">The cancellation token for the task.</param>
        /// <returns></returns>
        public static async Task Run(string analysisId, IServiceProvider serviceProvider, CancellationToken token)
        {
            // Define the required data.
            var analysisNodeIds   = new List <string>();
            var analysisEdgeIds   = new List <(string, string, string)>();
            var nodes             = new List <string>();
            var edges             = new List <(string, string)>();
            var sources           = new List <string>();
            var targets           = new List <string>();
            var parameters        = new Parameters();
            var maximumIterations = 100;
            var maximumIterationsWithoutImprovement = 25;

            // Use a new scope.
            using (var scope = serviceProvider.CreateScope())
            {
                // Use a new context instance.
                using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                // Reload the network.
                var analysis = context.Analyses
                               .FirstOrDefault(item => item.Id == analysisId);
                // Check if there was no item found.
                if (analysis == null)
                {
                    // Return.
                    return;
                }
                // Get the required data.
                analysisNodeIds = context.AnalysisNodes
                                  .Where(item => item.Analysis == analysis)
                                  .Where(item => item.Type == AnalysisNodeType.None)
                                  .Select(item => item.Node.Id)
                                  .ToList();
                analysisEdgeIds = context.AnalysisEdges
                                  .Where(item => item.Analysis == analysis)
                                  .Select(item => item.Edge)
                                  .Select(item => new
                {
                    Edge         = item.Id,
                    SourceNodeId = item.EdgeNodes
                                   .Where(item1 => item1.Type == EdgeNodeType.Source)
                                   .Select(item1 => item1.Node.Id)
                                   .FirstOrDefault(),
                    TargetNodeId = item.EdgeNodes
                                   .Where(item1 => item1.Type == EdgeNodeType.Target)
                                   .Select(item1 => item1.Node.Id)
                                   .FirstOrDefault()
                })
                                  .Where(item => !string.IsNullOrEmpty(item.SourceNodeId) && !string.IsNullOrEmpty(item.TargetNodeId))
                                  .AsEnumerable()
                                  .Select(item => (item.SourceNodeId, item.TargetNodeId, item.Edge))
                                  .Distinct()
                                  .ToList();
                // Get the nodes, edges, target nodes and source (preferred) nodes.
                nodes = analysisNodeIds
                        .ToList();
                edges = analysisEdgeIds
                        .Select(item => (item.Item1, item.Item2))
                        .ToList();
                sources = context.AnalysisNodes
                          .Where(item => item.Analysis == analysis)
                          .Where(item => item.Type == AnalysisNodeType.Source)
                          .Select(item => item.Node.Id)
                          .ToList();
                targets = context.AnalysisNodes
                          .Where(item => item.Analysis == analysis)
                          .Where(item => item.Type == AnalysisNodeType.Target)
                          .Select(item => item.Node.Id)
                          .ToList();
                // Check if there is any node in an edge that does not appear in the list of nodes.
                if (edges.Select(item => item.Item1).Concat(edges.Select(item => item.Item2)).Distinct().Except(nodes).Any())
                {
                    // Update the analysis with an error message.
                    analysis.Log = analysis.AppendToLog("There are edges which contain unknown nodes.");
                    // Update the analysis status.
                    analysis.Status = AnalysisStatus.Error;
                    // Update the analysis end time.
                    analysis.DateTimeEnded = DateTime.UtcNow;
                    // Update the analysis.
                    await IEnumerableExtensions.EditAsync(analysis.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Check if there is any target node that does not appear in the list of nodes.
                if (targets.Except(nodes).Any())
                {
                    // Update the analysis with an error message.
                    analysis.Log = analysis.AppendToLog("There are unknown target nodes.");
                    // Update the analysis status.
                    analysis.Status = AnalysisStatus.Error;
                    // Update the analysis end time.
                    analysis.DateTimeEnded = DateTime.UtcNow;
                    // Update the analysis.
                    await IEnumerableExtensions.EditAsync(analysis.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Check if there is any source node that does not appear in the list of nodes.
                if (sources.Except(nodes).Any())
                {
                    // Update the analysis with an error message.
                    analysis.Log = analysis.AppendToLog("There are unknown source nodes.");
                    // Update the analysis status.
                    analysis.Status = AnalysisStatus.Error;
                    // Update the analysis end time.
                    analysis.DateTimeEnded = DateTime.UtcNow;
                    // Update the analysis.
                    await IEnumerableExtensions.EditAsync(analysis.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Try to get the parameters for the algorithm.
                if (!analysis.Parameters.TryDeserializeJsonObject <Parameters>(out parameters))
                {
                    // Update the analysis with an error message.
                    analysis.Log = analysis.AppendToLog("The parameters are not valid for the algorithm.");
                    // Update the analysis status.
                    analysis.Status = AnalysisStatus.Error;
                    // Update the analysis end time.
                    analysis.DateTimeEnded = DateTime.UtcNow;
                    // Update the analysis.
                    await IEnumerableExtensions.EditAsync(analysis.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Set up the first iteration.
                maximumIterations = analysis.MaximumIterations;
                maximumIterationsWithoutImprovement = analysis.MaximumIterationsWithoutImprovement;
            }
            // Update the parameters.
            var heuristics = JsonSerializer.Deserialize <List <List <string> > >(parameters.Heuristics)
                             .TakeWhile(item => !item.Contains("Z"))
                             .Select(item => item.Distinct().ToList())
                             .Append(new List <string> {
                "Z"
            })
                             .ToList();

            parameters.Heuristics = JsonSerializer.Serialize(heuristics);
            // Use a new scope.
            using (var scope = serviceProvider.CreateScope())
            {
                // Use a new context instance.
                using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                // Reload the network.
                var analysis = context.Analyses
                               .FirstOrDefault(item => item.Id == analysisId);
                // Check if there was no item found.
                if (analysis == null)
                {
                    // Return.
                    return;
                }
                // Update the analysis status and parameters.
                analysis.Parameters = JsonSerializer.Serialize(parameters);
                analysis.Status     = AnalysisStatus.Ongoing;
                // Add a message to the log.
                analysis.Log = analysis.AppendToLog("The analysis is now running.");
                // Update the analysis.
                await IEnumerableExtensions.EditAsync(analysis.Yield(), serviceProvider, token);
            }
            // Define the required data.
            var analysisStillExists = true;
            var analysisStatus      = AnalysisStatus.Ongoing;
            var currentIteration    = 0;
            var currentIterationWithoutImprovement = 0;
            var controlPaths = new List <ControlPath>();

            // Use a new timer to display the progress.
            using (new Timer(async(state) =>
            {
                // Use a new scope.
                using (var scope = serviceProvider.CreateScope())
                {
                    // Use a new context instance.
                    using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                    // Reload the network.
                    var analysis = context.Analyses
                                   .FirstOrDefault(item => item.Id == analysisId);
                    // Update the loop variables.
                    analysisStillExists = analysis != null;
                    // Check if there was no item found.
                    if (analysis == null)
                    {
                        // Return.
                        return;
                    }
                    // Update the loop variables.
                    analysisStatus = analysis.Status;
                    // Update the iteration count.
                    analysis.CurrentIteration = currentIteration;
                    analysis.CurrentIterationWithoutImprovement = currentIterationWithoutImprovement;
                    // Update the analysis.
                    await IEnumerableExtensions.EditAsync(analysis.Yield(), serviceProvider, token);
                }
            }, null, TimeSpan.FromSeconds(0.0), TimeSpan.FromSeconds(30.0)))
            {
                // Set up the first iteration.
                var random           = new Random(parameters.RandomSeed);
                var bestSolutionSize = targets.Count() + 1;
                var bestControlPaths = new List <Dictionary <string, List <string> > >();
                // Run as long as the analysis exists and the final iteration hasn't been reached.
                while (analysisStillExists && analysisStatus == AnalysisStatus.Ongoing && currentIteration < maximumIterations && currentIterationWithoutImprovement < maximumIterationsWithoutImprovement && !token.IsCancellationRequested)
                {
                    // Move on to the next iterations.
                    currentIteration += 1;
                    currentIterationWithoutImprovement += 1;
                    // Define a variable to store the control paths.
                    var controlPath = new Dictionary <string, List <string> >();
                    // Set up the control path to start from the target nodes.
                    foreach (var node in targets)
                    {
                        controlPath[node] = new List <string> {
                            node
                        };
                    }
                    // Start from no repeats.
                    var currentRepeat = 0;
                    // Repeat as long as we haven't reached the limit.
                    while (currentRepeat < parameters.Repeats)
                    {
                        // Set the current targets as the initial targets.
                        var currentTargets = new List <string>(targets);
                        // Set the current path length to 0.
                        var currentPathLength = 0;
                        // Get the target nodes to keep. If it is the first check of the current iteration, we have no kept nodes, so the current targets are simply the targets. This is a part of the "repeat" optimization.
                        var keptTargetNodes = GetControllingNodes(controlPath)
                                              .Where(item => item.Value.Count() > 1)
                                              .Select(item => item.Value)
                                              .SelectMany(item => item)
                                              .ToHashSet();
                        // Go over each of the paths corresponding to the target nodes to reset.
                        foreach (var item in controlPath.Keys.Except(keptTargetNodes).ToList())
                        {
                            // Reset the control path.
                            controlPath[item] = new List <string>()
                            {
                                item
                            };
                        }
                        // Get the new targets.
                        currentTargets = currentTargets
                                         .Except(keptTargetNodes)
                                         .ToList();
                        // Run until there are no current targets or we reached the maximum path length.
                        while (currentTargets.Any() && currentPathLength < parameters.MaximumPathLength)
                        {
                            // Set all of the current targets as unmatched.
                            var unmatchedNodes = currentTargets.ToList();
                            // Set all nodes in the network as available to match.
                            var availableNodes = nodes.ToList();
                            // If it is the first check of the current iteration, there are no kept nodes, so the left nodes and edges remain unchanged. Otherwise, remove from the left nodes the corresponding nodes in the current step in the control paths for the kept nodes. This is a part of the "repeat" optimization.
                            availableNodes = availableNodes
                                             .Except(controlPath
                                                     .Where(item => keptTargetNodes.Contains(item.Key))
                                                     .Select(item => item.Value)
                                                     .Where(item => currentPathLength + 1 < item.Count())
                                                     .Select(item => item[currentPathLength + 1]))
                                             .ToList();
                            // Define a variable to store the matched edges of the matching.
                            var matchedEdges = new List <(string, string)>();
                            // Go over each heuristic set.
                            foreach (var heuristicSet in heuristics)
                            {
                                // Get the left nodes, right nodes, and edges of the current matching.
                                var leftNodes     = availableNodes.ToList();
                                var rightNodes    = unmatchedNodes.ToList();
                                var currentEdges  = GetSingleHeuristicEdges(leftNodes, rightNodes, edges, heuristicSet, controlPath, sources);
                                var matchingEdges = GetMaximumMatching(leftNodes, rightNodes, currentEdges, random);
                                // Add the matched edges to the list.
                                matchedEdges.AddRange(matchingEdges);
                                // Update the remaining nodes after the matching.
                                availableNodes.RemoveAll(item => matchingEdges.Any(item1 => item1.Item1 == item));
                                unmatchedNodes.RemoveAll(item => matchingEdges.Any(item1 => item1.Item2 == item));
                            }
                            // Update the current targets to the current matched edge source nodes, and the control path.
                            currentTargets = matchedEdges.Select(item => item.Item1).ToList();
                            // Get the dictionary which stores, for each target, the corresponding new matched target to add to the path.
                            var currentTargetDictionary = controlPath
                                                          .Where(item => item.Value.Count() == currentPathLength + 1)
                                                          .ToDictionary(item => item.Key, item => matchedEdges.Where(item1 => item1.Item2 == item.Value.Last()).Select(item1 => item1.Item1).FirstOrDefault())
                                                          .Where(item => item.Value != null);
                            // Go over all entries in dictionary.
                            foreach (var entry in currentTargetDictionary)
                            {
                                // Update the control path with the first node of the corresponding matched edge.
                                controlPath[entry.Key].Add(entry.Value);
                            }
                            // Update the current path length.
                            currentPathLength++;
                        }
                        // Update the current repeat count.
                        currentRepeat++;
                    }
                    // Define a variable to store if any path cuts have been performed. This is a part of the "cut-to-driven" optimization.
                    var pathCutsPerformed = false;
                    // Repeat until there are no more cuts.
                    do
                    {
                        // Reset the cut paths status.
                        pathCutsPerformed = false;
                        // Get the controlling nodes for the path.
                        var controllingNodes = GetControllingNodes(controlPath).Keys
                                               .ToHashSet();
                        // Go over each path in the control path.
                        foreach (var key in controlPath.Keys.ToList())
                        {
                            // Get the first index of any control node.
                            var index = controlPath[key].FindIndex(item => controllingNodes.Contains(item));
                            // Check if the index doesn't correspond to the last element in the list.
                            if (index < controlPath[key].Count() - 1)
                            {
                                // Cut the path up to the first index of any control node.
                                controlPath[key] = controlPath[key].Take(index + 1).ToList();
                                // Mark the cut as performed.
                                pathCutsPerformed = true;
                            }
                        }
                    } while (pathCutsPerformed);
                    // Compute the result.
                    var controlNodes = GetControllingNodes(controlPath).Keys.ToList();
                    // Check if the current solution is better than the previously obtained best solutions.
                    if (controlNodes.Count() < bestSolutionSize)
                    {
                        // Update the best solution.
                        bestSolutionSize = controlNodes.Count();
                        // Reset the number of iterations.
                        currentIterationWithoutImprovement = 0;
                        // Reset the best control paths.
                        bestControlPaths.RemoveAll(item => true);
                    }
                    // Check if the current solution is as good as the previously obtained best solutions.
                    if (controlNodes.Count() == bestSolutionSize)
                    {
                        // Check if none of the previous solutions has the same nodes.
                        if (!bestControlPaths.Any(item => !item.Keys.Except(controlPath.Keys).Any() && !controlPath.Keys.Except(item.Keys).Any()))
                        {
                            // Update the best control paths.
                            bestControlPaths.Add(controlPath);
                        }
                    }
                }
                // Get the control paths.
                controlPaths = bestControlPaths.Select(item => new ControlPath
                {
                    Paths = item.Values.Select(item1 =>
                    {
                        // Get the nodes and edges in the path.
                        var pathNodes = item1
                                        .Select(item2 => analysisNodeIds.FirstOrDefault(item3 => item3 == item2))
                                        .Where(item2 => item2 != null)
                                        .Reverse()
                                        .ToList();
                        var pathEdges = item1
                                        .Zip(item1.Skip(1), (item2, item3) => (item3.ToString(), item2.ToString()))
                                        .Select(item2 => analysisEdgeIds.FirstOrDefault(item3 => item3.Item1 == item2.Item1 && item3.Item2 == item2.Item2))
                                        .Select(item2 => item2.Item3)
                                        .Where(item2 => !string.IsNullOrEmpty(item2))
                                        .Reverse()
                                        .ToList();
                        // Return the path.
                        return(new Path
                        {
                            PathNodes = pathNodes.Select((item2, index) => new PathNode {
                                NodeId = item2, Type = PathNodeType.None, Index = index
                            })
                                        .Append(new PathNode {
                                NodeId = pathNodes.First(), Type = PathNodeType.Source, Index = -1
                            })
                                        .Append(new PathNode {
                                NodeId = pathNodes.Last(), Type = PathNodeType.Target, Index = pathNodes.Count()
                            })
                                        .ToList(),
                            PathEdges = pathEdges.Select((item2, index) => new PathEdge {
                                EdgeId = item2, Index = index
                            }).ToList()
                        });
                    }).ToList()
                }).ToList();
        /// <summary>
        /// Generates the items.
        /// </summary>
        /// <param name="serviceProvider">The application service provider.</param>
        /// <param name="token">The cancellation token for the task.</param>
        public async Task GenerateAsync(IServiceProvider serviceProvider, CancellationToken token)
        {
            // Check if there weren't any valid items found.
            if (Items == null)
            {
                // Throw an exception.
                throw new TaskException("No valid items could be found with the provided data.");
            }
            // Get the total number of batches.
            var count = Math.Ceiling((double)Items.Count() / ApplicationDbContext.BatchSize);

            // Go over each batch.
            for (var index = 0; index < count; index++)
            {
                // Check if the cancellation was requested.
                if (token.IsCancellationRequested)
                {
                    // Break.
                    break;
                }
                // Get the items in the current batch.
                var batchItems = Items
                                 .Skip(index * ApplicationDbContext.BatchSize)
                                 .Take(ApplicationDbContext.BatchSize)
                                 .ToList();
                // Get the IDs of the items in the current batch.
                var batchIds = batchItems.Select(item => item.Id);
                // Define the batch items.
                var batchNetworks = new List <Network>();
                // Use a new scope.
                using (var scope = serviceProvider.CreateScope())
                {
                    // Use a new context instance.
                    using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                    // Get the items with the provided IDs.
                    batchNetworks = context.Networks
                                    .Where(item => batchIds.Contains(item.Id))
                                    .ToList();
                }
                // Define the current retry.
                var currentRetry = 0;
                // Go over each item in the current batch.
                for (var batchItemIndex = 0; batchItemIndex < batchItems.Count(); batchItemIndex++)
                {
                    // Get the corresponding batch item.
                    var batchItem = batchItems[batchItemIndex];
                    // Get the corresponding item.
                    var batchNetwork = batchNetworks
                                       .FirstOrDefault(item => item.Id == batchItem.Id);
                    // Check if there was no item found.
                    if (batchNetwork == null)
                    {
                        // Continue.
                        continue;
                    }
                    // Check if the status is not valid.
                    if (batchNetwork.Status != NetworkStatus.Defined && batchNetwork.Status != NetworkStatus.Generating)
                    {
                        // Use a new scope.
                        using (var scope = serviceProvider.CreateScope())
                        {
                            // Use a new context instance.
                            using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                            // Reload the network.
                            var network = context.Networks
                                          .FirstOrDefault(item => item.Id == batchNetwork.Id);
                            // Check if there was no item found.
                            if (network == null)
                            {
                                // Continue.
                                continue;
                            }
                            // Update the status of the item.
                            network.Status = NetworkStatus.Error;
                            // Add a message to the log.
                            network.Log = network.AppendToLog("The status of the network is not valid in order to be generated.");
                            // Edit the network.
                            await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);
                        }
                        // Continue.
                        continue;
                    }
                    // Try to generate the network.
                    try
                    {
                        // Use a new scope.
                        using (var scope = serviceProvider.CreateScope())
                        {
                            // Use a new context instance.
                            using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                            // Reload the network.
                            var network = context.Networks
                                          .FirstOrDefault(item => item.Id == batchNetwork.Id);
                            // Check if there was no item found.
                            if (network == null)
                            {
                                // Continue.
                                continue;
                            }
                            // Update the status of the item.
                            network.Status = NetworkStatus.Generating;
                            // Add a message to the log.
                            network.Log = network.AppendToLog("The network is now generating.");
                            // Edit the network.
                            await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);
                        }
                        // Check the algorithm to generate the network.
                        switch (batchNetwork.Algorithm)
                        {
                        case NetworkAlgorithm.None:
                            // Run the algorithm on the network.
                            await Algorithms.Networks.None.Algorithm.Run(batchNetwork.Id, serviceProvider, token);

                            // End the switch.
                            break;

                        case NetworkAlgorithm.Neighbors:
                            // Run the algorithm on the network.
                            await Algorithms.Networks.Neighbors.Algorithm.Run(batchNetwork.Id, serviceProvider, token);

                            // End the switch.
                            break;

                        case NetworkAlgorithm.Gap0:
                            // Run the algorithm on the network.
                            await Algorithms.Networks.Gap.Algorithm.Run(batchNetwork.Id, 0, serviceProvider, token);

                            // End the switch.
                            break;

                        case NetworkAlgorithm.Gap1:
                            // Run the algorithm on the network.
                            await Algorithms.Networks.Gap.Algorithm.Run(batchNetwork.Id, 1, serviceProvider, token);

                            // End the switch.
                            break;

                        case NetworkAlgorithm.Gap2:
                            // Run the algorithm on the network.
                            await Algorithms.Networks.Gap.Algorithm.Run(batchNetwork.Id, 2, serviceProvider, token);

                            // End the switch.
                            break;

                        case NetworkAlgorithm.Gap3:
                            // Run the algorithm on the network.
                            await Algorithms.Networks.Gap.Algorithm.Run(batchNetwork.Id, 3, serviceProvider, token);

                            // End the switch.
                            break;

                        case NetworkAlgorithm.Gap4:
                            // Run the algorithm on the network.
                            await Algorithms.Networks.Gap.Algorithm.Run(batchNetwork.Id, 4, serviceProvider, token);

                            // End the switch.
                            break;

                        default:
                            // Use a new scope.
                            using (var scope = serviceProvider.CreateScope())
                            {
                                // Use a new context instance.
                                using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                                // Reload the network.
                                var network = context.Networks
                                              .FirstOrDefault(item => item.Id == batchNetwork.Id);
                                // Check if there was no item found.
                                if (network == null)
                                {
                                    // Continue.
                                    continue;
                                }
                                // Update the status of the item.
                                network.Status = NetworkStatus.Error;
                                // Add a message to the log.
                                network.Log = network.AppendToLog("The network algorithm is not valid.");
                                // Edit the network.
                                await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);
                            }
                            // End the switch.
                            break;
                        }
                    }
                    catch (Exception exception)
                    {
                        // Use a new scope.
                        using (var scope = serviceProvider.CreateScope())
                        {
                            // Use a new context instance.
                            using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                            // Reload the network.
                            var network = context.Networks
                                          .FirstOrDefault(item => item.Id == batchNetwork.Id);
                            // Check if there was no item found.
                            if (network == null)
                            {
                                // Continue.
                                continue;
                            }
                            // Update the status of the item.
                            network.Status = NetworkStatus.Defined;
                            // Add a message to the log.
                            network.Log = network.AppendToLog($"The try number {currentRetry + 1} ended with an error ({NumberOfRetries - currentRetry} tr{(NumberOfRetries - currentRetry != 1 ? "ies" : "y")} remaining). {(string.IsNullOrEmpty(exception.Message) ? "There was no error message returned." : exception.Message)}");
                            // Edit the network.
                            await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);
                        }
                        // Check if the task should be executed again.
                        if (currentRetry < NumberOfRetries)
                        {
                            // Increase the current retry.
                            currentRetry += 1;
                            // Repeat the loop for the current batch item.
                            batchItemIndex += -1;
                            // Continue.
                            continue;
                        }
                        // Use a new scope.
                        using (var scope = serviceProvider.CreateScope())
                        {
                            // Use a new context instance.
                            using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                            // Reload the network.
                            var network = context.Networks
                                          .FirstOrDefault(item => item.Id == batchNetwork.Id);
                            // Check if there was no item found.
                            if (network == null)
                            {
                                // Continue.
                                continue;
                            }
                            // Update the status of the item.
                            network.Status = NetworkStatus.Error;
                            // Add a message to the log.
                            network.Log = network.AppendToLog("One or more errors occured while generating the network.");
                            // Edit the network.
                            await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);
                        }
                        // Continue.
                        continue;
                    }
                    // Reset the current retry.
                    currentRetry = 0;
                    // Use a new scope.
                    using (var scope = serviceProvider.CreateScope())
                    {
                        // Use a new context instance.
                        using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                        // Reload the network.
                        var network = context.Networks
                                      .FirstOrDefault(item => item.Id == batchNetwork.Id);
                        // Check if there was no item found.
                        if (network == null)
                        {
                            // Continue.
                            continue;
                        }
                        // Check if an error has been encountered.
                        if (network.Status == NetworkStatus.Error)
                        {
                            // Continue.
                            continue;
                        }
                        // Update the status of the item.
                        network.Status = NetworkStatus.Completed;
                        // Add a message to the log.
                        network.Log = network.AppendToLog("The network has been successfully generated.");
                        // Remove the generation data.
                        network.Data = null;
                        // Edit the network.
                        await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);
                    }
                    // Use a new scope.
                    using (var scope = serviceProvider.CreateScope())
                    {
                        // Use a new context instance.
                        using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                        // Define the new background task.
                        var backgroundTask = new BackgroundTask
                        {
                            DateTimeCreated = DateTime.UtcNow,
                            Name            = $"{nameof(IContentTaskManager)}.{nameof(IContentTaskManager.SendNetworksEndedEmailsAsync)}",
                            IsRecurring     = false,
                            Data            = JsonSerializer.Serialize(new NetworksTask
                            {
                                Scheme    = Scheme,
                                HostValue = HostValue,
                                Items     = batchNetwork.Yield().Select(item => new NetworkInputModel
                                {
                                    Id = item.Id
                                })
                            })
                        };
                        // Mark the task for addition.
                        context.BackgroundTasks.Add(backgroundTask);
                        // Save the changes to the database.
                        await context.SaveChangesAsync();

                        // Create a new Hangfire background job.
                        BackgroundJob.Enqueue <IContentTaskManager>(item => item.SendNetworksEndedEmailsAsync(backgroundTask.Id, CancellationToken.None));
                    }
                }
            }
        }
        /// <summary>
        /// Edits the items in the database.
        /// </summary>
        /// <param name="serviceProvider">The application service provider.</param>
        /// <param name="token">The cancellation token for the task.</param>
        public async Task EditAsync(IServiceProvider serviceProvider, CancellationToken token)
        {
            // Check if there weren't any valid items found.
            if (Items == null)
            {
                // Throw an exception.
                throw new TaskException("No valid items could be found with the provided data.");
            }
            // Check if the exception item should be shown.
            var showExceptionItem = Items.Count() > 1;
            // Get the total number of batches.
            var count = Math.Ceiling((double)Items.Count() / ApplicationDbContext.BatchSize);

            // Go over each batch.
            for (var index = 0; index < count; index++)
            {
                // Check if the cancellation was requested.
                if (token.IsCancellationRequested)
                {
                    // Break.
                    break;
                }
                // Get the items in the current batch.
                var batchItems = Items
                                 .Skip(index * ApplicationDbContext.BatchSize)
                                 .Take(ApplicationDbContext.BatchSize);
                // Get the IDs of the items in the current batch.
                var batchIds = batchItems.Select(item => item.Id);
                // Define the list of items to get.
                var networks = new List <Network>();
                // Use a new scope.
                using (var scope = serviceProvider.CreateScope())
                {
                    // Use a new context instance.
                    using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                    // Get the items with the provided IDs.
                    var items = context.Networks
                                .Include(item => item.NetworkUsers)
                                .Where(item => batchIds.Contains(item.Id));
                    // Check if there were no items found.
                    if (items == null || !items.Any())
                    {
                        // Continue.
                        continue;
                    }
                    // Get the items found.
                    networks = items
                               .ToList();
                }
                // Save the items to add.
                var networksToEdit = new List <Network>();
                // Go over each item in the current batch.
                foreach (var batchItem in batchItems)
                {
                    // Get the corresponding item.
                    var network = networks.FirstOrDefault(item => item.Id == batchItem.Id);
                    // Check if there was no item found.
                    if (network == null)
                    {
                        // Continue.
                        continue;
                    }
                    // Check if there were no network users found.
                    if (!batchItem.IsPublic && (network.NetworkUsers == null || !network.NetworkUsers.Any()))
                    {
                        // Throw an exception.
                        throw new TaskException("There were no analysis users found, so the analysis must be public.", showExceptionItem, batchItem);
                    }
                    // Update the data.
                    network.Name        = batchItem.Name;
                    network.Description = batchItem.Description;
                    network.IsPublic    = batchItem.IsPublic;
                    // Append a message to the log.
                    network.Log = network.AppendToLog("The network details have been updated.");
                    // Add the item to the list.
                    networksToEdit.Add(network);
                }
                // Edit the items.
                await IEnumerableExtensions.EditAsync(networksToEdit, serviceProvider, token);
            }
        }
Exemple #9
0
        /// <summary>
        /// Edits the items in the database.
        /// </summary>
        /// <param name="serviceProvider">The application service provider.</param>
        /// <param name="token">The cancellation token for the task.</param>
        public async Task EditAsync(IServiceProvider serviceProvider, CancellationToken token)
        {
            // Check if there weren't any valid items found.
            if (Items == null)
            {
                // Throw an exception.
                throw new TaskException("No valid items could be found with the provided data.");
            }
            // Check if the exception item should be shown.
            var showExceptionItem = Items.Count() > 1;
            // Get the total number of batches.
            var count = Math.Ceiling((double)Items.Count() / ApplicationDbContext.BatchSize);

            // Go over each batch.
            for (var index = 0; index < count; index++)
            {
                // Check if the cancellation was requested.
                if (token.IsCancellationRequested)
                {
                    // Break.
                    break;
                }
                // Get the items in the current batch.
                var batchItems = Items
                                 .Skip(index * ApplicationDbContext.BatchSize)
                                 .Take(ApplicationDbContext.BatchSize);
                // Get the IDs of the items in the current batch.
                var batchIds = batchItems
                               .Where(item => !string.IsNullOrEmpty(item.Id))
                               .Select(item => item.Id);
                // Get the IDs of the related entities that appear in the current batch.
                var batchDatabaseIds = batchItems
                                       .Where(item => item.SampleDatabases != null)
                                       .Select(item => item.SampleDatabases)
                                       .SelectMany(item => item)
                                       .Where(item => item.Database != null)
                                       .Select(item => item.Database)
                                       .Where(item => !string.IsNullOrEmpty(item.Id))
                                       .Select(item => item.Id)
                                       .Distinct();
                // Define the list of items to get.
                var samples   = new List <Sample>();
                var databases = new List <Database>();
                // Use a new scope.
                using (var scope = serviceProvider.CreateScope())
                {
                    // Use a new context instance.
                    using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                    // Get the items with the provided IDs.
                    var items = context.Samples
                                .Where(item => batchIds.Contains(item.Id));
                    // Check if there were no items found.
                    if (items == null || !items.Any())
                    {
                        // Continue.
                        continue;
                    }
                    // Get the items found.
                    samples = items
                              .ToList();
                    // Get the related entities that appear in the current batch.
                    databases = context.Databases
                                .Where(item => batchDatabaseIds.Contains(item.Id))
                                .Distinct()
                                .ToList();
                }
                // Get the IDs of the items.
                var sampleIds = samples
                                .Select(item => item.Id);
                // Save the items to edit.
                var samplesToEdit = new List <Sample>();
                // Go over each of the valid items.
                foreach (var batchItem in batchItems)
                {
                    // Get the corresponding item.
                    var sample = samples
                                 .FirstOrDefault(item => batchItem.Id == item.Id);
                    // Check if there was no item found.
                    if (sample == null)
                    {
                        // Continue.
                        continue;
                    }
                    // Check if there were no sample databases provided.
                    if (batchItem.SampleDatabases == null || !batchItem.SampleDatabases.Any())
                    {
                        // Throw an exception.
                        throw new TaskException("There were no sample databases provided.", showExceptionItem, batchItem);
                    }
                    // Get the sample databases.
                    var sampleDatabases = batchItem.SampleDatabases
                                          .Where(item => item.Database != null)
                                          .Where(item => !string.IsNullOrEmpty(item.Database.Id))
                                          .Select(item => item.Database.Id)
                                          .Distinct()
                                          .Where(item => databases.Any(item1 => item1.Id == item))
                                          .Select(item => new SampleDatabase
                    {
                        DatabaseId = item
                    });
                    // Check if there were no node collection databases found.
                    if (sampleDatabases == null || !sampleDatabases.Any())
                    {
                        // Throw an exception.
                        throw new TaskException("There were no sample databases found.", showExceptionItem, batchItem);
                    }
                    // Check if the network algorithm is valid.
                    if (!Enum.TryParse <NetworkAlgorithm>(batchItem.NetworkAlgorithm, out var networkAlgorithm))
                    {
                        // Throw an exception.
                        throw new TaskException("The network algorithm is not valid.", showExceptionItem, batchItem);
                    }
                    // Update the node collection.
                    sample.Name                             = batchItem.Name;
                    sample.Description                      = batchItem.Description;
                    sample.NetworkName                      = batchItem.NetworkName;
                    sample.NetworkDescription               = batchItem.NetworkDescription;
                    sample.NetworkAlgorithm                 = networkAlgorithm;
                    sample.NetworkNodeDatabaseData          = batchItem.NetworkNodeDatabaseData;
                    sample.NetworkEdgeDatabaseData          = batchItem.NetworkEdgeDatabaseData;
                    sample.NetworkSeedNodeData              = batchItem.NetworkSeedNodeData;
                    sample.NetworkSeedEdgeData              = batchItem.NetworkSeedEdgeData;
                    sample.NetworkSeedNodeCollectionData    = batchItem.NetworkSeedNodeCollectionData;
                    sample.AnalysisName                     = batchItem.AnalysisName;
                    sample.AnalysisDescription              = batchItem.AnalysisDescription;
                    sample.AnalysisNetworkData              = batchItem.AnalysisNetworkData;
                    sample.AnalysisSourceNodeData           = batchItem.AnalysisSourceNodeData;
                    sample.AnalysisSourceNodeCollectionData = batchItem.AnalysisSourceNodeCollectionData;
                    sample.AnalysisTargetNodeData           = batchItem.AnalysisTargetNodeData;
                    sample.AnalysisTargetNodeCollectionData = batchItem.AnalysisTargetNodeCollectionData;
                    sample.SampleDatabases                  = sampleDatabases.ToList();
                    // Add the node collection to the list.
                    samplesToEdit.Add(sample);
                }
                // Delete the related entities.
                await SampleExtensions.DeleteRelatedEntitiesAsync <SampleDatabase>(sampleIds, serviceProvider, token);

                // Update the items.
                await IEnumerableExtensions.EditAsync(samplesToEdit, serviceProvider, token);
            }
        }
Exemple #10
0
        /// <summary>
        /// Runs the algorithm on the analysis with the provided details, using the given parameters.
        /// </summary>
        /// <param name="analysisId">The ID of the analysis which to run using the algorithm.</param>
        /// <param name="serviceProvider">The application service provider.</param>
        /// <param name="token">The cancellation token for the task.</param>
        /// <returns></returns>
        public static async Task Run(string analysisId, IServiceProvider serviceProvider, CancellationToken token)
        {
            // Define the required data.
            var analysisNodeIds   = new List <string>();
            var analysisEdgeIds   = new List <(string, string, string)>();
            var nodes             = new List <string>();
            var edges             = new List <(string, string)>();
            var sources           = new List <string>();
            var targets           = new List <string>();
            var parameters        = new Parameters();
            var maximumIterations = 100;
            var maximumIterationsWithoutImprovement = 25;

            // Use a new scope.
            using (var scope = serviceProvider.CreateScope())
            {
                // Use a new context instance.
                using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                // Reload the network.
                var analysis = context.Analyses
                               .FirstOrDefault(item => item.Id == analysisId);
                // Check if there was no item found.
                if (analysis == null)
                {
                    // Return.
                    return;
                }
                // Get the required data.
                analysisNodeIds = context.AnalysisNodes
                                  .Where(item => item.Analysis == analysis)
                                  .Where(item => item.Type == AnalysisNodeType.None)
                                  .Select(item => item.Node.Id)
                                  .ToList();
                analysisEdgeIds = context.AnalysisEdges
                                  .Where(item => item.Analysis == analysis)
                                  .Select(item => item.Edge)
                                  .Select(item => new
                {
                    Edge         = item.Id,
                    SourceNodeId = item.EdgeNodes
                                   .Where(item1 => item1.Type == EdgeNodeType.Source)
                                   .Select(item1 => item1.Node.Id)
                                   .FirstOrDefault(),
                    TargetNodeId = item.EdgeNodes
                                   .Where(item1 => item1.Type == EdgeNodeType.Target)
                                   .Select(item1 => item1.Node.Id)
                                   .FirstOrDefault()
                })
                                  .Where(item => !string.IsNullOrEmpty(item.SourceNodeId) && !string.IsNullOrEmpty(item.TargetNodeId))
                                  .AsEnumerable()
                                  .Select(item => (item.SourceNodeId, item.TargetNodeId, item.Edge))
                                  .Distinct()
                                  .ToList();
                // Get the nodes, edges, target nodes and source (preferred) nodes.
                nodes = analysisNodeIds
                        .ToList();
                edges = analysisEdgeIds
                        .Select(item => (item.Item1, item.Item2))
                        .ToList();
                sources = context.AnalysisNodes
                          .Where(item => item.Analysis == analysis)
                          .Where(item => item.Type == AnalysisNodeType.Source)
                          .Select(item => item.Node.Id)
                          .ToList();
                targets = context.AnalysisNodes
                          .Where(item => item.Analysis == analysis)
                          .Where(item => item.Type == AnalysisNodeType.Target)
                          .Select(item => item.Node.Id)
                          .ToList();
                // Check if there is any node in an edge that does not appear in the list of nodes.
                if (edges.Select(item => item.Item1).Concat(edges.Select(item => item.Item2)).Distinct().Except(nodes).Any())
                {
                    // Update the analysis with an error message.
                    analysis.Log = analysis.AppendToLog("There are edges which contain unknown nodes.");
                    // Update the analysis status.
                    analysis.Status = AnalysisStatus.Error;
                    // Update the analysis end time.
                    analysis.DateTimeEnded = DateTime.UtcNow;
                    // Update the analysis.
                    await IEnumerableExtensions.EditAsync(analysis.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Check if there is any target node that does not appear in the list of nodes.
                if (targets.Except(nodes).Any())
                {
                    // Update the analysis with an error message.
                    analysis.Log = analysis.AppendToLog("There are unknown target nodes.");
                    // Update the analysis status.
                    analysis.Status = AnalysisStatus.Error;
                    // Update the analysis end time.
                    analysis.DateTimeEnded = DateTime.UtcNow;
                    // Update the analysis.
                    await IEnumerableExtensions.EditAsync(analysis.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Check if there is any source node that does not appear in the list of nodes.
                if (sources.Except(nodes).Any())
                {
                    // Update the analysis with an error message.
                    analysis.Log = analysis.AppendToLog("There are unknown source nodes.");
                    // Update the analysis status.
                    analysis.Status = AnalysisStatus.Error;
                    // Update the analysis end time.
                    analysis.DateTimeEnded = DateTime.UtcNow;
                    // Update the analysis.
                    await IEnumerableExtensions.EditAsync(analysis.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Try to get the parameters for the algorithm.
                if (!analysis.Parameters.TryDeserializeJsonObject <Parameters>(out parameters))
                {
                    // Update the analysis with an error message.
                    analysis.Log = analysis.AppendToLog("The parameters are not valid for the algorithm.");
                    // Update the analysis status.
                    analysis.Status = AnalysisStatus.Error;
                    // Update the analysis end time.
                    analysis.DateTimeEnded = DateTime.UtcNow;
                    // Update the analysis.
                    await IEnumerableExtensions.EditAsync(analysis.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Set up the first iteration.
                maximumIterations = analysis.MaximumIterations;
                maximumIterationsWithoutImprovement = analysis.MaximumIterationsWithoutImprovement;
            }
            // Get the additional needed variables.
            var nodeIndex       = nodes.Select((item, index) => (item, index)).ToDictionary(item => item.item, item => item.index);
            var nodeIsPreferred = nodes.ToDictionary(item => item, item => sources.Contains(item));
            var matrixA         = GetMatrixA(nodeIndex, edges);
            var matrixC         = GetMatrixC(nodeIndex, targets);
            var powersMatrixA   = GetPowersMatrixA(matrixA, parameters.MaximumPathLength);
            var powersMatrixCA  = GetPowersMatrixCA(matrixC, powersMatrixA);
            var targetAncestors = GetTargetAncestors(powersMatrixA, targets, nodeIndex);

            // Use a new scope.
            using (var scope = serviceProvider.CreateScope())
            {
                // Use a new context instance.
                using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                // Reload the network.
                var analysis = context.Analyses
                               .FirstOrDefault(item => item.Id == analysisId);
                // Check if there was no item found.
                if (analysis == null)
                {
                    // Return.
                    return;
                }
                // Update the analysis status.
                analysis.Status = AnalysisStatus.Ongoing;
                // Add a message to the log.
                analysis.Log = analysis.AppendToLog("The analysis is now running.");
                // Update the analysis.
                await IEnumerableExtensions.EditAsync(analysis.Yield(), serviceProvider, token);
            }
            // Define the required data.
            var analysisStillExists = true;
            var analysisStatus      = AnalysisStatus.Ongoing;
            var currentIteration    = 0;
            var currentIterationWithoutImprovement = 0;
            var controlPaths = new List <ControlPath>();

            // Use a new timer to display the progress.
            using (new Timer(async(state) =>
            {
                // Use a new scope.
                using (var scope = serviceProvider.CreateScope())
                {
                    // Use a new context instance.
                    using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                    // Reload the network.
                    var analysis = context.Analyses
                                   .FirstOrDefault(item => item.Id == analysisId);
                    // Update the loop variables.
                    analysisStillExists = analysis != null;
                    // Check if there was no item found.
                    if (analysis == null)
                    {
                        // Return.
                        return;
                    }
                    // Update the loop variables.
                    analysisStatus = analysis.Status;
                    // Update the iteration count.
                    analysis.CurrentIteration = currentIteration;
                    analysis.CurrentIterationWithoutImprovement = currentIterationWithoutImprovement;
                    // Update the analysis.
                    await IEnumerableExtensions.EditAsync(analysis.Yield(), serviceProvider, token);
                }
            }, null, TimeSpan.FromSeconds(0.0), TimeSpan.FromSeconds(30.0)))
            {
                // Set up the first iteration.
                var random           = new Random(parameters.RandomSeed);
                var bestSolutionSize = 0.0;
                // Initialize a new population.
                var population = new Population(nodeIndex, targets, targetAncestors, powersMatrixCA, nodeIsPreferred, parameters, random);
                // Run as long as the analysis exists and the final iteration hasn't been reached.
                while (analysisStillExists && analysisStatus == AnalysisStatus.Ongoing && currentIteration < maximumIterations && currentIterationWithoutImprovement < maximumIterationsWithoutImprovement && !token.IsCancellationRequested)
                {
                    // Move on to the next iterations.
                    currentIteration += 1;
                    currentIterationWithoutImprovement += 1;
                    // Move on to the next population.
                    population = new Population(population, nodeIndex, targets, targetAncestors, powersMatrixCA, nodeIsPreferred, parameters, random);
                    // Get the best fitness of the current solution.
                    var currentSolutionSize = population.GetFitnessList().Max();
                    // Check if the current solution is better than the previously obtained best solutions.
                    if (bestSolutionSize < currentSolutionSize)
                    {
                        // Update the best solution.
                        bestSolutionSize = currentSolutionSize;
                        // Reset the number of iterations.
                        currentIterationWithoutImprovement = 0;
                    }
                }
                // Get the control paths.
                controlPaths = population.GetControlPaths(nodeIndex, nodes, edges).Select(item => new ControlPath
                {
                    Paths = item.Values.Select(item1 =>
                    {
                        // Get the nodes and edges in the path.
                        var pathNodes = item1
                                        .Select(item2 => analysisNodeIds.FirstOrDefault(item3 => item3 == item2))
                                        .Where(item2 => item2 != null)
                                        .Reverse()
                                        .ToList();
                        var pathEdges = item1
                                        .Zip(item1.Skip(1), (item2, item3) => (item3.ToString(), item2.ToString()))
                                        .Select(item2 => analysisEdgeIds.FirstOrDefault(item3 => item3.Item1 == item2.Item1 && item3.Item2 == item2.Item2))
                                        .Select(item2 => item2.Item3)
                                        .Where(item2 => !string.IsNullOrEmpty(item2))
                                        .Reverse()
                                        .ToList();
                        // Return the path.
                        return(new Path
                        {
                            PathNodes = pathNodes.Select((item2, index) => new PathNode {
                                NodeId = item2, Type = PathNodeType.None, Index = index
                            })
                                        .Append(new PathNode {
                                NodeId = pathNodes.First(), Type = PathNodeType.Source, Index = -1
                            })
                                        .Append(new PathNode {
                                NodeId = pathNodes.Last(), Type = PathNodeType.Target, Index = pathNodes.Count()
                            })
                                        .ToList(),
                            PathEdges = pathEdges.Select((item2, index) => new PathEdge {
                                EdgeId = item2, Index = index
                            }).ToList()
                        });
                    }).ToList()
                }).ToList();
        /// <summary>
        /// Runs the algorithm on the network with the provided details, using the given parameters.
        /// </summary>
        /// <param name="networkId">The ID of the network on which to run the algorithm.</param>
        /// <param name="serviceProvider">The application service provider.</param>
        /// <param name="token">The cancellation token for the task.</param>
        /// <returns></returns>
        public static async Task Run(string networkId, IServiceProvider serviceProvider, CancellationToken token)
        {
            // Define the required data.
            var data                  = new List <NetworkNodeInputModel>();
            var databaseTypeName      = string.Empty;
            var nodeDatabaseIds       = new List <string>();
            var edgeDatabaseIds       = new List <string>();
            var seedNodeCollectionIds = new List <string>();

            // Use a new scope.
            using (var scope = serviceProvider.CreateScope())
            {
                // Use a new context instance.
                using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                // Reload the network.
                var network = context.Networks
                              .FirstOrDefault(item => item.Id == networkId);
                // Check if there was no item found.
                if (network == null)
                {
                    // Return.
                    return;
                }
                // Get the related data.
                var databaseTypes = context.NetworkDatabases
                                    .Where(item => item.Network == network)
                                    .Select(item => item.Database.DatabaseType);
                // Check if there was any error in retrieving related data from the database.
                if (databaseTypes == null)
                {
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog("There was an error in retrieving related data from the database.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Check if there weren't any database types found.
                if (!databaseTypes.Any())
                {
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog("No database types corresponding to the network databases could be found.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Check if the database types are different.
                if (databaseTypes.Distinct().Count() > 1)
                {
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog("The database types corresponding to the network databases are different.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Check if the database types are not valid.
                if (databaseTypes.Any(item => item.Name == "Generic"))
                {
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog("The database type corresponding to the network databases and the network algorithm don't match.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Get the database type name.
                databaseTypeName = databaseTypes.Select(item => item.Name).First();
                // Try to deserialize the data.
                if (!network.Data.TryDeserializeJsonObject <List <NetworkNodeInputModel> >(out data) || data == null)
                {
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog("The seed data corresponding to the network could not be deserialized.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Get the IDs of the required related data.
                nodeDatabaseIds = context.NetworkDatabases
                                  .Where(item => item.Network == network)
                                  .Where(item => item.Type == NetworkDatabaseType.Node)
                                  .Select(item => item.Database)
                                  .Distinct()
                                  .Select(item => item.Id)
                                  .ToList();
                edgeDatabaseIds = context.NetworkDatabases
                                  .Where(item => item.Network == network)
                                  .Where(item => item.Type == NetworkDatabaseType.Edge)
                                  .Select(item => item.Database)
                                  .Distinct()
                                  .Select(item => item.Id)
                                  .ToList();
                seedNodeCollectionIds = context.NetworkNodeCollections
                                        .Where(item => item.Network == network)
                                        .Where(item => item.Type == NetworkNodeCollectionType.Seed)
                                        .Select(item => item.NodeCollection)
                                        .Distinct()
                                        .Select(item => item.Id)
                                        .ToList();
            }
            // Get the related data.
            var nodeTitle = databaseTypeName == "PPI" ? "Protein" : "Node";
            var edgeTitle = databaseTypeName == "PPI" ? "Interaction" : "Edge";
            // Get the node identifiers from the data.
            var seedNodeIdentifiers = data
                                      .Where(item => item.Type == "Seed")
                                      .Select(item => item.Node)
                                      .Where(item => item != null)
                                      .Select(item => item.Id)
                                      .Where(item => !string.IsNullOrEmpty(item))
                                      .Distinct();
            // Define the required data.
            var seedNodeIds = new List <string>();

            // Use a new scope.
            using (var scope = serviceProvider.CreateScope())
            {
                // Use a new context instance.
                using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                // Reload the network.
                var network = context.Networks
                              .FirstOrDefault(item => item.Id == networkId);
                // Check if there was no item found.
                if (network == null)
                {
                    // Return.
                    return;
                }
                // Get the available nodes.
                var availableNodes = context.Nodes
                                     .Where(item => item.DatabaseNodes.Any(item1 => nodeDatabaseIds.Contains(item1.Database.Id)));
                // Check if there haven't been any available nodes found.
                if (availableNodes == null || !availableNodes.Any())
                {
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog($"No available {nodeTitle.ToLower()}s could be found in the selected databases.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Get the available edges.
                var availableEdges = context.Edges
                                     .Where(item => item.DatabaseEdges.Any(item1 => edgeDatabaseIds.Contains(item1.Database.Id)))
                                     .Where(item => item.EdgeNodes.All(item1 => availableNodes.Contains(item1.Node)));
                // Check if there haven't been any available edges found.
                if (availableEdges == null || !availableEdges.Any())
                {
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog($"No available {edgeTitle.ToLower()}s could be found in the selected databases.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
                // Get the seed nodes.
                var seedNodesByIdentifier = availableNodes
                                            .Where(item => seedNodeIdentifiers.Contains(item.Id) || item.DatabaseNodeFieldNodes.Any(item1 => item1.DatabaseNodeField.IsSearchable && seedNodeIdentifiers.Contains(item1.Value)));
                var seedNodesByNodeCollection = availableNodes
                                                .Where(item => item.NodeCollectionNodes.Any(item1 => seedNodeCollectionIds.Contains(item1.NodeCollection.Id)));
                seedNodeIds = seedNodesByIdentifier
                              .Concat(seedNodesByNodeCollection)
                              .Distinct()
                              .Select(item => item.Id)
                              .ToList();
                // Check if there haven't been any seed nodes found.
                if (seedNodeIds == null || !seedNodeIds.Any())
                {
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog($"No seed {nodeTitle.ToLower()}s could be found with the provided seed data.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);

                    // End the function.
                    return;
                }
            }
            // Define the list to store the edges.
            var currentEdgeList = new List <EdgeItemModel>();

            // Use a new scope.
            using (var scope = serviceProvider.CreateScope())
            {
                // Use a new context instance.
                using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                // Get the available nodes.
                var availableNodes = context.Nodes
                                     .Where(item => item.DatabaseNodes.Any(item1 => nodeDatabaseIds.Contains(item1.Database.Id)));
                // Define the edges of the network.
                currentEdgeList = context.Edges
                                  .Where(item => item.DatabaseEdges.Any(item1 => edgeDatabaseIds.Contains(item1.Database.Id)))
                                  .Where(item => item.EdgeNodes.All(item1 => availableNodes.Contains(item1.Node)))
                                  .Where(item => item.EdgeNodes.Any(item1 => seedNodeIds.Contains(item1.Node.Id)))
                                  .Select(item => new EdgeItemModel
                {
                    EdgeId       = item.Id,
                    SourceNodeId = item.EdgeNodes
                                   .Where(item => item.Type == EdgeNodeType.Source)
                                   .Select(item => item.Node.Id)
                                   .FirstOrDefault(),
                    TargetNodeId = item.EdgeNodes
                                   .Where(item => item.Type == EdgeNodeType.Target)
                                   .Select(item => item.Node.Id)
                                   .FirstOrDefault()
                })
                                  .Where(item => !string.IsNullOrEmpty(item.EdgeId) && !string.IsNullOrEmpty(item.SourceNodeId) && !string.IsNullOrEmpty(item.TargetNodeId))
                                  .ToList();
            }
            // Check if there haven't been any edges found.
            if (currentEdgeList == null || !currentEdgeList.Any())
            {
                // Use a new scope.
                using (var scope = serviceProvider.CreateScope())
                {
                    // Use a new context instance.
                    using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                    // Reload the network.
                    var network = context.Networks
                                  .FirstOrDefault(item => item.Id == networkId);
                    // Check if there was no item found.
                    if (network == null)
                    {
                        // Return.
                        return;
                    }
                    // Update the status of the item.
                    network.Status = NetworkStatus.Error;
                    // Add a message to the log.
                    network.Log = network.AppendToLog($"No {edgeTitle.ToLower()}s could be found with the provided data using the provided algorithm.");
                    // Edit the network.
                    await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);
                }
                // End the function.
                return;
            }
            // Define the edges of the network.
            var edgeIds = currentEdgeList
                          .Select(item => item.EdgeId)
                          .Distinct()
                          .ToList();
            // Get all of the nodes used by the found edges.
            var nodeIds = currentEdgeList
                          .Select(item => item.SourceNodeId)
                          .Concat(currentEdgeList
                                  .Select(item => item.TargetNodeId))
                          .Distinct()
                          .ToList();

            // Update the seed node IDs.
            seedNodeIds = seedNodeIds
                          .Intersect(nodeIds)
                          .ToList();
            // Define the related entities.
            var networkNodes = nodeIds
                               .Select(item => new NetworkNode
            {
                NodeId = item,
                Type   = NetworkNodeType.None
            })
                               .Concat(seedNodeIds
                                       .Select(item => new NetworkNode
            {
                NodeId = item,
                Type   = NetworkNodeType.Seed
            }))
                               .ToList();
            var networkEdges = edgeIds
                               .Select(item => new NetworkEdge
            {
                EdgeId = item
            })
                               .ToList();

            // Use a new scope.
            using (var scope = serviceProvider.CreateScope())
            {
                // Use a new context instance.
                using var context = scope.ServiceProvider.GetRequiredService <ApplicationDbContext>();
                // Reload the network.
                var network = context.Networks
                              .FirstOrDefault(item => item.Id == networkId);
                // Check if there was no item found.
                if (network == null)
                {
                    // Return.
                    return;
                }
                // Define the related entities.
                network.NetworkNodes = networkNodes;
                network.NetworkEdges = networkEdges;
                // Edit the network.
                await IEnumerableExtensions.EditAsync(network.Yield(), serviceProvider, token);
            }
        }