diff --git a/Directory.Packages.props b/Directory.Packages.props
index 6b5521d..14a1347 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -5,13 +5,15 @@
+
-
+
-
+
+
@@ -26,8 +28,9 @@
+
-
\ No newline at end of file
+
diff --git a/app/InkForge.Desktop/App.axaml b/app/InkForge.Desktop/App.axaml
index 7042e4e..77b1e58 100644
--- a/app/InkForge.Desktop/App.axaml
+++ b/app/InkForge.Desktop/App.axaml
@@ -5,6 +5,7 @@
+
@@ -13,4 +14,4 @@
/Assets/Fonts#FluentSystemIcons-Filled
/Assets/Fonts#FluentSystemIcons-Regular
-
\ No newline at end of file
+
diff --git a/app/InkForge.Desktop/App.axaml.cs b/app/InkForge.Desktop/App.axaml.cs
index e38d88e..ed789b2 100644
--- a/app/InkForge.Desktop/App.axaml.cs
+++ b/app/InkForge.Desktop/App.axaml.cs
@@ -8,8 +8,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
-using ReactiveUI;
-
using Splat;
using Splat.Microsoft.Extensions.DependencyInjection;
@@ -47,7 +45,6 @@ public partial class App : Application
services.UseMicrosoftDependencyResolver();
Locator.CurrentMutable.InitializeSplat();
- Locator.CurrentMutable.InitializeReactiveUI();
services.AddInkForge();
}
diff --git a/app/InkForge.Desktop/AppViewLocator.cs b/app/InkForge.Desktop/AppViewLocator.cs
index 6fd1ce3..0212785 100644
--- a/app/InkForge.Desktop/AppViewLocator.cs
+++ b/app/InkForge.Desktop/AppViewLocator.cs
@@ -1,3 +1,4 @@
+using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
@@ -7,8 +8,6 @@ using InkForge.Desktop.ViewModels.Workspaces;
using InkForge.Desktop.Views.Documents;
using InkForge.Desktop.Views.Workspaces;
-using ReactiveUI;
-
namespace InkForge.Desktop;
public class AppViewLocator : IDataTemplate
@@ -19,6 +18,7 @@ public class AppViewLocator : IDataTemplate
return param switch
#pragma warning restore CS8509 // The switch expression does not handle all possible values of its input type (it is not exhaustive).
{
+ NoteEditDocumentViewModel viewModel => _(new NoteEditDocument(), viewModel),
ViewModels.Tools.WorkspaceTool viewModel => _(new Views.Tools.WorkspaceTool(), viewModel),
WelcomePageDocumentViewModel viewModel => _(new WelcomePageDocument(), viewModel),
WorkspaceViewModel viewModel => _(new WorkspaceView(), viewModel),
@@ -26,9 +26,9 @@ public class AppViewLocator : IDataTemplate
static TView _(TView view, TViewModel viewModel)
where TViewModel : class
- where TView : IViewFor
+ where TView : StyledElement
{
- view.ViewModel = viewModel;
+ view.DataContext = viewModel;
return view;
}
}
@@ -36,6 +36,7 @@ public class AppViewLocator : IDataTemplate
public bool Match(object? data)
{
return data is
+ NoteEditDocumentViewModel or
RecentItemViewModel or
ViewModels.Tools.WorkspaceTool or
WelcomePageDocumentViewModel or
diff --git a/app/InkForge.Desktop/InkForge.Desktop.csproj b/app/InkForge.Desktop/InkForge.Desktop.csproj
index 0475604..58ae8e9 100644
--- a/app/InkForge.Desktop/InkForge.Desktop.csproj
+++ b/app/InkForge.Desktop/InkForge.Desktop.csproj
@@ -12,18 +12,21 @@
+
-
+
-
+
+
+
@@ -41,4 +44,4 @@
-
\ No newline at end of file
+
diff --git a/app/InkForge.Desktop/InkForgeFactory.cs b/app/InkForge.Desktop/InkForgeFactory.cs
index 7183d12..a59d961 100644
--- a/app/InkForge.Desktop/InkForgeFactory.cs
+++ b/app/InkForge.Desktop/InkForgeFactory.cs
@@ -1,84 +1,67 @@
-using Dock.Model.ReactiveUI;
+using Avalonia;
+
using Dock.Model.Controls;
using Dock.Model.Core;
-using Dock.Model.ReactiveUI.Controls;
-using Dock.Avalonia.Controls;
+using Dock.Model.Mvvm;
+using Dock.Model.Mvvm.Controls;
+
+using DynamicData.Binding;
+
+using InkForge.Desktop.Managers;
+using InkForge.Desktop.Models;
+using InkForge.Desktop.ViewModels.Documents;
+using InkForge.Desktop.ViewModels.Tools;
+
using Microsoft.Extensions.DependencyInjection;
-using Avalonia;
-using InkForge.Desktop.ViewModels;
namespace InkForge.Desktop;
public class InkForgeFactory : Factory
{
- private readonly IDocumentDock _documentDock;
+ private readonly IDock _mainDock;
private readonly IRootDock _rootDock;
- private readonly ViewModels.Tools.WorkspaceTool _workspaceTool;
+ private readonly WelcomePageDocumentViewModel _welcomePage;
+ private readonly WorkspaceTool _workspaceTool;
- public InkForgeFactory()
+ public InkForgeFactory(WorkspaceManager workspace)
{
- _rootDock = new RootDock
- {
- IsCollapsable = false,
- };
-
- _documentDock = new DocumentDock
- {
- Id = "Documents",
- Title = "Documents",
- CanCreateDocument = false,
- IsCollapsable = false,
- Proportion = double.NaN,
- };
+ _rootDock = CreateRootDock();
+ _mainDock = CreateDockDock();
+ _mainDock.IsCollapsable = false;
+ _mainDock.CanClose = false;
+ _welcomePage = CreateWelcomePageDocumentViewModel();
_workspaceTool = CreateWorkspaceTool();
+
+ workspace.WhenValueChanged(m => m.Workspace).Subscribe(OnWorkspaceChanged);
}
public override IRootDock CreateLayout()
{
- ProportionalDock workspaceLayout = new()
+ ToolDock toolDock = new()
{
- Proportion = 0.3,
+ Alignment = Alignment.Left,
+ Proportion = 0.25,
VisibleDockables = [_workspaceTool],
};
ProportionalDock windowLayoutContent = new()
{
Orientation = Orientation.Horizontal,
- IsCollapsable = false,
- VisibleDockables = [workspaceLayout, new ProportionalDockSplitter(), _documentDock]
+ VisibleDockables = [toolDock, new ProportionalDockSplitter(), _mainDock]
};
- RootDock windowLayout = new()
- {
- Title = "Default",
- IsCollapsable = false,
- VisibleDockables = [windowLayoutContent],
- ActiveDockable = windowLayoutContent,
- };
-
- _rootDock.VisibleDockables = [windowLayout];
- _rootDock.ActiveDockable = windowLayout;
- _rootDock.DefaultDockable = windowLayout;
+ _rootDock.VisibleDockables = [windowLayoutContent];
+ _rootDock.DefaultDockable = windowLayoutContent;
return _rootDock;
}
- public override void InitLayout(IDockable layout)
+ private static WelcomePageDocumentViewModel CreateWelcomePageDocumentViewModel()
{
- DockableLocator = new Dictionary>
- {
- ["Root"] = () => _rootDock,
- ["Documents"] = () => _documentDock,
- ["Workspace"] = () => _workspaceTool,
- };
-
- HostWindowLocator = new Dictionary>
- {
- [nameof(IDockWindow)] = () => new HostWindow()
- };
-
- base.InitLayout(layout);
+ return ActivatorUtilities.CreateInstance(
+ Application.Current!.GetValue(App.ServiceProviderProperty)
+ );
}
private static ViewModels.Tools.WorkspaceTool CreateWorkspaceTool()
@@ -87,4 +70,16 @@ public class InkForgeFactory : Factory
Application.Current!.GetValue(App.ServiceProviderProperty)
);
}
+
+ private void OnWorkspaceChanged(Workspace? workspace)
+ {
+ IDockable dock = workspace switch
+ {
+ null => _welcomePage,
+ _ => workspace.Services.GetRequiredService().Dock,
+ };
+
+ AddDockable(_mainDock, dock);
+ CloseOtherDockables(dock);
+ }
}
diff --git a/app/InkForge.Desktop/Managers/DocumentManager.cs b/app/InkForge.Desktop/Managers/DocumentManager.cs
index 7aff6e9..9b9784c 100644
--- a/app/InkForge.Desktop/Managers/DocumentManager.cs
+++ b/app/InkForge.Desktop/Managers/DocumentManager.cs
@@ -1,48 +1,38 @@
-using Avalonia;
+using AvaloniaEdit.Document;
-using Dock.Model.Core;
+using CommunityToolkit.Mvvm.Input;
+
+using Dock.Model.Controls;
using InkForge.Desktop.Models;
using InkForge.Desktop.ViewModels.Documents;
-using Microsoft.Extensions.DependencyInjection;
-
-using ReactiveUI;
-
namespace InkForge.Desktop.Managers;
-public class DocumentManager
+public partial class DocumentManager
{
- private readonly IDock _documents;
private readonly InkForgeFactory _factory;
- private readonly WelcomePageDocumentViewModel _welcomePage;
- private readonly WorkspaceManager _workspaceManager;
- public DocumentManager(WorkspaceManager workspaceManager, InkForgeFactory factory)
+ public IDocumentDock Dock { get; }
+
+ public DocumentManager(NoteStore noteStore, InkForgeFactory factory)
{
- _workspaceManager = workspaceManager;
_factory = factory;
- _documents = factory.GetDockable("Documents")!;
- _welcomePage = CreateWelcomePageDocumentViewModel();
- workspaceManager.WhenAnyValue(v => v.Workspace).Subscribe(OnWorkspaceChanged);
+ Dock = factory.CreateDocumentDock();
+ Dock.IsCollapsable = false;
+ Dock.CanCreateDocument = true;
+ Dock.CreateDocument = CreateDocumentCommand;
}
- private void OnWorkspaceChanged(Workspace? workspace)
+ [RelayCommand]
+ private void OnCreateDocument()
{
- if (workspace is null)
+ NoteEditDocumentViewModel editViewModel = new(new()
{
- _factory.AddDockable(_documents, _welcomePage);
- }
- else
- {
- _factory.RemoveDockable(_welcomePage, false);
- }
- }
-
- private static WelcomePageDocumentViewModel CreateWelcomePageDocumentViewModel()
- {
- return ActivatorUtilities.CreateInstance(
- Application.Current!.GetValue(App.ServiceProviderProperty)
- );
+ Name = "Untitled Note",
+ }, new());
+ _factory.AddDockable(Dock, editViewModel);
+ _factory.SetActiveDockable(editViewModel);
+ _factory.SetFocusedDockable(Dock, editViewModel);
}
}
diff --git a/app/InkForge.Desktop/Managers/WorkspaceManager.cs b/app/InkForge.Desktop/Managers/WorkspaceManager.cs
index 3bee05d..f5bd450 100644
--- a/app/InkForge.Desktop/Managers/WorkspaceManager.cs
+++ b/app/InkForge.Desktop/Managers/WorkspaceManager.cs
@@ -1,3 +1,7 @@
+using Avalonia;
+
+using CommunityToolkit.Mvvm.ComponentModel;
+
using InkForge.Data;
using InkForge.Desktop.Data.Options;
using InkForge.Desktop.Models;
@@ -5,24 +9,16 @@ using InkForge.Desktop.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
-using ReactiveUI;
-
namespace InkForge.Desktop.Managers;
-public class WorkspaceManager(IServiceProvider serviceProvider) : ReactiveObject
+public partial class WorkspaceManager(IServiceProvider serviceProvider) : ObservableObject
{
private readonly IServiceProvider _serviceProvider = serviceProvider;
- private Workspace? _workspace;
-
- public Workspace? Workspace
- {
- get => _workspace;
- private set => this.RaiseAndSetIfChanged(ref _workspace, value);
- }
+ [ObservableProperty] private Workspace? _workspace;
public ValueTask CloseWorkspace()
{
- _workspace?.Dispose();
+ Workspace?.Dispose();
Workspace = null;
return ValueTask.CompletedTask;
}
@@ -66,7 +62,7 @@ public class WorkspaceManager(IServiceProvider serviceProvider) : ReactiveObject
var db = dbContext.Database;
if ((await db.GetPendingMigrationsAsync().ConfigureAwait(false)).Any())
{
- if (file.Exists)
+ if ((await db.GetAppliedMigrationsAsync().ConfigureAwait(false)).Any())
{
file.CopyTo(Path.ChangeExtension(file.FullName, $"{DateTime.Now:s}{file.Extension}"));
}
@@ -74,6 +70,8 @@ public class WorkspaceManager(IServiceProvider serviceProvider) : ReactiveObject
await db.MigrateAsync().ConfigureAwait(false);
}
+ await serviceProvider.GetRequiredService().Load().ConfigureAwait(false);
+
scope = null;
}
catch (Exception)
diff --git a/app/InkForge.Desktop/Microsoft/Extensions/DependencyInjection/InkForgeServiceCollection.cs b/app/InkForge.Desktop/Microsoft/Extensions/DependencyInjection/InkForgeServiceCollection.cs
index 328f8ce..bf99529 100644
--- a/app/InkForge.Desktop/Microsoft/Extensions/DependencyInjection/InkForgeServiceCollection.cs
+++ b/app/InkForge.Desktop/Microsoft/Extensions/DependencyInjection/InkForgeServiceCollection.cs
@@ -23,7 +23,6 @@ public static class InkForgeServiceCollections
// Singletons
// - Concrete
- services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
@@ -33,6 +32,7 @@ public static class InkForgeServiceCollections
// Scoped
// - Concrete
+ services.AddScoped();
services.AddScoped();
services.AddScoped();
diff --git a/app/InkForge.Desktop/Models/Note.cs b/app/InkForge.Desktop/Models/Note.cs
index 58a0295..c19675e 100644
--- a/app/InkForge.Desktop/Models/Note.cs
+++ b/app/InkForge.Desktop/Models/Note.cs
@@ -1,61 +1,12 @@
-using System.Reactive.Linq;
-using System.Reactive.Subjects;
-
-using ReactiveUI;
+using CommunityToolkit.Mvvm.ComponentModel;
namespace InkForge.Desktop.Models;
-public class Note : ReactiveObject
+public partial class Note : ObservableObject
{
- private readonly ObservableAsPropertyHelper _parent;
- private readonly BehaviorSubject _parentId = new(default);
- private DateTimeOffset _createdTime;
- private int _id;
- private string _name = default!;
- private DateTimeOffset _updatedTime;
-
- public DateTimeOffset CreatedTime
- {
- get => _createdTime;
- set => this.RaiseAndSetIfChanged(ref _createdTime, value);
- }
-
- public int Id
- {
- get => _id;
- set => this.RaiseAndSetIfChanged(ref _id, value);
- }
-
- public string Name
- {
- get => _name;
- set => this.RaiseAndSetIfChanged(ref _name, value);
- }
-
- public DateTimeOffset UpdatedTime
- {
- get => _updatedTime;
- set => this.RaiseAndSetIfChanged(ref _updatedTime, value);
- }
-
- public Note? Parent
- {
- get => _parent.Value;
- set => ParentId = value?.Id;
- }
-
- public int? ParentId
- {
- get => _parentId.Value;
- set => _parentId.OnNext(value);
- }
-
- public Note(NoteStore noteStore)
- {
- _parent = _parentId.Select(id => id switch
- {
- { } => noteStore.Watch((int)id),
- _ => Observable.Empty(),
- }).Switch(null).ToProperty(this, nameof(Parent), deferSubscription: true);
- }
+ [ObservableProperty] private DateTimeOffset _createdTime;
+ [ObservableProperty] private int _id;
+ [ObservableProperty] private string _name = default!;
+ [ObservableProperty] private int? _parentId;
+ [ObservableProperty] private DateTimeOffset _updatedTime;
}
diff --git a/app/InkForge.Desktop/Models/NoteStore.cs b/app/InkForge.Desktop/Models/NoteStore.cs
index 6be8a08..ff9d6aa 100644
--- a/app/InkForge.Desktop/Models/NoteStore.cs
+++ b/app/InkForge.Desktop/Models/NoteStore.cs
@@ -1,7 +1,4 @@
-using System.Collections.ObjectModel;
-using System.Reactive.Linq;
-
-using DynamicData;
+using Avalonia.Collections;
using InkForge.Data;
@@ -9,51 +6,46 @@ using Microsoft.EntityFrameworkCore;
namespace InkForge.Desktop.Models;
-public class NoteStore
+public class NoteStore(IDbContextFactory dbContextFactory)
{
- private readonly IDbContextFactory _dbContextFactory;
- private readonly SourceCache _notesCache = new(m => m.Id);
+ public AvaloniaDictionary Notes { get; } = [];
- public ReadOnlyObservableCollection Notes { get; }
-
- public NoteStore(IDbContextFactory dbContextFactory)
+ public async ValueTask Load()
{
- _dbContextFactory = dbContextFactory;
+ await using var dbContext = await dbContextFactory.CreateDbContextAsync().ConfigureAwait(false);
+ Notes.Clear();
+ await foreach (var note in dbContext.Notes.AsAsyncEnumerable().ConfigureAwait(false))
+ {
+ Notes.Add(note.Id, Map(note));
+ }
}
public void AddNote(Note note)
{
- using var dbContext = _dbContextFactory.CreateDbContext();
- var entity = ToEntity(note);
+ using var dbContext = dbContextFactory.CreateDbContext();
+ var entity = Map(note);
var entry = dbContext.Notes.Add(entity);
-
+
dbContext.SaveChanges();
}
- public Note CreateNote() => new(this);
-
public Note? GetById(int id)
{
- if (((Note?)_notesCache.Lookup(id)) is not Note note)
+ if (!Notes.TryGetValue(id, out var note))
{
- using var dbContext = _dbContextFactory.CreateDbContext();
+ using var dbContext = dbContextFactory.CreateDbContext();
if (dbContext.Notes.Find(id) is not { } dbNote)
{
return null;
}
- note = ToNote(dbNote);
+ Notes.Add(id, note = Map(dbNote));
}
return note;
}
- public IObservable Watch(int id)
- {
- return _notesCache.WatchValue(id);
- }
-
- private NoteEntity ToEntity(Note note)
+ private NoteEntity Map(Note note)
{
return new()
{
@@ -64,25 +56,26 @@ public class NoteStore
Created = note.CreatedTime,
Updated = note.UpdatedTime,
},
- Parent = note.Parent switch
+ Parent = note.ParentId switch
{
- { Id: { } parentId } => new()
+ { } parentId => new()
{
Id = parentId
},
- _ => null,
- }
+ _ => null
+ },
};
}
- private Note ToNote(NoteEntity entity)
+ private Note Map(NoteEntity entity)
{
- var note = CreateNote();
- note.Id = entity.Id;
- note.Name = entity.Value.Name;
- note.CreatedTime = entity.Value.Created;
- note.UpdatedTime = entity.Value.Updated;
- note.ParentId = entity.Parent?.Id;
- return note;
+ return new()
+ {
+ Id = entity.Id,
+ Name = entity.Value.Name,
+ CreatedTime = entity.Value.Created,
+ UpdatedTime = entity.Value.Updated,
+ ParentId = entity.Parent?.Id
+ };
}
}
diff --git a/app/InkForge.Desktop/Models/TextDocumentStore.cs b/app/InkForge.Desktop/Models/TextDocumentStore.cs
new file mode 100644
index 0000000..2e079a0
--- /dev/null
+++ b/app/InkForge.Desktop/Models/TextDocumentStore.cs
@@ -0,0 +1,131 @@
+using System.Buffers;
+using System.Text;
+
+using Avalonia.Collections;
+
+using AvaloniaEdit.Document;
+
+using InkForge.Data;
+
+using Microsoft.Data.Sqlite;
+using Microsoft.EntityFrameworkCore;
+
+namespace InkForge.Desktop.Models;
+
+public class TextDocumentStore(IDbContextFactory dbContextFactory)
+{
+ private readonly AvaloniaDictionary _cache = [];
+
+ public void Close(int id)
+ {
+ if (_cache.Remove(id, out var document))
+ {
+ document.Remove(0, document.TextLength);
+ }
+ }
+
+ public TextDocument Get(int id)
+ {
+ if (!_cache.TryGetValue(id, out var document))
+ {
+ using var dbContext = dbContextFactory.CreateDbContext();
+ var connection = dbContext.Database.GetDbConnection();
+ using var command = connection.CreateCommand();
+ command.CommandText = $"SELECT rowid FROM Blobs WHERE Id={id}";
+ using var commandReader = command.ExecuteReader();
+ document = new();
+ if (commandReader.Read())
+ {
+ using SqliteBlob stream = new((SqliteConnection)connection, "Blob", "Value", commandReader.GetInt64(0), true);
+ CopyDocumentContent(stream, document);
+ }
+
+ _cache.Add(id, document);
+ }
+
+ return document;
+
+ static void CopyDocumentContent(Stream stream, TextDocument document)
+ {
+ DocumentTextWriter writer = new(document, 0);
+ StreamReader reader = new(stream, Encoding.UTF8);
+ Span buffer = stackalloc char[128];
+ while (!reader.EndOfStream)
+ {
+ var read = reader.Read(buffer);
+ writer.Write(buffer[..read]);
+ }
+ }
+ }
+
+ public int? Save(int? id, TextDocument textDocument)
+ {
+ var state = textDocument.CreateSnapshot();
+ var bytes = TextBytes(state);
+
+ using var dbContext = dbContextFactory.CreateDbContext();
+ var connection = dbContext.Database.GetDbConnection();
+ using var transaction = dbContext.Database.BeginTransaction();
+ using var command = connection.CreateCommand();
+ command.CommandText = id switch
+ {
+ null => $"INSERT INTO Blobs(Value) VALUES(zeroblob({bytes})) RETURNING (Id, rowid)",
+ _ => $"UPDATE Blobs SET Value=zeroblob({bytes}) WHERE Id={id} RETURNING (Id, rowid)"
+ };
+ using var commandReader = command.ExecuteReader();
+ if (!commandReader.Read())
+ {
+ return null;
+ }
+
+ id = commandReader.GetInt32(0);
+ using (SqliteBlob stream = new((SqliteConnection)connection, "Blobs", "Value", commandReader.GetInt64(1)))
+ {
+ using StreamWriter writer = new(stream, Encoding.UTF8);
+ state.WriteTextTo(writer);
+ }
+
+ transaction.Commit();
+ _cache.TryAdd((int)id, textDocument);
+ return id;
+
+ static int TextBytes(ITextSource text)
+ {
+ int length = 0;
+ Span byteBuffer = stackalloc byte[128];
+ using var reader = text.CreateReader();
+ ArrayBufferWriter buffer = new();
+ var encoder = Encoding.UTF8.GetEncoder();
+ while (reader.Peek() != -1)
+ {
+ var memory = buffer.GetMemory();
+ buffer.Advance(reader.Read(memory.Span));
+ ReadOnlySpan chars = buffer.WrittenSpan;
+
+ convert:
+ encoder.Convert(buffer.WrittenSpan, byteBuffer, false, out var charsUsed, out var bytesUsed, out _);
+ chars = chars[charsUsed..];
+ if (bytesUsed > 0)
+ {
+ length += bytesUsed;
+ goto convert;
+ }
+
+ Span remaining = [];
+ if (!chars.IsEmpty)
+ {
+ remaining = buffer.GetSpan(chars.Length);
+ chars.CopyTo(remaining);
+ }
+
+ buffer.Clear();
+ if (!remaining.IsEmpty)
+ {
+ buffer.Write(remaining);
+ }
+ }
+
+ return length;
+ }
+ }
+}
diff --git a/app/InkForge.Desktop/Models/Workspace.cs b/app/InkForge.Desktop/Models/Workspace.cs
index 4cb23de..7da3d8c 100644
--- a/app/InkForge.Desktop/Models/Workspace.cs
+++ b/app/InkForge.Desktop/Models/Workspace.cs
@@ -4,21 +4,16 @@ using Microsoft.Extensions.DependencyInjection;
namespace InkForge.Desktop.Models;
-public sealed class Workspace : IDisposable
+public sealed class Workspace(IServiceScope scope) : IDisposable
{
private bool _disposedValue;
- private IServiceScope? _scope;
+ private IServiceScope? _scope = scope;
public string Name { get; set; } = default!;
public LocalWorkspaceOptions Options { get; set; } = default!;
- public IServiceProvider Services => _scope!.ServiceProvider;
-
- public Workspace(IServiceScope scope)
- {
- _scope = scope;
- }
+ public IServiceProvider Services { get; } = scope.ServiceProvider;
public void Dispose()
{
@@ -33,14 +28,4 @@ public sealed class Workspace : IDisposable
_disposedValue = true;
}
}
-
- // private async Task LoadNotes()
- // {
- // await using var dbContext = await _dbContextFactory.CreateDbContextAsync().ConfigureAwait(false);
- // await foreach (var asdf in dbContext.Notes.AsAsyncEnumerable().ConfigureAwait(false))
- // {
-
- // }
- // _ = (await dbContext.Notes.ToListAsync().ConfigureAwait(false));
- // }
}
diff --git a/app/InkForge.Desktop/Program.cs b/app/InkForge.Desktop/Program.cs
index 12dc592..5f8493d 100644
--- a/app/InkForge.Desktop/Program.cs
+++ b/app/InkForge.Desktop/Program.cs
@@ -1,6 +1,5 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
-using Avalonia.ReactiveUI;
using Avalonia.Threading;
using InkForge.Desktop;
@@ -20,7 +19,6 @@ static class Program
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure()
.UsePlatformDetect()
- .UseReactiveUI()
.WithInterFont()
.LogToTrace();
@@ -40,7 +38,7 @@ static class Program
_ = app.ApplicationLifetime switch
{
IClassicDesktopStyleApplicationLifetime desktop => desktop.MainWindow = new MainWindow(),
- _ => throw new NotSupportedException(),
+ _ => throw new NotSupportedException(),
};
}
diff --git a/app/InkForge.Desktop/Services/TopLevels.cs b/app/InkForge.Desktop/Services/TopLevels.cs
index 05f63d9..c5344d1 100644
--- a/app/InkForge.Desktop/Services/TopLevels.cs
+++ b/app/InkForge.Desktop/Services/TopLevels.cs
@@ -1,4 +1,5 @@
using System.Reactive.Linq;
+using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Controls;
@@ -52,7 +53,7 @@ public class TopLevels
// Register any new context
if (e.NewValue != null)
{
- RegistrationMapper.Add(e.NewValue, sender);
+ CollectionsMarshal.GetValueRefOrAddDefault(RegistrationMapper, e.NewValue, out _) = sender;
}
}
diff --git a/app/InkForge.Desktop/ViewModels/Documents/NoteEditDocumentViewModel.cs b/app/InkForge.Desktop/ViewModels/Documents/NoteEditDocumentViewModel.cs
new file mode 100644
index 0000000..9dfe8c9
--- /dev/null
+++ b/app/InkForge.Desktop/ViewModels/Documents/NoteEditDocumentViewModel.cs
@@ -0,0 +1,30 @@
+using System.Reactive.Linq;
+
+using AvaloniaEdit.Document;
+
+using Dock.Model.Mvvm.Controls;
+
+using DynamicData.Binding;
+
+using InkForge.Desktop.Models;
+
+namespace InkForge.Desktop.ViewModels.Documents;
+
+public class NoteEditDocumentViewModel : Document
+{
+ public Note Note { get; }
+
+ public TextDocument Document { get; }
+
+ public NoteEditDocumentViewModel(Note note, TextDocument textDocument)
+ {
+ Note = note;
+ Document = textDocument;
+
+ Observable.CombineLatest(
+ this.WhenValueChanged(v => v.Note.Name),
+ this.WhenValueChanged(v => v.Document.UndoStack.IsOriginalFile),
+ (name, original) => original ? name : $"{name} *"
+ ).Subscribe(title => Title = title!);
+ }
+}
diff --git a/app/InkForge.Desktop/ViewModels/Documents/WelcomePageDocumentViewModel.cs b/app/InkForge.Desktop/ViewModels/Documents/WelcomePageDocumentViewModel.cs
index 8108738..d916dc0 100644
--- a/app/InkForge.Desktop/ViewModels/Documents/WelcomePageDocumentViewModel.cs
+++ b/app/InkForge.Desktop/ViewModels/Documents/WelcomePageDocumentViewModel.cs
@@ -2,33 +2,28 @@ using System.Reactive;
using Avalonia.Platform.Storage;
-using Dock.Model.ReactiveUI.Controls;
+using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
+
+using Dock.Model.Mvvm.Controls;
using InkForge.Desktop.Managers;
using InkForge.Desktop.Services;
-using ReactiveUI;
-
namespace InkForge.Desktop.ViewModels.Documents;
-public class WelcomePageDocumentViewModel : Document
+public partial class WelcomePageDocumentViewModel : Document
{
private readonly WorkspaceManager _workspaceController;
- public ReactiveCommand CreateNew { get; }
-
- public ReactiveCommand OpenNew { get; }
-
public WelcomePageDocumentViewModel(WorkspaceManager workspaceController)
{
- CanClose = false;
Title = "Welcome";
_workspaceController = workspaceController;
- CreateNew = ReactiveCommand.CreateFromTask(OnCreateNew);
- OpenNew = ReactiveCommand.CreateFromTask(OnOpenNew);
}
+ [RelayCommand]
private async Task OnCreateNew()
{
var storageProvider = this.GetStorageProvider()!;
@@ -56,6 +51,7 @@ public class WelcomePageDocumentViewModel : Document
await _workspaceController.OpenWorkspace(filePath, true);
}
+ [RelayCommand]
private async Task OnOpenNew()
{
var storageProvider = this.GetStorageProvider()!;
diff --git a/app/InkForge.Desktop/ViewModels/InkForgeDocumentDock.cs b/app/InkForge.Desktop/ViewModels/InkForgeDocumentDock.cs
deleted file mode 100644
index bd0f1f6..0000000
--- a/app/InkForge.Desktop/ViewModels/InkForgeDocumentDock.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Dock.Model.Core;
-using Dock.Model.ReactiveUI.Controls;
-
-namespace InkForge.Desktop.ViewModels;
-
-public class InkForgeDocumentDock : DocumentDock, IDock
-{
- bool IDock.IsEmpty
- {
- get => false;
- set { }
- }
-}
diff --git a/app/InkForge.Desktop/ViewModels/MainViewModel.cs b/app/InkForge.Desktop/ViewModels/MainViewModel.cs
index 6925461..469c7dc 100644
--- a/app/InkForge.Desktop/ViewModels/MainViewModel.cs
+++ b/app/InkForge.Desktop/ViewModels/MainViewModel.cs
@@ -1,32 +1,16 @@
-using Avalonia;
+using CommunityToolkit.Mvvm.ComponentModel;
using Dock.Model.Core;
-using InkForge.Desktop.Managers;
-
-using Microsoft.Extensions.DependencyInjection;
-
-using ReactiveUI;
-
namespace InkForge.Desktop.ViewModels;
-public class MainViewModel : ReactiveObject
+public class MainViewModel : ObservableObject
{
- private readonly DocumentManager _documentManager;
public IDock Layout { get; }
public MainViewModel(InkForgeFactory factory)
{
Layout = factory.CreateLayout();
factory.InitLayout(Layout);
-
- _documentManager = CreateDocumentManager();
- }
-
- private static DocumentManager CreateDocumentManager()
- {
- return ActivatorUtilities.CreateInstance(
- Application.Current!.GetValue(App.ServiceProviderProperty)
- );
}
}
diff --git a/app/InkForge.Desktop/ViewModels/RecentItemViewModel.cs b/app/InkForge.Desktop/ViewModels/RecentItemViewModel.cs
index c5dd596..4f4a08b 100644
--- a/app/InkForge.Desktop/ViewModels/RecentItemViewModel.cs
+++ b/app/InkForge.Desktop/ViewModels/RecentItemViewModel.cs
@@ -1,9 +1,14 @@
-using ReactiveUI;
+using CommunityToolkit.Mvvm.ComponentModel;
namespace InkForge.Desktop.ViewModels;
-public record class RecentItemViewModel(
- DateTimeOffset Created,
- string Name,
- DateTimeOffset LastUsed
-) : ReactiveRecord;
+public partial class RecentItemViewModel(
+ DateTimeOffset created,
+ string name,
+ DateTimeOffset lastUsed
+) : ObservableObject
+{
+ [ObservableProperty] private DateTimeOffset _created = created;
+ [ObservableProperty] private string _name = name;
+ [ObservableProperty] private DateTimeOffset _lastUsed = lastUsed;
+}
diff --git a/app/InkForge.Desktop/ViewModels/Tools/WorkspaceTool.cs b/app/InkForge.Desktop/ViewModels/Tools/WorkspaceTool.cs
index b5f0777..583c976 100644
--- a/app/InkForge.Desktop/ViewModels/Tools/WorkspaceTool.cs
+++ b/app/InkForge.Desktop/ViewModels/Tools/WorkspaceTool.cs
@@ -1,32 +1,40 @@
-using Dock.Model.ReactiveUI.Controls;
+using System.Reactive.Linq;
+
+using CommunityToolkit.Mvvm.ComponentModel;
+
+using Dock.Model.Mvvm.Controls;
+
+using DynamicData.Binding;
using InkForge.Desktop.Managers;
+using InkForge.Desktop.Models;
using InkForge.Desktop.ViewModels.Workspaces;
-using ReactiveUI;
-
namespace InkForge.Desktop.ViewModels.Tools;
-public class WorkspaceTool : Tool
+public partial class WorkspaceTool : Tool
{
- private WorkspaceViewModel? _workspace;
-
- public WorkspaceViewModel? Workspace
- {
- get => _workspace;
- private set => this.RaiseAndSetIfChanged(ref _workspace, value);
- }
+ private readonly IWorkspaceViewModelFactory _workspaceViewModelFactory;
+ [ObservableProperty] private WorkspaceViewModel? _workspace;
public WorkspaceTool(WorkspaceManager workspaceManager, IWorkspaceViewModelFactory workspaceViewModelFactory)
{
- Title = "Workspace";
+ _workspaceViewModelFactory = workspaceViewModelFactory;
+
+ Title = "Explorer";
CanClose = false;
+ CanFloat = false;
+ CanPin = false;
- workspaceManager.WhenAnyValue(v => v.Workspace,
- v => v switch
- {
- { } => workspaceViewModelFactory.Create(v),
- _ => null
- }).BindTo(this, v => v.Workspace);
+ workspaceManager.WhenValueChanged(v => v.Workspace).Subscribe(OnWorkspaceManagerWorkspaceChanged);
+ }
+
+ private void OnWorkspaceManagerWorkspaceChanged(Workspace? workspace)
+ {
+ Workspace = workspace switch
+ {
+ { } v => _workspaceViewModelFactory.Create(v),
+ _ => null
+ };
}
}
diff --git a/app/InkForge.Desktop/ViewModels/Workspaces/WorkspaceViewModel.cs b/app/InkForge.Desktop/ViewModels/Workspaces/WorkspaceViewModel.cs
index f28ea4e..6a7bab7 100644
--- a/app/InkForge.Desktop/ViewModels/Workspaces/WorkspaceViewModel.cs
+++ b/app/InkForge.Desktop/ViewModels/Workspaces/WorkspaceViewModel.cs
@@ -1,3 +1,9 @@
+using System.Collections.ObjectModel;
+
+using Avalonia;
+
+using DynamicData;
+
using InkForge.Desktop.Models;
using Microsoft.Extensions.DependencyInjection;
@@ -6,30 +12,24 @@ namespace InkForge.Desktop.ViewModels.Workspaces
{
public class WorkspaceViewModel
{
+ private readonly Workspace _workspace;
private readonly NoteStore _noteStore;
- // private readonly ObservableAsPropertyHelper _workspaceNameProperty;
+ private readonly ReadOnlyObservableCollection> _notes;
- // public string WorkspaceName => _workspaceNameProperty.Value;
+ public string Name => _workspace.Name;
- // public ReactiveCommand AddDocument { get; }
+ public ReadOnlyObservableCollection> Notes => _notes;
- public WorkspaceViewModel(NoteStore noteStore)
+ public WorkspaceViewModel(Workspace workspace, NoteStore noteStore)
{
+ _workspace = workspace;
_noteStore = noteStore;
+ noteStore.Notes
+ .AsObservableChangeSet(m => m.Key)
+ .Transform(m => m.Value, true)
+ .TransformToTree(m => m.Id)
+ .Bind(out _notes).Subscribe();
}
-
- // public WorkspacesViewModel(Workspace workspace)
- // {
- // _workspace = workspace;
- // _workspaceNameProperty = this.WhenAnyValue(v => v._workspace.Name).ToProperty(this, nameof(WorkspaceName));
-
- // AddDocument = ReactiveCommand.Create(OnAddDocument);
- // }
-
- // private void OnAddDocument()
- // {
-
- // }
}
public interface IWorkspaceViewModelFactory
@@ -39,14 +39,14 @@ namespace InkForge.Desktop.ViewModels.Workspaces
namespace Internal
{
- internal class WorkspaceViewModelFactory(IServiceProvider services) : IWorkspaceViewModelFactory
+ internal class WorkspaceViewModelFactory : IWorkspaceViewModelFactory
{
private static ObjectFactory? s_workspaceViewModelFactory;
- public WorkspaceViewModel Create(Workspace workspace)
+ public static WorkspaceViewModel Create(Workspace workspace)
{
s_workspaceViewModelFactory ??= ActivatorUtilities.CreateFactory([typeof(Workspace)]);
- return s_workspaceViewModelFactory(services, [workspace]);
+ return s_workspaceViewModelFactory(workspace.Services, [workspace]);
}
WorkspaceViewModel IWorkspaceViewModelFactory.Create(Workspace workspace) => Create(workspace);
diff --git a/app/InkForge.Desktop/Views/Documents/NoteEditDocument.axaml b/app/InkForge.Desktop/Views/Documents/NoteEditDocument.axaml
new file mode 100644
index 0000000..da3412d
--- /dev/null
+++ b/app/InkForge.Desktop/Views/Documents/NoteEditDocument.axaml
@@ -0,0 +1,15 @@
+
+
+
diff --git a/app/InkForge.Desktop/Views/Documents/NoteEditDocument.axaml.cs b/app/InkForge.Desktop/Views/Documents/NoteEditDocument.axaml.cs
new file mode 100644
index 0000000..8c0f5d4
--- /dev/null
+++ b/app/InkForge.Desktop/Views/Documents/NoteEditDocument.axaml.cs
@@ -0,0 +1,11 @@
+using Avalonia.Controls;
+
+namespace InkForge.Desktop.Views.Documents;
+
+public partial class NoteEditDocument : UserControl
+{
+ public NoteEditDocument()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/app/InkForge.Desktop/Views/Documents/WelcomePageDocument.axaml b/app/InkForge.Desktop/Views/Documents/WelcomePageDocument.axaml
index 63d4366..5b3a72e 100644
--- a/app/InkForge.Desktop/Views/Documents/WelcomePageDocument.axaml
+++ b/app/InkForge.Desktop/Views/Documents/WelcomePageDocument.axaml
@@ -28,11 +28,11 @@
-
\ No newline at end of file
+
diff --git a/app/InkForge.Desktop/Views/Documents/WelcomePageDocument.axaml.cs b/app/InkForge.Desktop/Views/Documents/WelcomePageDocument.axaml.cs
index 61334e9..563892b 100644
--- a/app/InkForge.Desktop/Views/Documents/WelcomePageDocument.axaml.cs
+++ b/app/InkForge.Desktop/Views/Documents/WelcomePageDocument.axaml.cs
@@ -1,10 +1,8 @@
-using Avalonia.ReactiveUI;
-
-using InkForge.Desktop.ViewModels.Documents;
+using Avalonia.Controls;
namespace InkForge.Desktop.Views.Documents;
-public partial class WelcomePageDocument : ReactiveUserControl
+public partial class WelcomePageDocument : UserControl
{
public WelcomePageDocument()
{
diff --git a/app/InkForge.Desktop/Views/MainWindow.axaml.cs b/app/InkForge.Desktop/Views/MainWindow.axaml.cs
index 42b4735..d7bbbf9 100644
--- a/app/InkForge.Desktop/Views/MainWindow.axaml.cs
+++ b/app/InkForge.Desktop/Views/MainWindow.axaml.cs
@@ -1,5 +1,5 @@
using Avalonia;
-using Avalonia.ReactiveUI;
+using Avalonia.Controls;
using InkForge.Desktop.ViewModels;
@@ -7,12 +7,12 @@ using Microsoft.Extensions.DependencyInjection;
namespace InkForge.Desktop.Views;
-public partial class MainWindow : ReactiveWindow
+public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
- ViewModel = CreateViewModel();
+ DataContext = CreateViewModel();
}
private static MainViewModel CreateViewModel()
diff --git a/app/InkForge.Desktop/Views/Tools/WorkspaceTool.axaml b/app/InkForge.Desktop/Views/Tools/WorkspaceTool.axaml
index c5e7d85..a0b6cd4 100644
--- a/app/InkForge.Desktop/Views/Tools/WorkspaceTool.axaml
+++ b/app/InkForge.Desktop/Views/Tools/WorkspaceTool.axaml
@@ -29,4 +29,4 @@
-
\ No newline at end of file
+
diff --git a/app/InkForge.Desktop/Views/Tools/WorkspaceTool.axaml.cs b/app/InkForge.Desktop/Views/Tools/WorkspaceTool.axaml.cs
index a0cfc1d..534ff7d 100644
--- a/app/InkForge.Desktop/Views/Tools/WorkspaceTool.axaml.cs
+++ b/app/InkForge.Desktop/Views/Tools/WorkspaceTool.axaml.cs
@@ -1,8 +1,8 @@
-using Avalonia.ReactiveUI;
+using Avalonia.Controls;
namespace InkForge.Desktop.Views.Tools;
-public partial class WorkspaceTool : ReactiveUserControl
+public partial class WorkspaceTool : UserControl
{
public WorkspaceTool()
{
diff --git a/app/InkForge.Desktop/Views/Workspaces/WorkspaceView.axaml b/app/InkForge.Desktop/Views/Workspaces/WorkspaceView.axaml
index c07ca41..549557f 100644
--- a/app/InkForge.Desktop/Views/Workspaces/WorkspaceView.axaml
+++ b/app/InkForge.Desktop/Views/Workspaces/WorkspaceView.axaml
@@ -12,7 +12,8 @@
-
-
-
-
\ No newline at end of file
+
diff --git a/app/InkForge.Desktop/Views/Workspaces/WorkspaceView.axaml.cs b/app/InkForge.Desktop/Views/Workspaces/WorkspaceView.axaml.cs
index 1505573..9386646 100644
--- a/app/InkForge.Desktop/Views/Workspaces/WorkspaceView.axaml.cs
+++ b/app/InkForge.Desktop/Views/Workspaces/WorkspaceView.axaml.cs
@@ -1,10 +1,8 @@
-using Avalonia.ReactiveUI;
-
-using InkForge.Desktop.ViewModels.Workspaces;
+using Avalonia.Controls;
namespace InkForge.Desktop.Views.Workspaces;
-public partial class WorkspaceView : ReactiveUserControl
+public partial class WorkspaceView : UserControl
{
public WorkspaceView()
{
diff --git a/shared/InkForge.Data/Blob.cs b/shared/InkForge.Data/Blob.cs
index 6596df0..a3630fd 100644
--- a/shared/InkForge.Data/Blob.cs
+++ b/shared/InkForge.Data/Blob.cs
@@ -1,3 +1,3 @@
namespace InkForge.Data;
-public class Blob : Entity;
+public class Blob : Entity;
diff --git a/shared/InkForge.Data/NoteDbContext.cs b/shared/InkForge.Data/NoteDbContext.cs
index 0d058ec..17fecbe 100644
--- a/shared/InkForge.Data/NoteDbContext.cs
+++ b/shared/InkForge.Data/NoteDbContext.cs
@@ -26,7 +26,10 @@ public class NoteDbContext(
{
options.HasKey(m => m.Id);
- options.OwnsOne(m => m.Value);
+ options.OwnsOne(m => m.Value, m =>
+ {
+ m.HasOne().WithOne().HasForeignKey(m => m.ContentId).IsRequired();
+ });
options.HasOne(m => m.Parent);
});
diff --git a/shared/InkForge.Data/Notes.cs b/shared/InkForge.Data/Notes.cs
index 894d143..98fbcb3 100644
--- a/shared/InkForge.Data/Notes.cs
+++ b/shared/InkForge.Data/Notes.cs
@@ -4,13 +4,13 @@ namespace InkForge.Data
{
public DateTimeOffset Created { get; set; }
- public string Name { get; set; } = default!;
-
- public DateTimeOffset Updated { get; set; }
+ public int ContentId { get; set; }
public DateTimeOffset? Deleted { get; set; }
- public Blob Content { get; set; } = default!;
+ public string Name { get; set; } = default!;
+
+ public DateTimeOffset Updated { get; set; }
}
public class NoteEntity : Entity;
diff --git a/shared/migrations/InkForge.Sqlite/Migrations/20240207000000__01_Initial.Designer.cs b/shared/migrations/InkForge.Sqlite/Migrations/20240207000000__01_Initial.Designer.cs
deleted file mode 100644
index bcfd152..0000000
--- a/shared/migrations/InkForge.Sqlite/Migrations/20240207000000__01_Initial.Designer.cs
+++ /dev/null
@@ -1,172 +0,0 @@
-//
-using System;
-using InkForge.Data;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-
-#nullable disable
-
-namespace InkForge.Sqlite.Migrations
-{
- [DbContext(typeof(NoteDbContext))]
- [Migration("20240207000000__01_Initial")]
- partial class _01_Initial
- {
- ///
- protected override void BuildTargetModel(ModelBuilder modelBuilder)
- {
-#pragma warning disable 612, 618
- modelBuilder.HasAnnotation("ProductVersion", "8.0.1");
-
- modelBuilder.Entity("InkForge.Data.Blob", b =>
- {
- b.Property("Id")
- .HasColumnType("TEXT");
-
- b.Property("Content")
- .IsRequired()
- .HasColumnType("BLOB");
-
- b.HasKey("Id");
-
- b.ToTable("Blobs");
- });
-
- modelBuilder.Entity("InkForge.Data.Infrastructure.NoteEntity", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("INTEGER");
-
- b.HasKey("Id");
-
- b.ToTable("Notes");
- });
-
- modelBuilder.Entity("InkForge.Data.Infrastructure.NoteVersionEntity", b =>
- {
- b.Property("Version")
- .ValueGeneratedOnAdd()
- .HasColumnType("INTEGER");
-
- b.Property("Id")
- .HasColumnType("INTEGER");
-
- b.HasKey("Version");
-
- b.HasIndex("Id", "Version")
- .IsUnique();
-
- b.ToTable("NoteVersions");
- });
-
- modelBuilder.Entity("InkForge.Data.Infrastructure.NoteEntity", b =>
- {
- b.OwnsOne("InkForge.Data.Domain.Note", "Value", b1 =>
- {
- b1.Property("ParentId")
- .HasColumnType("INTEGER");
-
- b1.Property("ContentId")
- .IsRequired()
- .HasColumnType("TEXT");
-
- b1.Property("Created")
- .HasColumnType("TEXT");
-
- b1.Property("Deleted")
- .HasColumnType("TEXT");
-
- b1.Property("Name")
- .IsRequired()
- .HasColumnType("TEXT");
-
- b1.Property("Updated")
- .HasColumnType("TEXT");
-
- b1.HasKey("ParentId");
-
- b1.HasIndex("ContentId");
-
- b1.ToTable("Notes");
-
- b1.HasOne("InkForge.Data.Blob", "Content")
- .WithMany()
- .HasForeignKey("ContentId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b1.WithOwner("Parent")
- .HasForeignKey("ParentId");
-
- b1.Navigation("Content");
-
- b1.Navigation("Parent");
- });
-
- b.Navigation("Value")
- .IsRequired();
- });
-
- modelBuilder.Entity("InkForge.Data.Infrastructure.NoteVersionEntity", b =>
- {
- b.OwnsOne("InkForge.Data.Domain.Note", "Value", b1 =>
- {
- b1.Property("NoteVersionEntityVersion")
- .HasColumnType("INTEGER");
-
- b1.Property("ContentId")
- .IsRequired()
- .HasColumnType("TEXT");
-
- b1.Property("Created")
- .HasColumnType("TEXT");
-
- b1.Property("Deleted")
- .HasColumnType("TEXT");
-
- b1.Property("Name")
- .IsRequired()
- .HasColumnType("TEXT");
-
- b1.Property("ParentId")
- .HasColumnType("INTEGER");
-
- b1.Property("Updated")
- .HasColumnType("TEXT");
-
- b1.HasKey("NoteVersionEntityVersion");
-
- b1.HasIndex("ContentId");
-
- b1.HasIndex("ParentId");
-
- b1.ToTable("NoteVersions");
-
- b1.HasOne("InkForge.Data.Blob", "Content")
- .WithMany()
- .HasForeignKey("ContentId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b1.WithOwner()
- .HasForeignKey("NoteVersionEntityVersion");
-
- b1.HasOne("InkForge.Data.Infrastructure.NoteEntity", "Parent")
- .WithMany()
- .HasForeignKey("ParentId");
-
- b1.Navigation("Content");
-
- b1.Navigation("Parent");
- });
-
- b.Navigation("Value")
- .IsRequired();
- });
-#pragma warning restore 612, 618
- }
- }
-}
diff --git a/shared/migrations/InkForge.Sqlite/Migrations/20240214000000__02_Metadata.Designer.cs b/shared/migrations/InkForge.Sqlite/Migrations/20240214000000__02_Metadata.Designer.cs
deleted file mode 100644
index 89a839f..0000000
--- a/shared/migrations/InkForge.Sqlite/Migrations/20240214000000__02_Metadata.Designer.cs
+++ /dev/null
@@ -1,207 +0,0 @@
-//
-using System;
-using InkForge.Data;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-
-#nullable disable
-
-namespace InkForge.Sqlite.Migrations
-{
- [DbContext(typeof(NoteDbContext))]
- [Migration("20240214000000__02_Metadata")]
- partial class _02_Metadata
- {
- ///
- protected override void BuildTargetModel(ModelBuilder modelBuilder)
- {
-#pragma warning disable 612, 618
- modelBuilder.HasAnnotation("ProductVersion", "8.0.2");
-
- modelBuilder.Entity("InkForge.Data.Blob", b =>
- {
- b.Property("Id")
- .HasColumnType("TEXT");
-
- b.Property("Content")
- .IsRequired()
- .HasColumnType("BLOB");
-
- b.HasKey("Id");
-
- b.ToTable("Blobs");
- });
-
- modelBuilder.Entity("InkForge.Data.Infrastructure.MetadataEntity", b =>
- {
- b.Property("Id")
- .HasColumnType("TEXT");
-
- b.Property("Value")
- .IsRequired()
- .HasColumnType("TEXT");
-
- b.HasKey("Id");
-
- b.ToTable("Metadata");
- });
-
- modelBuilder.Entity("InkForge.Data.Infrastructure.MetadataVersionEntity", b =>
- {
- b.Property("Version")
- .ValueGeneratedOnAdd()
- .HasColumnType("INTEGER");
-
- b.Property("Id")
- .HasColumnType("TEXT");
-
- b.Property("Value")
- .IsRequired()
- .HasColumnType("TEXT");
-
- b.HasKey("Version");
-
- b.HasIndex("Id", "Version")
- .IsUnique();
-
- b.ToTable("MetadataHistory");
- });
-
- modelBuilder.Entity("InkForge.Data.Infrastructure.NoteEntity", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("INTEGER");
-
- b.HasKey("Id");
-
- b.ToTable("Notes");
- });
-
- modelBuilder.Entity("InkForge.Data.Infrastructure.NoteVersionEntity", b =>
- {
- b.Property("Version")
- .ValueGeneratedOnAdd()
- .HasColumnType("INTEGER");
-
- b.Property("Id")
- .HasColumnType("INTEGER");
-
- b.HasKey("Version");
-
- b.HasIndex("Id", "Version")
- .IsUnique();
-
- b.ToTable("NoteVersions");
- });
-
- modelBuilder.Entity("InkForge.Data.Infrastructure.NoteEntity", b =>
- {
- b.OwnsOne("InkForge.Data.Domain.Note", "Value", b1 =>
- {
- b1.Property("ParentId")
- .HasColumnType("INTEGER");
-
- b1.Property("ContentId")
- .IsRequired()
- .HasColumnType("TEXT");
-
- b1.Property("Created")
- .HasColumnType("TEXT");
-
- b1.Property("Deleted")
- .HasColumnType("TEXT");
-
- b1.Property("Name")
- .IsRequired()
- .HasColumnType("TEXT");
-
- b1.Property("Updated")
- .HasColumnType("TEXT");
-
- b1.HasKey("ParentId");
-
- b1.HasIndex("ContentId");
-
- b1.ToTable("Notes");
-
- b1.HasOne("InkForge.Data.Blob", "Content")
- .WithMany()
- .HasForeignKey("ContentId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b1.WithOwner("Parent")
- .HasForeignKey("ParentId");
-
- b1.Navigation("Content");
-
- b1.Navigation("Parent");
- });
-
- b.Navigation("Value")
- .IsRequired();
- });
-
- modelBuilder.Entity("InkForge.Data.Infrastructure.NoteVersionEntity", b =>
- {
- b.OwnsOne("InkForge.Data.Domain.Note", "Value", b1 =>
- {
- b1.Property("NoteVersionEntityVersion")
- .HasColumnType("INTEGER");
-
- b1.Property("ContentId")
- .IsRequired()
- .HasColumnType("TEXT");
-
- b1.Property("Created")
- .HasColumnType("TEXT");
-
- b1.Property("Deleted")
- .HasColumnType("TEXT");
-
- b1.Property("Name")
- .IsRequired()
- .HasColumnType("TEXT");
-
- b1.Property("ParentId")
- .HasColumnType("INTEGER");
-
- b1.Property("Updated")
- .HasColumnType("TEXT");
-
- b1.HasKey("NoteVersionEntityVersion");
-
- b1.HasIndex("ContentId");
-
- b1.HasIndex("ParentId");
-
- b1.ToTable("NoteVersions");
-
- b1.HasOne("InkForge.Data.Blob", "Content")
- .WithMany()
- .HasForeignKey("ContentId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b1.WithOwner()
- .HasForeignKey("NoteVersionEntityVersion");
-
- b1.HasOne("InkForge.Data.Infrastructure.NoteEntity", "Parent")
- .WithMany()
- .HasForeignKey("ParentId");
-
- b1.Navigation("Content");
-
- b1.Navigation("Parent");
- });
-
- b.Navigation("Value")
- .IsRequired();
- });
-#pragma warning restore 612, 618
- }
- }
-}
diff --git a/shared/migrations/InkForge.Sqlite/Migrations/20240214000000__02_Metadata.cs b/shared/migrations/InkForge.Sqlite/Migrations/20240214000000__02_Metadata.cs
deleted file mode 100644
index 698c390..0000000
--- a/shared/migrations/InkForge.Sqlite/Migrations/20240214000000__02_Metadata.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using Microsoft.EntityFrameworkCore.Migrations;
-
-#nullable disable
-
-namespace InkForge.Sqlite.Migrations
-{
- ///
- public partial class _02_Metadata : Migration
- {
- ///
- protected override void Up(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.CreateTable(
- name: "Metadata",
- columns: table => new
- {
- Id = table.Column(type: "TEXT", nullable: false),
- Value = table.Column(type: "TEXT", nullable: false)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_Metadata", x => x.Id);
- });
-
- migrationBuilder.CreateTable(
- name: "MetadataHistory",
- columns: table => new
- {
- Version = table.Column(type: "INTEGER", nullable: false)
- .Annotation("Sqlite:Autoincrement", true),
- Value = table.Column(type: "TEXT", nullable: false),
- Id = table.Column(type: "TEXT", nullable: true)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_MetadataHistory", x => x.Version);
- });
-
- migrationBuilder.CreateIndex(
- name: "IX_MetadataHistory_Id_Version",
- table: "MetadataHistory",
- columns: new[] { "Id", "Version" },
- unique: true);
- }
-
- ///
- protected override void Down(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.DropTable(
- name: "Metadata");
-
- migrationBuilder.DropTable(
- name: "MetadataHistory");
- }
- }
-}
diff --git a/shared/migrations/InkForge.Sqlite/Migrations/20240405000000__03_DropHistory.Designer.cs b/shared/migrations/InkForge.Sqlite/Migrations/20240401_Initial.Designer.cs
similarity index 83%
rename from shared/migrations/InkForge.Sqlite/Migrations/20240405000000__03_DropHistory.Designer.cs
rename to shared/migrations/InkForge.Sqlite/Migrations/20240401_Initial.Designer.cs
index eaf5c59..8a092e2 100644
--- a/shared/migrations/InkForge.Sqlite/Migrations/20240405000000__03_DropHistory.Designer.cs
+++ b/shared/migrations/InkForge.Sqlite/Migrations/20240401_Initial.Designer.cs
@@ -11,8 +11,8 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace InkForge.Sqlite.Migrations
{
[DbContext(typeof(NoteDbContext))]
- [Migration("20240405000000__03_DropHistory")]
- partial class _03_DropHistory
+ [Migration("20240401_Initial")]
+ partial class _20240401_Initial
{
///
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@@ -22,8 +22,9 @@ namespace InkForge.Sqlite.Migrations
modelBuilder.Entity("InkForge.Data.Blob", b =>
{
- b.Property("Id")
- .HasColumnType("TEXT");
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
b.Property("Value")
.IsRequired()
@@ -75,9 +76,8 @@ namespace InkForge.Sqlite.Migrations
b1.Property("NoteEntityId")
.HasColumnType("INTEGER");
- b1.Property("ContentId")
- .IsRequired()
- .HasColumnType("TEXT");
+ b1.Property("ContentId")
+ .HasColumnType("INTEGER");
b1.Property("Created")
.HasColumnType("TEXT");
@@ -94,20 +94,19 @@ namespace InkForge.Sqlite.Migrations
b1.HasKey("NoteEntityId");
- b1.HasIndex("ContentId");
+ b1.HasIndex("ContentId")
+ .IsUnique();
b1.ToTable("Notes");
- b1.HasOne("InkForge.Data.Blob", "Content")
- .WithMany()
- .HasForeignKey("ContentId")
+ b1.HasOne("InkForge.Data.Blob", null)
+ .WithOne()
+ .HasForeignKey("InkForge.Data.NoteEntity.Value#InkForge.Data.Note", "ContentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b1.WithOwner()
.HasForeignKey("NoteEntityId");
-
- b1.Navigation("Content");
});
b.Navigation("Parent");
diff --git a/shared/migrations/InkForge.Sqlite/Migrations/20240207000000__01_Initial.cs b/shared/migrations/InkForge.Sqlite/Migrations/20240401_Initial.cs
similarity index 56%
rename from shared/migrations/InkForge.Sqlite/Migrations/20240207000000__01_Initial.cs
rename to shared/migrations/InkForge.Sqlite/Migrations/20240401_Initial.cs
index 0ac6965..0f53da1 100644
--- a/shared/migrations/InkForge.Sqlite/Migrations/20240207000000__01_Initial.cs
+++ b/shared/migrations/InkForge.Sqlite/Migrations/20240401_Initial.cs
@@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
namespace InkForge.Sqlite.Migrations
{
///
- public partial class _01_Initial : Migration
+ public partial class _20240401_Initial : Migration
{
///
protected override void Up(MigrationBuilder migrationBuilder)
@@ -15,25 +15,38 @@ namespace InkForge.Sqlite.Migrations
name: "Blobs",
columns: table => new
{
- Id = table.Column(type: "TEXT", nullable: false),
- Content = table.Column(type: "BLOB", nullable: false)
+ Id = table.Column(type: "INTEGER", nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Value = table.Column(type: "BLOB", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Blobs", x => x.Id);
});
+ migrationBuilder.CreateTable(
+ name: "Metadata",
+ columns: table => new
+ {
+ Id = table.Column(type: "TEXT", nullable: false),
+ Value = table.Column(type: "TEXT", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Metadata", x => x.Id);
+ });
+
migrationBuilder.CreateTable(
name: "Notes",
columns: table => new
{
- Id = table.Column(type: "INTEGER", nullable: false)
- .Annotation("Sqlite:Autoincrement", true),
+ Id = table.Column(type: "INTEGER", nullable: false),
Value_Created = table.Column(type: "TEXT", nullable: false),
+ Value_ContentId = table.Column(type: "INTEGER", nullable: false),
+ Value_Deleted = table.Column(type: "TEXT", nullable: true),
Value_Name = table.Column(type: "TEXT", nullable: false),
Value_Updated = table.Column(type: "TEXT", nullable: false),
- Value_Deleted = table.Column(type: "TEXT", nullable: true),
- Value_ContentId = table.Column(type: "TEXT", nullable: false)
+ ParentId = table.Column(type: "INTEGER", nullable: true)
},
constraints: table =>
{
@@ -44,65 +57,30 @@ namespace InkForge.Sqlite.Migrations
principalTable: "Blobs",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
- });
-
- migrationBuilder.CreateTable(
- name: "NoteVersions",
- columns: table => new
- {
- Version = table.Column(type: "INTEGER", nullable: false)
- .Annotation("Sqlite:Autoincrement", true),
- Value_Created = table.Column(type: "TEXT", nullable: false),
- Value_ParentId = table.Column(type: "INTEGER", nullable: true),
- Value_Name = table.Column(type: "TEXT", nullable: false),
- Value_Updated = table.Column(type: "TEXT", nullable: false),
- Value_Deleted = table.Column(type: "TEXT", nullable: true),
- Value_ContentId = table.Column(type: "TEXT", nullable: false),
- Id = table.Column(type: "INTEGER", nullable: false)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_NoteVersions", x => x.Version);
table.ForeignKey(
- name: "FK_NoteVersions_Blobs_Value_ContentId",
- column: x => x.Value_ContentId,
- principalTable: "Blobs",
- principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
- table.ForeignKey(
- name: "FK_NoteVersions_Notes_Value_ParentId",
- column: x => x.Value_ParentId,
+ name: "FK_Notes_Notes_ParentId",
+ column: x => x.ParentId,
principalTable: "Notes",
principalColumn: "Id");
});
+ migrationBuilder.CreateIndex(
+ name: "IX_Notes_ParentId",
+ table: "Notes",
+ column: "ParentId");
+
migrationBuilder.CreateIndex(
name: "IX_Notes_Value_ContentId",
table: "Notes",
- column: "Value_ContentId");
-
- migrationBuilder.CreateIndex(
- name: "IX_NoteVersions_Id_Version",
- table: "NoteVersions",
- columns: new[] { "Id", "Version" },
+ column: "Value_ContentId",
unique: true);
-
- migrationBuilder.CreateIndex(
- name: "IX_NoteVersions_Value_ContentId",
- table: "NoteVersions",
- column: "Value_ContentId");
-
- migrationBuilder.CreateIndex(
- name: "IX_NoteVersions_Value_ParentId",
- table: "NoteVersions",
- column: "Value_ParentId");
}
///
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
- name: "NoteVersions");
+ name: "Metadata");
migrationBuilder.DropTable(
name: "Notes");
diff --git a/shared/migrations/InkForge.Sqlite/Migrations/20240405000000__03_DropHistory.cs b/shared/migrations/InkForge.Sqlite/Migrations/20240405000000__03_DropHistory.cs
deleted file mode 100644
index ca5ed12..0000000
--- a/shared/migrations/InkForge.Sqlite/Migrations/20240405000000__03_DropHistory.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-using System;
-using Microsoft.EntityFrameworkCore.Migrations;
-
-#nullable disable
-
-namespace InkForge.Sqlite.Migrations
-{
- ///
- public partial class _03_DropHistory : Migration
- {
- ///
- protected override void Up(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.DropTable(
- name: "MetadataHistory");
-
- migrationBuilder.DropTable(
- name: "NoteVersions");
-
- migrationBuilder.RenameColumn(
- name: "Content",
- table: "Blobs",
- newName: "Value");
-
- migrationBuilder.AlterColumn(
- name: "Id",
- table: "Notes",
- type: "INTEGER",
- nullable: false,
- oldClrType: typeof(int),
- oldType: "INTEGER")
- .OldAnnotation("Sqlite:Autoincrement", true);
-
- migrationBuilder.AddColumn(
- name: "ParentId",
- table: "Notes",
- type: "INTEGER",
- nullable: true);
-
- migrationBuilder.CreateIndex(
- name: "IX_Notes_ParentId",
- table: "Notes",
- column: "ParentId");
-
- migrationBuilder.AddForeignKey(
- name: "FK_Notes_Notes_ParentId",
- table: "Notes",
- column: "ParentId",
- principalTable: "Notes",
- principalColumn: "Id");
- }
-
- ///
- protected override void Down(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.DropForeignKey(
- name: "FK_Notes_Notes_ParentId",
- table: "Notes");
-
- migrationBuilder.DropIndex(
- name: "IX_Notes_ParentId",
- table: "Notes");
-
- migrationBuilder.DropColumn(
- name: "ParentId",
- table: "Notes");
-
- migrationBuilder.RenameColumn(
- name: "Value",
- table: "Blobs",
- newName: "Content");
-
- migrationBuilder.AlterColumn(
- name: "Id",
- table: "Notes",
- type: "INTEGER",
- nullable: false,
- oldClrType: typeof(int),
- oldType: "INTEGER")
- .Annotation("Sqlite:Autoincrement", true);
-
- migrationBuilder.CreateTable(
- name: "MetadataHistory",
- columns: table => new
- {
- Version = table.Column(type: "INTEGER", nullable: false)
- .Annotation("Sqlite:Autoincrement", true),
- Id = table.Column(type: "TEXT", nullable: true),
- Value = table.Column(type: "TEXT", nullable: false)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_MetadataHistory", x => x.Version);
- });
-
- migrationBuilder.CreateTable(
- name: "NoteVersions",
- columns: table => new
- {
- Version = table.Column(type: "INTEGER", nullable: false)
- .Annotation("Sqlite:Autoincrement", true),
- Id = table.Column(type: "INTEGER", nullable: false),
- Value_ContentId = table.Column(type: "TEXT", nullable: false),
- Value_ParentId = table.Column(type: "INTEGER", nullable: true),
- Value_Created = table.Column(type: "TEXT", nullable: false),
- Value_Deleted = table.Column(type: "TEXT", nullable: true),
- Value_Name = table.Column(type: "TEXT", nullable: false),
- Value_Updated = table.Column(type: "TEXT", nullable: false)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_NoteVersions", x => x.Version);
- table.ForeignKey(
- name: "FK_NoteVersions_Blobs_Value_ContentId",
- column: x => x.Value_ContentId,
- principalTable: "Blobs",
- principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
- table.ForeignKey(
- name: "FK_NoteVersions_Notes_Value_ParentId",
- column: x => x.Value_ParentId,
- principalTable: "Notes",
- principalColumn: "Id");
- });
-
- migrationBuilder.CreateIndex(
- name: "IX_MetadataHistory_Id_Version",
- table: "MetadataHistory",
- columns: new[] { "Id", "Version" },
- unique: true);
-
- migrationBuilder.CreateIndex(
- name: "IX_NoteVersions_Id_Version",
- table: "NoteVersions",
- columns: new[] { "Id", "Version" },
- unique: true);
-
- migrationBuilder.CreateIndex(
- name: "IX_NoteVersions_Value_ContentId",
- table: "NoteVersions",
- column: "Value_ContentId");
-
- migrationBuilder.CreateIndex(
- name: "IX_NoteVersions_Value_ParentId",
- table: "NoteVersions",
- column: "Value_ParentId");
- }
- }
-}
diff --git a/shared/migrations/InkForge.Sqlite/Migrations/NoteDbContextModelSnapshot.cs b/shared/migrations/InkForge.Sqlite/Migrations/NoteDbContextModelSnapshot.cs
index 09d4e1f..2c82e81 100644
--- a/shared/migrations/InkForge.Sqlite/Migrations/NoteDbContextModelSnapshot.cs
+++ b/shared/migrations/InkForge.Sqlite/Migrations/NoteDbContextModelSnapshot.cs
@@ -19,8 +19,9 @@ namespace InkForge.Sqlite.Migrations
modelBuilder.Entity("InkForge.Data.Blob", b =>
{
- b.Property("Id")
- .HasColumnType("TEXT");
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
b.Property("Value")
.IsRequired()
@@ -28,7 +29,7 @@ namespace InkForge.Sqlite.Migrations
b.HasKey("Id");
- b.ToTable("Blobs", (string)null);
+ b.ToTable("Blobs");
});
modelBuilder.Entity("InkForge.Data.MetadataEntity", b =>
@@ -42,7 +43,7 @@ namespace InkForge.Sqlite.Migrations
b.HasKey("Id");
- b.ToTable("Metadata", (string)null);
+ b.ToTable("Metadata");
});
modelBuilder.Entity("InkForge.Data.NoteEntity", b =>
@@ -58,7 +59,7 @@ namespace InkForge.Sqlite.Migrations
b.HasIndex("ParentId");
- b.ToTable("Notes", (string)null);
+ b.ToTable("Notes");
});
modelBuilder.Entity("InkForge.Data.NoteEntity", b =>
@@ -67,14 +68,13 @@ namespace InkForge.Sqlite.Migrations
.WithMany()
.HasForeignKey("ParentId");
- b.OwnsOne("InkForge.Data.NoteEntity.Value#InkForge.Data.Note", "Value", b1 =>
+ b.OwnsOne("InkForge.Data.Note", "Value", b1 =>
{
b1.Property("NoteEntityId")
.HasColumnType("INTEGER");
- b1.Property("ContentId")
- .IsRequired()
- .HasColumnType("TEXT");
+ b1.Property("ContentId")
+ .HasColumnType("INTEGER");
b1.Property("Created")
.HasColumnType("TEXT");
@@ -91,20 +91,19 @@ namespace InkForge.Sqlite.Migrations
b1.HasKey("NoteEntityId");
- b1.HasIndex("ContentId");
+ b1.HasIndex("ContentId")
+ .IsUnique();
- b1.ToTable("Notes", (string)null);
+ b1.ToTable("Notes");
- b1.HasOne("InkForge.Data.Blob", "Content")
- .WithMany()
- .HasForeignKey("ContentId")
+ b1.HasOne("InkForge.Data.Blob", null)
+ .WithOne()
+ .HasForeignKey("InkForge.Data.NoteEntity.Value#InkForge.Data.Note", "ContentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b1.WithOwner()
.HasForeignKey("NoteEntityId");
-
- b1.Navigation("Content");
});
b.Navigation("Parent");