diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 69c3da45af..966ea72e8c 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -153,7 +153,6 @@ const config: UserConfig = { { text: 'Full Text Searching', link: '/documents/full-text' }, { text: 'Noda Time Support', link: '/documents/noda-time' }, { text: 'Partial updates/patching', link: '/documents/partial-updates-patching' }, - { text: 'PLv8 Support', link: '/documents/plv8' }, { text: 'AspNetCore Support', link: '/documents/aspnetcore' }, ] }, diff --git a/docs/configuration/ioc.md b/docs/configuration/ioc.md index 9b8cb52523..6ff101b0e7 100644 --- a/docs/configuration/ioc.md +++ b/docs/configuration/ioc.md @@ -2,7 +2,8 @@ ::: tip The Marten team recommends using the `IServiceCollection.AddMarten()` extension method -for IoC integration out of the box. +for IoC integration out of the box and honestly, the full `IHost` integration. At this point Marten +depends on the `IHostedService` abstraction in .NET for start up actions and the async daemon. ::: The Marten team has striven to make the library perfectly usable without the usage of an IoC container, but you may still want to diff --git a/docs/configuration/prebuilding.md b/docs/configuration/prebuilding.md index ccbb4b1b0b..2e7901be18 100644 --- a/docs/configuration/prebuilding.md +++ b/docs/configuration/prebuilding.md @@ -161,6 +161,7 @@ public static class Program services.AddMarten(opts => { + opts.Events.AppendMode = EventAppendMode.Quick; opts.GeneratedCodeMode = TypeLoadMode.Dynamic; opts.AutoCreateSchemaObjects = AutoCreate.All; opts.DatabaseSchemaName = "cli"; @@ -209,7 +210,7 @@ public static class Program } } ``` -snippet source | anchor +snippet source | anchor Okay, after all that, there should be a new command line option called `codegen` for your project. Assuming diff --git a/docs/configuration/storeoptions.md b/docs/configuration/storeoptions.md index 020855c202..46b263096c 100644 --- a/docs/configuration/storeoptions.md +++ b/docs/configuration/storeoptions.md @@ -333,7 +333,7 @@ but you do need to tell Marten about any non-default length limit like so: var store = DocumentStore.For(_ => { // If you have overridden NAMEDATALEN in your - // PostgreSQL database to 100 + // Postgresql database to 100 _.NameDataLength = 100; }); ``` diff --git a/docs/documents/index.md b/docs/documents/index.md index 0bf8477216..94e376dcdb 100644 --- a/docs/documents/index.md +++ b/docs/documents/index.md @@ -1,6 +1,18 @@ # Marten as Document DB -Marten's original focus was on enabling Postgresql as a document database for .Net developers that would allow developers to work very efficiently compared to the typical RDBMS + ORM approach while delivering solid performance. In Marten's case, persistent .Net _documents_ are just serialized to JSON and persisted to Postgresql using its unique JSONB capabilities. The advantage to developers of this approach is that there is much less configuration work necessary to map their persistent classes to a database structure. Developers are also far more able to evolve their application's model as there is so much less friction in changing the persistence layer with Marten compared to the RDBMS + ORM combination. +Marten's original focus was on enabling Postgresql as a document database for .Net developers. In Marten's case, this means +that instead of an ORM like EF Core where you have to map .NET types to flat relational database tables, Marten just utilizes +JSON serialization to persist and load .NET objects ("documents"). In conjunction with PostgreSQL's JSONB data type and its ability +to efficiently support rich querying and even indexing through JSON documents, Marten's approach has turned out to be highly +effective to implement persistence in many .NET applications. + +When a document database is a good fit for a system (mostly when you have relatively self-contained entities and don't need to +model complex relationships between document types), Marten can make teams much more productive over ORM or purely relational +database usage by: + +* Eliminating explicit ORM mapping +* Being able to accept changes as entities evolve without having to worry much about database migrations +* Utilizing built in database initialization and migrations at runtime so you can "just work" Here's an introduction to Marten Db as a document database from .Net Conf 2018: diff --git a/docs/documents/querying/linq/projections.md b/docs/documents/querying/linq/projections.md index c9ca2aa912..ee11d4a5ce 100644 --- a/docs/documents/querying/linq/projections.md +++ b/docs/documents/querying/linq/projections.md @@ -158,7 +158,7 @@ public async Task can_do_simple_select_many_against_simple_array() var names = query.Query().SelectMany(x => x.Tags).ToList(); names - .Count().ShouldBe(9); + .Count.ShouldBe(9); } } ``` diff --git a/docs/events/metadata.md b/docs/events/metadata.md index caeebf23ea..8fe7f127d6 100644 --- a/docs/events/metadata.md +++ b/docs/events/metadata.md @@ -152,7 +152,20 @@ where you append new events. At this point you can override: Do note that if you want to potentially overwrite the timestamp of events _and_ you want to use the "QuickAppend" option for faster appending, you'll need this configuration: -snippet: sample_setting_quick_with_server_timestamps + + +```cs +var builder = Host.CreateApplicationBuilder(); +builder.Services.AddMarten(opts => +{ + opts.Connection(builder.Configuration.GetConnectionString("marten")); + + // This is important! + opts.Events.AppendMode = EventAppendMode.QuickWithServerTimestamps; +}); +``` +snippet source | anchor + The setting above is important because the `QuickAppend` normally takes the timestamp from the database server time at the point of inserting database rows. The `QuickWithServerTimestamps` option changes Marten's @@ -162,12 +175,74 @@ by default, or explicitly overridden data on `IEvent` wrappers. Now, on to event appending. The first way is to pull out the `IEvent` wrapper and directly setting metadata like this: -snippet: sample_overriding_event_metadata_by_position + + +```cs +public static async Task override_metadata(IDocumentSession session) +{ + var started = new QuestStarted { Name = "Find the Orb" }; + + var joined = new MembersJoined + { + Day = 2, Location = "Faldor's Farm", Members = new string[] { "Garion", "Polgara", "Belgarath" } + }; + + var slayed1 = new MonsterSlayed { Name = "Troll" }; + var slayed2 = new MonsterSlayed { Name = "Dragon" }; + + var joined2 = new MembersJoined { Day = 5, Location = "Sendaria", Members = new string[] { "Silk", "Barak" } }; + + var action = session.Events + .StartStream(started, joined, slayed1, slayed2, joined2); + + // I'm grabbing the IEvent wrapper for the first event in the action + var wrapper = action.Events[0]; + wrapper.Timestamp = DateTimeOffset.UtcNow.Subtract(1.Hours()); + wrapper.SetHeader("category", "important"); + wrapper.Id = Guid.NewGuid(); // Just showing that you *can* override this value + wrapper.CausationId = wrapper.CorrelationId = Activity.Current?.Id; + + await session.SaveChangesAsync(); +} +``` +snippet source | anchor + The second option is to directly append the `IEvent` wrappers where you've already set metadata like this: -snippet: sample_override_by_appending_the_event_wrapper + + +```cs +public static async Task override_metadata2(IDocumentSession session) +{ + var started = new QuestStarted { Name = "Find the Orb" }; + + var joined = new MembersJoined + { + Day = 2, Location = "Faldor's Farm", Members = new string[] { "Garion", "Polgara", "Belgarath" } + }; + + var slayed1 = new MonsterSlayed { Name = "Troll" }; + var slayed2 = new MonsterSlayed { Name = "Dragon" }; + + var joined2 = new MembersJoined { Day = 5, Location = "Sendaria", Members = new string[] { "Silk", "Barak" } }; + + // The result of this is an IEvent wrapper around the + // started data with an overridden timestamp + // and a value for the "color" header + var wrapper = started.AsEvent() + .AtTimestamp(DateTimeOffset.UtcNow.Subtract(1.Hours())) + .WithHeader("color", "blue"); + + session.Events + .StartStream(wrapper, joined, slayed1, slayed2, joined2); + + await session.SaveChangesAsync(); +} +``` +snippet source | anchor + ::: tip You can also create event wrappers by calling either: diff --git a/docs/events/storage.md b/docs/events/storage.md index 33291eedd8..51dadc12a6 100644 --- a/docs/events/storage.md +++ b/docs/events/storage.md @@ -136,7 +136,29 @@ two different `Created` types above. While you _could_ manually alias all of the yourself to disambiguate, it's too easy to forget to do that. Instead, you can just switch to different naming schemes like this: -snippet: sample_event_naming_style + + +```cs +var builder = Host.CreateApplicationBuilder(); +builder.Services.AddMarten(opts => +{ + opts.Connection(builder.Configuration.GetConnectionString("marten")); + + // This is the default behavior, but just showing you that + // this is an option + opts.Events.EventNamingStyle = EventNamingStyle.ClassicTypeName; + + // This mode is "the classic style Marten has always used, except smart enough + // to disambiguate inner classes that have the same type name" + opts.Events.EventNamingStyle = EventNamingStyle.SmarterTypeName; + + // Forget all the pretty naming aliases, just use the .NET full type name for + // the event type name + opts.Events.EventNamingStyle = EventNamingStyle.FullTypeName; +}); +``` +snippet source | anchor + Note that you will have to switch out of the "classic" naming mode to disambiguate between event types with the same class name in different namespaces.