state after adding all of the user stuff and messing around with the wierd brave bug
This commit is contained in:
80
OpenArchival.DataAccess/Providers/ArchiveCategoryProvider.cs
Normal file
80
OpenArchival.DataAccess/Providers/ArchiveCategoryProvider.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public class ArchiveCategoryProvider : IArchiveCategoryProvider
|
||||
{
|
||||
private Microsoft.EntityFrameworkCore.IDbContextFactory<ApplicationDbContext> _dbFactory;
|
||||
private ILogger _logger;
|
||||
|
||||
[SetsRequiredMembers]
|
||||
public ArchiveCategoryProvider(Microsoft.EntityFrameworkCore.IDbContextFactory<ApplicationDbContext> dbFactory, ILogger<ArchiveCategoryProvider> logger)
|
||||
{
|
||||
_dbFactory = dbFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task CreateCategoryAsync(ArchiveCategory category)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArchiveCategories.Add(category);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateCategoryAsync(ArchiveCategory category)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArchiveCategories.Update(category);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteCategoryAsync(ArchiveCategory category)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArchiveCategories.Remove(category);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArchiveCategory>?> GetArchiveCategory(string categoryName)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArchiveCategories.Where(a => a.Name == categoryName).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ArchiveCategory?> GetArchiveCategory(int id)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArchiveCategories.Where(a => a.Id == id).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArchiveCategory>?> GetAllArchiveCategories()
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArchiveCategories.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArchiveCategory>?> Search(string query)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArchiveCategories
|
||||
.Where(p => p.Name.ToLower().Contains(query.ToLower())).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArchiveCategory>?> Top(int count)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArchiveCategories
|
||||
.OrderBy(p => p.Name)
|
||||
.Take(count)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
73
OpenArchival.DataAccess/Providers/ArchiveEntryTagProvider.cs
Normal file
73
OpenArchival.DataAccess/Providers/ArchiveEntryTagProvider.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public class ArchiveEntryTagProvider : IArchiveEntryTagProvider
|
||||
{
|
||||
private readonly IDbContextFactory<ApplicationDbContext> _dbFactory;
|
||||
private readonly ILogger<ArchiveEntryTagProvider> _logger;
|
||||
|
||||
[SetsRequiredMembers]
|
||||
public ArchiveEntryTagProvider(IDbContextFactory<ApplicationDbContext> context, ILogger<ArchiveEntryTagProvider> logger)
|
||||
{
|
||||
_dbFactory = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<ArtifactEntryTag?> GetEntryTagAsync(int id)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArtifactEntryTags.Where(t => t.Id == id).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactEntryTag>?> GetEntryTagAsync(string name)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArtifactEntryTags.Where(t => t.Name == name).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateEntryTagAsync(ArtifactEntryTag entryTag)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArtifactEntryTags.Update(entryTag);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task CreateEntryTagAsync(ArtifactEntryTag entryTag)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArtifactEntryTags.Add(entryTag);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteEntryTagAsync(ArtifactEntryTag entryTag)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArtifactEntryTags.Remove(entryTag);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactEntryTag>?> Search(string query)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArtifactEntryTags
|
||||
.Where(p => p.Name.ToLower().Contains(query.ToLower())).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactEntryTag>?> Top(int count)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArtifactEntryTags
|
||||
.OrderBy(p => p.Name)
|
||||
.Take(count)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
72
OpenArchival.DataAccess/Providers/ArtifactDefectProvider.cs
Normal file
72
OpenArchival.DataAccess/Providers/ArtifactDefectProvider.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public class ArtifactDefectProvider : IArtifactDefectProvider
|
||||
{
|
||||
private readonly IDbContextFactory<ApplicationDbContext> _dbFactory;
|
||||
private readonly ILogger<ArtifactDefectProvider> _logger;
|
||||
|
||||
[SetsRequiredMembers]
|
||||
public ArtifactDefectProvider(IDbContextFactory<ApplicationDbContext> context, ILogger<ArtifactDefectProvider> logger)
|
||||
{
|
||||
_dbFactory = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<ArtifactDefect?> GetDefectAsync(int id)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
return await context.ArtifactDefects.Where(d => d.Id == id).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactDefect>?> GetDefectAsync(string description)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
return await context.ArtifactDefects.Where(d => d.Description == description).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateDefectAsync(ArtifactDefect artifactDefect)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
context.ArtifactDefects.Update(artifactDefect);
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task CreateDefectAsync(ArtifactDefect artifactDefect)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArtifactDefects.Add(artifactDefect);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteDefectAsync(ArtifactDefect artifactDefect)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArtifactDefects.Remove(artifactDefect);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactDefect>?> Search(string query)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArtifactDefects
|
||||
.Where(p => p.Description.ToLower().Contains(query.ToLower())).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactDefect>?> Top(int count)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArtifactDefects
|
||||
.OrderBy(p => p.Description)
|
||||
.Take(count)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
525
OpenArchival.DataAccess/Providers/ArtifactGroupingProvider.cs
Normal file
525
OpenArchival.DataAccess/Providers/ArtifactGroupingProvider.cs
Normal file
@@ -0,0 +1,525 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public class ArtifactGroupingProvider : IArtifactGroupingProvider
|
||||
{
|
||||
private readonly IDbContextFactory<ApplicationDbContext> _context;
|
||||
private readonly ILogger<ArtifactGroupingProvider> _logger;
|
||||
|
||||
[SetsRequiredMembers]
|
||||
public ArtifactGroupingProvider(IDbContextFactory<ApplicationDbContext> context, ILogger<ArtifactGroupingProvider> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<ArtifactGrouping?> GetGroupingAsync(int id)
|
||||
{
|
||||
await using var context = await _context.CreateDbContextAsync();
|
||||
return await context.ArtifactGroupings
|
||||
.Include(g => g.Category)
|
||||
.Include(g => g.IdentifierFields)
|
||||
.Include(g => g.Type)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.StorageLocation)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.Type)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.Tags)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.ListedNames)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.Defects)
|
||||
.Include(g => g.ViewCount) // Added
|
||||
.Include(g => g.IdentifierFields)
|
||||
.Where(g => g.Id == id)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<ArtifactGrouping?> GetGroupingAsync(string artifactGroupingIdentifier)
|
||||
{
|
||||
await using var context = await _context.CreateDbContextAsync();
|
||||
return await context.ArtifactGroupings
|
||||
.Include(g => g.Category)
|
||||
.Include(g => g.IdentifierFields)
|
||||
.Include(g => g.Type)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.StorageLocation)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.Type)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.Tags)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.ListedNames)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.Defects)
|
||||
.Include(g => g.ViewCount) // Added
|
||||
.Where(g => g.ArtifactGroupingIdentifier == artifactGroupingIdentifier)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task CreateGroupingAsync(ArtifactGrouping grouping)
|
||||
{
|
||||
await using var context = await _context.CreateDbContextAsync();
|
||||
|
||||
// Attach the Category to the context. If it has a key, it will be tracked.
|
||||
context.Attach(grouping.Category);
|
||||
|
||||
// --- Local caches for de-duplication within this transaction ---
|
||||
var processedTypes = new Dictionary<string, ArtifactType>();
|
||||
var processedLocations = new Dictionary<string, ArtifactStorageLocation>();
|
||||
var processedTags = new Dictionary<string, ArtifactEntryTag>();
|
||||
var processedNames = new Dictionary<string, ListedName>();
|
||||
var processedDefects = new Dictionary<string, ArtifactDefect>();
|
||||
// --- End local caches ---
|
||||
|
||||
// --- Helper functions to get unique entities (from cache or DB) ---
|
||||
async Task<ArtifactType> GetUniqueTypeAsync(ArtifactType typeToProcess)
|
||||
{
|
||||
if (string.IsNullOrEmpty(typeToProcess?.Name)) return typeToProcess;
|
||||
if (processedTypes.TryGetValue(typeToProcess.Name, out var uniqueType))
|
||||
{
|
||||
return uniqueType;
|
||||
}
|
||||
var dbType = await context.ArtifactTypes.FirstOrDefaultAsync(t => t.Name == typeToProcess.Name);
|
||||
if (dbType != null)
|
||||
{
|
||||
processedTypes[dbType.Name] = dbType;
|
||||
return dbType;
|
||||
}
|
||||
processedTypes[typeToProcess.Name] = typeToProcess;
|
||||
return typeToProcess;
|
||||
}
|
||||
|
||||
async Task<ArtifactStorageLocation> GetUniqueLocationAsync(ArtifactStorageLocation locationToProcess)
|
||||
{
|
||||
if (string.IsNullOrEmpty(locationToProcess?.Location)) return locationToProcess;
|
||||
if (processedLocations.TryGetValue(locationToProcess.Location, out var uniqueLocation))
|
||||
{
|
||||
return uniqueLocation;
|
||||
}
|
||||
var dbLocation = await context.ArtifactStorageLocations.FirstOrDefaultAsync(l => l.Location == locationToProcess.Location);
|
||||
if (dbLocation != null)
|
||||
{
|
||||
processedLocations[dbLocation.Location] = dbLocation;
|
||||
return dbLocation;
|
||||
}
|
||||
processedLocations[locationToProcess.Location] = locationToProcess;
|
||||
return locationToProcess;
|
||||
}
|
||||
|
||||
async Task<ArtifactEntryTag> GetUniqueTagAsync(ArtifactEntryTag tagToProcess)
|
||||
{
|
||||
if (string.IsNullOrEmpty(tagToProcess?.Name)) return tagToProcess;
|
||||
if (processedTags.TryGetValue(tagToProcess.Name, out var uniqueTag))
|
||||
{
|
||||
return uniqueTag;
|
||||
}
|
||||
var dbTag = await context.ArtifactEntryTags.FirstOrDefaultAsync(t => t.Name == tagToProcess.Name);
|
||||
if (dbTag != null)
|
||||
{
|
||||
processedTags[dbTag.Name] = dbTag;
|
||||
return dbTag;
|
||||
}
|
||||
processedTags[tagToProcess.Name] = tagToProcess;
|
||||
return tagToProcess;
|
||||
}
|
||||
|
||||
async Task<ListedName> GetUniqueNameAsync(ListedName nameToProcess)
|
||||
{
|
||||
if (string.IsNullOrEmpty(nameToProcess?.Value)) return nameToProcess;
|
||||
if (processedNames.TryGetValue(nameToProcess.Value, out var uniqueName))
|
||||
{
|
||||
return uniqueName;
|
||||
}
|
||||
var dbName = await context.ArtifactAssociatedNames.FirstOrDefaultAsync(n => n.Value == nameToProcess.Value);
|
||||
if (dbName != null)
|
||||
{
|
||||
processedNames[dbName.Value] = dbName;
|
||||
return dbName;
|
||||
}
|
||||
processedNames[nameToProcess.Value] = nameToProcess;
|
||||
return nameToProcess;
|
||||
}
|
||||
|
||||
async Task<ArtifactDefect> GetUniqueDefectAsync(ArtifactDefect defectToProcess)
|
||||
{
|
||||
if (string.IsNullOrEmpty(defectToProcess?.Description)) return defectToProcess;
|
||||
if (processedDefects.TryGetValue(defectToProcess.Description, out var uniqueDefect))
|
||||
{
|
||||
return uniqueDefect;
|
||||
}
|
||||
var dbDefect = await context.ArtifactDefects.FirstOrDefaultAsync(d => d.Description == defectToProcess.Description);
|
||||
if (dbDefect != null)
|
||||
{
|
||||
processedDefects[dbDefect.Description] = dbDefect;
|
||||
return dbDefect;
|
||||
}
|
||||
processedDefects[defectToProcess.Description] = defectToProcess;
|
||||
return defectToProcess;
|
||||
}
|
||||
// --- End helper functions ---
|
||||
|
||||
// De-duplicate the main grouping's type
|
||||
grouping.Type = await GetUniqueTypeAsync(grouping.Type);
|
||||
|
||||
// Iterate through all child entries to handle their related entities.
|
||||
foreach (var entry in grouping.ChildArtifactEntries)
|
||||
{
|
||||
// Handle Artifact Types
|
||||
entry.Type = await GetUniqueTypeAsync(entry.Type);
|
||||
|
||||
// Handle Storage Location
|
||||
entry.StorageLocation = await GetUniqueLocationAsync(entry.StorageLocation);
|
||||
|
||||
// Handle Tags
|
||||
var managedTags = new List<ArtifactEntryTag>();
|
||||
foreach (var tag in entry.Tags)
|
||||
{
|
||||
managedTags.Add(await GetUniqueTagAsync(tag));
|
||||
}
|
||||
entry.Tags = managedTags;
|
||||
|
||||
// Handle Listed Names
|
||||
var managedNames = new List<ListedName>();
|
||||
foreach (var name in entry.ListedNames)
|
||||
{
|
||||
managedNames.Add(await GetUniqueNameAsync(name));
|
||||
}
|
||||
entry.ListedNames = managedNames;
|
||||
|
||||
// Handle Defects
|
||||
var managedDefects = new List<ArtifactDefect>();
|
||||
foreach (var defect in entry.Defects)
|
||||
{
|
||||
managedDefects.Add(await GetUniqueDefectAsync(defect));
|
||||
}
|
||||
entry.Defects = managedDefects;
|
||||
}
|
||||
|
||||
// Concatinate all of the text to be searchable by postgres
|
||||
grouping.GenerateSearchIndex();
|
||||
|
||||
// Add the new grouping and save changes.
|
||||
context.ChangeTracker.TrackGraph(grouping, node =>
|
||||
{
|
||||
// If the entity's key is set, EF should treat it as an existing, unchanged entity.
|
||||
if (node.Entry.IsKeySet)
|
||||
{
|
||||
node.Entry.State = EntityState.Unchanged;
|
||||
}
|
||||
// Otherwise, it's a new entity that needs to be inserted.
|
||||
else
|
||||
{
|
||||
node.Entry.State = EntityState.Added;
|
||||
}
|
||||
});
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateGroupingAsync(ArtifactGrouping updatedGrouping)
|
||||
{
|
||||
await using var context = await _context.CreateDbContextAsync();
|
||||
|
||||
// 1. Retrieve the existing grouping object from the database, eagerly loading all related data.
|
||||
var existingGrouping = await context.ArtifactGroupings
|
||||
.Include(g => g.Category)
|
||||
.Include(g => g.IdentifierFields)
|
||||
.Include(g => g.Type)
|
||||
.Include(g => g.ViewCount) // Load ViewCount
|
||||
//.Include(g => g.BlogPosts) // BlogPosts not handled yet
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.StorageLocation)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.Type)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.Tags)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.ListedNames)
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.ThenInclude(e => e.Defects)
|
||||
.Where(g => g.Id == updatedGrouping.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (existingGrouping == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Manually copy over primitive properties.
|
||||
existingGrouping.Title = updatedGrouping.Title;
|
||||
existingGrouping.Description = updatedGrouping.Description;
|
||||
existingGrouping.IsPublicallyVisible = updatedGrouping.IsPublicallyVisible;
|
||||
existingGrouping.IdentifierFields = updatedGrouping.IdentifierFields;
|
||||
|
||||
// Handle one-to-many relationships (Type, Category).
|
||||
var existingGroupingType = await context.ArtifactTypes.FirstOrDefaultAsync(t => t.Name == updatedGrouping.Type.Name);
|
||||
if (existingGroupingType != null)
|
||||
{
|
||||
existingGrouping.Type = existingGroupingType;
|
||||
}
|
||||
else
|
||||
{
|
||||
existingGrouping.Type = updatedGrouping.Type;
|
||||
}
|
||||
|
||||
if (existingGrouping.Category.Name != updatedGrouping.Category.Name)
|
||||
{
|
||||
existingGrouping.Category = updatedGrouping.Category;
|
||||
context.Add(existingGrouping.Category);
|
||||
}
|
||||
|
||||
// Handle ViewCount (Added)
|
||||
if (updatedGrouping.ViewCount != null)
|
||||
{
|
||||
if (existingGrouping.ViewCount == null)
|
||||
{
|
||||
// Create a new ViewCount
|
||||
existingGrouping.ViewCount = new ArtifactGroupingViewCount
|
||||
{
|
||||
Grouping = existingGrouping,
|
||||
Views = updatedGrouping.ViewCount.Views
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update existing ViewCount
|
||||
existingGrouping.ViewCount.Views = updatedGrouping.ViewCount.Views;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Handle BlogPosts update (requires model definition & de-duplication)
|
||||
// await DeDuplicateGroupingRelationsAsync(context, updatedGrouping);
|
||||
// existingGrouping.BlogPosts.Clear();
|
||||
// updatedGrouping.BlogPosts.ForEach(post => existingGrouping.BlogPosts.Add(post));
|
||||
|
||||
// 3. Synchronize the ChildArtifactEntries collection.
|
||||
var updatedEntryIds = updatedGrouping.ChildArtifactEntries.Select(e => e.Id).ToList();
|
||||
var entriesToRemove = existingGrouping.ChildArtifactEntries
|
||||
.Where(e => !updatedEntryIds.Contains(e.Id))
|
||||
.ToList();
|
||||
|
||||
foreach (var entryToRemove in entriesToRemove)
|
||||
{
|
||||
existingGrouping.ChildArtifactEntries.Remove(entryToRemove);
|
||||
}
|
||||
|
||||
foreach (var updatedEntry in updatedGrouping.ChildArtifactEntries)
|
||||
{
|
||||
// FIRST, de-duplicate all related entities on the incoming entry.
|
||||
await DeDuplicateEntryRelationsAsync(context, updatedEntry);
|
||||
|
||||
var existingEntry = existingGrouping.ChildArtifactEntries
|
||||
.FirstOrDefault(e => e.Id == updatedEntry.Id);
|
||||
|
||||
if (existingEntry != null)
|
||||
{
|
||||
// The entry exists, so manually update its properties.
|
||||
existingEntry.Title = updatedEntry.Title;
|
||||
existingEntry.Description = updatedEntry.Description;
|
||||
existingEntry.ArtifactNumber = updatedEntry.ArtifactNumber;
|
||||
existingEntry.IsPubliclyVisible = updatedEntry.IsPubliclyVisible;
|
||||
existingEntry.AssociatedDates = updatedEntry.AssociatedDates;
|
||||
existingEntry.FileTextContent = updatedEntry.FileTextContent;
|
||||
existingEntry.Quantity = updatedEntry.Quantity;
|
||||
existingEntry.Links = updatedEntry.Links;
|
||||
|
||||
// The relations on updatedEntry are already de-duplicated, so just assign them.
|
||||
existingEntry.StorageLocation = updatedEntry.StorageLocation;
|
||||
existingEntry.Type = updatedEntry.Type;
|
||||
|
||||
// For collections, clear the old ones and add the new de-duplicated ones.
|
||||
existingEntry.Tags.Clear();
|
||||
updatedEntry.Tags.ForEach(tag => existingEntry.Tags.Add(tag));
|
||||
|
||||
existingEntry.ListedNames.Clear();
|
||||
updatedEntry.ListedNames.ForEach(name => existingEntry.ListedNames.Add(name));
|
||||
|
||||
existingEntry.Defects.Clear();
|
||||
updatedEntry.Defects.ForEach(defect => existingEntry.Defects.Add(defect));
|
||||
}
|
||||
else
|
||||
{
|
||||
// The entry is new and its children are already de-duplicated, so just add it.
|
||||
existingGrouping.ChildArtifactEntries.Add(updatedEntry);
|
||||
}
|
||||
}
|
||||
|
||||
existingGrouping.GenerateSearchIndex();
|
||||
|
||||
// 4. Save all changes.
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task DeDuplicateEntryRelationsAsync(ApplicationDbContext context, ArtifactEntry entry)
|
||||
{
|
||||
// --- Handle One-to-Many Relationships ---
|
||||
var existingLocation = await context.ArtifactStorageLocations.FirstOrDefaultAsync(l => l.Location == entry.StorageLocation.Location);
|
||||
if (existingLocation != null)
|
||||
{
|
||||
entry.StorageLocation = existingLocation;
|
||||
}
|
||||
|
||||
var existingType = await context.ArtifactTypes.FirstOrDefaultAsync(t => t.Name == entry.Type.Name);
|
||||
if (existingType != null)
|
||||
{
|
||||
entry.Type = existingType;
|
||||
}
|
||||
|
||||
// --- Handle Many-to-Many Relationships ---
|
||||
|
||||
// De-duplicate Tags
|
||||
var processedTags = new List<ArtifactEntryTag>();
|
||||
foreach (var tag in entry.Tags)
|
||||
{
|
||||
var existingTag = await context.ArtifactEntryTags.FirstOrDefaultAsync(t => t.Name == tag.Name) ?? tag;
|
||||
processedTags.Add(existingTag);
|
||||
}
|
||||
entry.Tags = processedTags;
|
||||
|
||||
// De-duplicate ListedNames
|
||||
var processedNames = new List<ListedName>();
|
||||
if (entry.ListedNames != null)
|
||||
{
|
||||
foreach (var name in entry.ListedNames)
|
||||
{
|
||||
var existingName = await context.ArtifactAssociatedNames.FirstOrDefaultAsync(n => n.Value == name.Value) ?? name;
|
||||
processedNames.Add(existingName);
|
||||
}
|
||||
entry.ListedNames = processedNames;
|
||||
}
|
||||
|
||||
// De-duplicate Defects
|
||||
var processedDefects = new List<ArtifactDefect>();
|
||||
if (entry.Defects != null)
|
||||
{
|
||||
foreach (var defect in entry.Defects)
|
||||
{
|
||||
var existingDefect = await context.ArtifactDefects.FirstOrDefaultAsync(d => d.Description == defect.Description) ?? defect;
|
||||
processedDefects.Add(existingDefect);
|
||||
}
|
||||
entry.Defects = processedDefects;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A helper method to synchronize many-to-many collections.
|
||||
/// </summary>
|
||||
private async Task SyncCollectionAsync<TEntity, TKey>(
|
||||
DbContext context,
|
||||
ICollection<TEntity> existingItems,
|
||||
ICollection<TEntity> updatedItems,
|
||||
Func<TEntity, TKey> keySelector) where TEntity : class
|
||||
{
|
||||
var existingKeys = existingItems.Select(keySelector).ToHashSet();
|
||||
var updatedKeys = updatedItems.Select(keySelector).ToHashSet();
|
||||
|
||||
// 1. Remove items that are no longer in the updated collection
|
||||
var keysToRemove = existingKeys.Except(updatedKeys);
|
||||
var itemsToRemove = existingItems.Where(item => keysToRemove.Contains(keySelector(item))).ToList();
|
||||
foreach (var item in itemsToRemove)
|
||||
{
|
||||
existingItems.Remove(item);
|
||||
}
|
||||
|
||||
// 2. Identify keys for brand new items
|
||||
var keysToAdd = updatedKeys.Except(existingKeys).ToList();
|
||||
if (!keysToAdd.Any())
|
||||
{
|
||||
return; // Nothing to add
|
||||
}
|
||||
|
||||
// 3. Batch-fetch all entities from the DB that match the new keys.
|
||||
Dictionary<TKey, TEntity> existingDbItemsMap = [];
|
||||
if (typeof(TEntity) == typeof(ArtifactEntryTag))
|
||||
{
|
||||
var tagKeys = keysToAdd.Cast<string>().ToList();
|
||||
var tags = await context.Set<ArtifactEntryTag>()
|
||||
.Where(t => tagKeys.Contains(t.Name))
|
||||
.ToListAsync();
|
||||
existingDbItemsMap = tags.ToDictionary(t => (TKey)(object)t.Name) as Dictionary<TKey, TEntity>;
|
||||
}
|
||||
else if (typeof(TEntity) == typeof(ListedName))
|
||||
{
|
||||
var nameKeys = keysToAdd.Cast<string>().ToList();
|
||||
var names = await context.Set<ListedName>()
|
||||
.Where(n => nameKeys.Contains(n.Value))
|
||||
.ToListAsync();
|
||||
existingDbItemsMap = names.ToDictionary(n => (TKey)(object)n.Value) as Dictionary<TKey, TEntity>;
|
||||
}
|
||||
else if (typeof(TEntity) == typeof(ArtifactDefect))
|
||||
{
|
||||
var defectKeys = keysToAdd.Cast<string>().ToList();
|
||||
var defects = await context.Set<ArtifactDefect>()
|
||||
.Where(d => defectKeys.Contains(d.Description))
|
||||
.ToListAsync();
|
||||
existingDbItemsMap = defects.ToDictionary(d => (TKey)(object)d.Description) as Dictionary<TKey, TEntity>;
|
||||
}
|
||||
// TODO: Add support for other entity types like BlogPost or ArtifactEntry if needed
|
||||
|
||||
|
||||
// 4. Add the items, using the tracked entity from the DB if it exists.
|
||||
foreach (var updatedItem in updatedItems.Where(i => keysToAdd.Contains(keySelector(i))))
|
||||
{
|
||||
var key = keySelector(updatedItem);
|
||||
if (existingDbItemsMap.TryGetValue(key, out var dbItem))
|
||||
{
|
||||
// The item already exists in the DB, so add the tracked version.
|
||||
existingItems.Add(dbItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a brand new item, so add the untracked one from the input.
|
||||
existingItems.Add(updatedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteGroupingAsync(int id)
|
||||
{
|
||||
await using var context = await _context.CreateDbContextAsync();
|
||||
await context.ArtifactGroupings
|
||||
.Where(p => p.Id == id)
|
||||
.ExecuteDeleteAsync();
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteGroupingAsync(ArtifactGrouping grouping)
|
||||
{
|
||||
await using var context = await _context.CreateDbContextAsync();
|
||||
context.ArtifactGroupings.Remove(grouping);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactGrouping>> GetGroupingsPaged(int pageNumber, int resultsCount)
|
||||
{
|
||||
await using var context = await _context.CreateDbContextAsync();
|
||||
if (pageNumber < 1 || resultsCount < 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException($"Either page number or number of results was less than or equal to 0. {nameof(pageNumber)}={pageNumber} {nameof(resultsCount)}={resultsCount}");
|
||||
}
|
||||
|
||||
var totalCount = await context.ArtifactGroupings.CountAsync();
|
||||
|
||||
var items = await context.ArtifactGroupings
|
||||
.Include(g => g.ChildArtifactEntries)
|
||||
.Include(g => g.Category)
|
||||
.OrderBy(g => g.Id)
|
||||
.Skip((pageNumber - 1) * resultsCount)
|
||||
.Take(resultsCount)
|
||||
.ToListAsync();
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
public async Task<int> GetTotalCount()
|
||||
{
|
||||
await using var context = await _context.CreateDbContextAsync();
|
||||
return context.ArtifactGroupings.Count();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public class ArtifactStorageLocationProvider : IArtifactStorageLocationProvider
|
||||
{
|
||||
private readonly IDbContextFactory<ApplicationDbContext> _dbFactory;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
[SetsRequiredMembers]
|
||||
public ArtifactStorageLocationProvider(IDbContextFactory<ApplicationDbContext> dbFactory, ILogger<ArtifactStorageLocationProvider> logger)
|
||||
{
|
||||
_dbFactory = dbFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task CreateArtifactStorageLocationAsync(ArtifactStorageLocation location)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArtifactStorageLocations.Add(location);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateArtifactStorageLocationAsync(ArtifactStorageLocation location)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArtifactStorageLocations.Update(location);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteArtifactStorageLocationAsync(ArtifactStorageLocation location)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArtifactStorageLocations.Remove(location);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactStorageLocation>?> GetArtifactStorageLocation(string locationName)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArtifactStorageLocations.Where(a => a.Location == locationName).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ArtifactStorageLocation?> GetArtifactStorageLocation(int id)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArtifactStorageLocations.Where(a => a.Id == id).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactStorageLocation>?> GetAllArtifactStorageLocations()
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArtifactStorageLocations.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactStorageLocation>?> Search(string query)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
// STEP 1: Get the unique location STRINGS that match the search query.
|
||||
// This simple query is guaranteed to be translated correctly by EF Core.
|
||||
var uniqueMatchingNames = await context.ArtifactStorageLocations
|
||||
.Where(p => p.Location.ToLower().Contains(query.ToLower()))
|
||||
.Select(p => p.Location)
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
|
||||
// If no names matched, return an empty list immediately.
|
||||
if (uniqueMatchingNames is null || !uniqueMatchingNames.Any())
|
||||
{
|
||||
return new List<ArtifactStorageLocation>();
|
||||
}
|
||||
|
||||
// STEP 2: Now, fetch the full objects that correspond to the unique names.
|
||||
var matchingLocations = await context.ArtifactStorageLocations
|
||||
.Where(p => uniqueMatchingNames.Contains(p.Location))
|
||||
.ToListAsync();
|
||||
|
||||
// STEP 3: Perform a final DistinctBy on the small in-memory list to ensure
|
||||
// a clean result set with one object per location name.
|
||||
var finalResults = matchingLocations
|
||||
.DistinctBy(p => p.Location)
|
||||
.OrderBy(p => p.Location) // Optional: Orders the final search results
|
||||
.ToList();
|
||||
|
||||
return finalResults;
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactStorageLocation>?> Top(int count)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
// STEP 1: Get a unique, ordered list of the TOP N location *strings*.
|
||||
// This is a simple query that EF Core can always translate correctly.
|
||||
var uniqueLocationNames = await context.ArtifactStorageLocations
|
||||
.Select(p => p.Location)
|
||||
.Distinct()
|
||||
.OrderBy(locationName => locationName)
|
||||
.Take(count)
|
||||
.ToListAsync();
|
||||
|
||||
if (uniqueLocationNames is null || !uniqueLocationNames.Any())
|
||||
{
|
||||
return new List<ArtifactStorageLocation>();
|
||||
}
|
||||
|
||||
// STEP 2: Fetch all the full ArtifactStorageLocation objects that match the unique names.
|
||||
// We use the list from Step 1 to create a 'WHERE IN (...)' clause.
|
||||
var matchingLocations = await context.ArtifactStorageLocations
|
||||
.Where(p => uniqueLocationNames.Contains(p.Location))
|
||||
.ToListAsync();
|
||||
|
||||
// STEP 3: The previous query might fetch duplicates (e.g., two entries for "Box A").
|
||||
// We now perform the final DistinctBy in-memory, which is guaranteed to work.
|
||||
var finalResults = matchingLocations
|
||||
.DistinctBy(p => p.Location)
|
||||
.OrderBy(p => p.Location) // Re-apply ordering to the final list
|
||||
.ToList();
|
||||
|
||||
return finalResults;
|
||||
}
|
||||
}
|
||||
74
OpenArchival.DataAccess/Providers/ArtifactTypeProvider.cs
Normal file
74
OpenArchival.DataAccess/Providers/ArtifactTypeProvider.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public class ArtifactTypeProvider : IArtifactTypeProvider
|
||||
{
|
||||
private readonly IDbContextFactory<ApplicationDbContext> _dbFactory;
|
||||
private readonly ILogger<ArtifactTypeProvider> _logger;
|
||||
|
||||
[SetsRequiredMembers]
|
||||
public ArtifactTypeProvider(IDbContextFactory<ApplicationDbContext> dbFactory, ILogger<ArtifactTypeProvider> logger)
|
||||
{
|
||||
_dbFactory = dbFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task CreateArtifactTypeAsync(ArtifactType artifactType)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
context.ArtifactTypes.Add(artifactType);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateArtifactTypeAsync(ArtifactType artifactType)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
context.ArtifactTypes.Update(artifactType);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteArtifactTypeAsync(ArtifactType artifactType)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
context.ArtifactTypes.Remove(artifactType);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactType>?> GetArtifactType(string name)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
return await context.ArtifactTypes.Where(a => a.Name == name).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ArtifactType?> GetArtifactType(int id)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
return await context.ArtifactTypes.FirstOrDefaultAsync(a => a.Id == id);
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactType>?> GetAllArtifactTypes()
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
return await context.ArtifactTypes.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactType>?> Search(string query)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
return await context.ArtifactTypes
|
||||
.Where(p => p.Name.ToLower().Contains(query.ToLower()))
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ArtifactType>?> Top(int count)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
return await context.ArtifactTypes
|
||||
.OrderBy(p => p.Name)
|
||||
.Take(count)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
61
OpenArchival.DataAccess/Providers/FilePathListingProvider.cs
Normal file
61
OpenArchival.DataAccess/Providers/FilePathListingProvider.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public class FilePathListingProvider : IFilePathListingProvider
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly ILogger<FilePathListingProvider> _logger;
|
||||
|
||||
[SetsRequiredMembers]
|
||||
public FilePathListingProvider(ApplicationDbContext context, ILogger<FilePathListingProvider> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<FilePathListing?> GetFilePathListingAsync(int id)
|
||||
{
|
||||
return await _context.ArtifactFilePaths.Where(f => f.Id == id).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<FilePathListing?> GetFilePathListingByPathAsync(string path)
|
||||
{
|
||||
return await _context.ArtifactFilePaths.Where(f => f.Path == path).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task CreateFilePathListingAsync(FilePathListing filePathListing)
|
||||
{
|
||||
_context.ArtifactFilePaths.Add(filePathListing);
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateFilePathListingAsync(FilePathListing filePathListing)
|
||||
{
|
||||
_context.ArtifactFilePaths.Update(filePathListing);
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteFilePathListingAsync(FilePathListing filePathListing)
|
||||
{
|
||||
_context.ArtifactFilePaths.Remove(filePathListing);
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteFilePathListingAsync(string originalFileName, string diskPath)
|
||||
{
|
||||
var listingToDelete = await _context.ArtifactFilePaths
|
||||
.Where(p => p.OriginalName == originalFileName)
|
||||
.Where(p => p.Path == diskPath)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (listingToDelete == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_context.RemoveRange(listingToDelete);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public interface IArchiveCategoryProvider
|
||||
{
|
||||
public Task CreateCategoryAsync(ArchiveCategory category);
|
||||
|
||||
public Task UpdateCategoryAsync(ArchiveCategory category);
|
||||
|
||||
public Task DeleteCategoryAsync(ArchiveCategory category);
|
||||
|
||||
public Task<ArchiveCategory?> GetArchiveCategory(int id);
|
||||
|
||||
|
||||
public Task<List<ArchiveCategory>?> GetArchiveCategory(string categoryName);
|
||||
|
||||
public Task<List<ArchiveCategory>?> GetAllArchiveCategories();
|
||||
|
||||
public Task<List<ArchiveCategory>?> Search(string query);
|
||||
|
||||
public Task<List<ArchiveCategory>?> Top(int count);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public interface IArchiveEntryTagProvider
|
||||
{
|
||||
public Task<ArtifactEntryTag?> GetEntryTagAsync(int id);
|
||||
|
||||
public Task<List<ArtifactEntryTag>?> GetEntryTagAsync(string name);
|
||||
|
||||
public Task UpdateEntryTagAsync(ArtifactEntryTag entryTag);
|
||||
|
||||
public Task CreateEntryTagAsync(ArtifactEntryTag entryTag);
|
||||
|
||||
public Task DeleteEntryTagAsync(ArtifactEntryTag entryTag);
|
||||
|
||||
public Task<List<ArtifactEntryTag>?> Search(string query);
|
||||
|
||||
public Task<List<ArtifactEntryTag>?> Top(int count);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public interface IArtifactDefectProvider
|
||||
{
|
||||
public Task<ArtifactDefect?> GetDefectAsync(int id);
|
||||
public Task<List<ArtifactDefect>?> GetDefectAsync(string description);
|
||||
public Task UpdateDefectAsync(ArtifactDefect artifactDefect);
|
||||
public Task CreateDefectAsync(ArtifactDefect artifactDefect);
|
||||
public Task DeleteDefectAsync(ArtifactDefect artifactDefect);
|
||||
public Task<List<ArtifactDefect>?> Search(string query);
|
||||
public Task<List<ArtifactDefect>?> Top(int count);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public interface IArtifactGroupingProvider
|
||||
{
|
||||
Task<ArtifactGrouping?> GetGroupingAsync(int id);
|
||||
Task<ArtifactGrouping?> GetGroupingAsync(string artifactGroupingIdentifier);
|
||||
Task CreateGroupingAsync(ArtifactGrouping grouping);
|
||||
Task UpdateGroupingAsync(ArtifactGrouping grouping);
|
||||
Task DeleteGroupingAsync(int id);
|
||||
Task DeleteGroupingAsync(ArtifactGrouping grouping);
|
||||
Task<List<ArtifactGrouping>> GetGroupingsPaged(int pageNumber, int resultsCount);
|
||||
public Task<int> GetTotalCount();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public interface IArtifactStorageLocationProvider
|
||||
{
|
||||
Task CreateArtifactStorageLocationAsync(ArtifactStorageLocation location);
|
||||
Task UpdateArtifactStorageLocationAsync(ArtifactStorageLocation location);
|
||||
Task DeleteArtifactStorageLocationAsync(ArtifactStorageLocation location);
|
||||
Task<List<ArtifactStorageLocation>?> GetArtifactStorageLocation(string locationName);
|
||||
Task<ArtifactStorageLocation?> GetArtifactStorageLocation(int id);
|
||||
Task<List<ArtifactStorageLocation>?> GetAllArtifactStorageLocations();
|
||||
Task<List<ArtifactStorageLocation>?> Search(string query);
|
||||
Task<List<ArtifactStorageLocation>?> Top(int count);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public interface IArtifactTypeProvider
|
||||
{
|
||||
Task CreateArtifactTypeAsync(ArtifactType artifactType);
|
||||
Task UpdateArtifactTypeAsync(ArtifactType artifactType);
|
||||
Task DeleteArtifactTypeAsync(ArtifactType artifactType);
|
||||
Task<List<ArtifactType>?> GetArtifactType(string name);
|
||||
Task<ArtifactType?> GetArtifactType(int id);
|
||||
Task<List<ArtifactType>?> GetAllArtifactTypes();
|
||||
Task<List<ArtifactType>?> Search(string query);
|
||||
Task<List<ArtifactType>?> Top(int count);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public interface IFilePathListingProvider
|
||||
{
|
||||
Task<FilePathListing?> GetFilePathListingAsync(int id);
|
||||
Task<FilePathListing?> GetFilePathListingByPathAsync(string path);
|
||||
Task CreateFilePathListingAsync(FilePathListing filePathListing);
|
||||
Task UpdateFilePathListingAsync(FilePathListing filePathListing);
|
||||
Task DeleteFilePathListingAsync(FilePathListing filePathListing);
|
||||
public Task<bool> DeleteFilePathListingAsync(string originalFileName, string diskPath);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public interface IListedNameProvider
|
||||
{
|
||||
Task<ListedName?> GetAssociatedNameAsync(int id);
|
||||
Task<List<ListedName>?> GetAssociatedNamesAsync(string name);
|
||||
Task CreateAssociatedNameAsync(ListedName associatedName);
|
||||
Task UpdateAssociatedNameAsync(ListedName associatedName);
|
||||
Task DeleteAssociatedNameAsync(ListedName associatedName);
|
||||
public Task<List<ListedName>?> Search(string query);
|
||||
public Task<List<ListedName>?> Top(int count);
|
||||
}
|
||||
79
OpenArchival.DataAccess/Providers/ListedNameProvider.cs
Normal file
79
OpenArchival.DataAccess/Providers/ListedNameProvider.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace OpenArchival.DataAccess;
|
||||
|
||||
public class ListedNameProvider : IListedNameProvider
|
||||
{
|
||||
private readonly IDbContextFactory<ApplicationDbContext> _dbFactory;
|
||||
private readonly ILogger<ListedNameProvider> _logger;
|
||||
|
||||
[SetsRequiredMembers]
|
||||
public ListedNameProvider(IDbContextFactory<ApplicationDbContext> context, ILogger<ListedNameProvider> logger)
|
||||
{
|
||||
_dbFactory = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<ListedName?> GetAssociatedNameAsync(int id)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArtifactAssociatedNames.Where(n => n.Id == id).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ListedName>?> GetAssociatedNamesAsync(string name)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArtifactAssociatedNames
|
||||
.Where(n => n.Value == name)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task CreateAssociatedNameAsync(ListedName associatedName)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArtifactAssociatedNames.Add(associatedName);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateAssociatedNameAsync(ListedName associatedName)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArtifactAssociatedNames.Update(associatedName);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteAssociatedNameAsync(ListedName associatedName)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
context.ArtifactAssociatedNames.Remove(associatedName);
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ListedName>?> Search(string query)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
var lowerCaseQuery = query.ToLower();
|
||||
|
||||
return await context.ArtifactAssociatedNames
|
||||
.Where(p => p.Value.ToLower().Contains(lowerCaseQuery))
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ListedName>?> Top(int count)
|
||||
{
|
||||
await using var context = await _dbFactory.CreateDbContextAsync();
|
||||
|
||||
return await context.ArtifactAssociatedNames
|
||||
.OrderBy(p => p.Value)
|
||||
.Take(count)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user