The event store should not need to know about the specific fields or properties of events. Otherwise every modification of your model would result in having to migrate your database (just as in good old-fashioned state-based persistence). Therefore I wouldn't recommend option 1 and 2 at all.
Below is the schema as used in Ncqrs. As you can see, the table "Events" stores the related data as a CLOB (i.e. JSON or XML). This corresponds to your option 3 (Only that there is no "ProductEvents" table because you only need one generic "Events" table. In Ncqrs the mapping to your Aggregate Roots happens through the "EventSources" table, where each EventSource corresponds to an actual Aggregate Root.)
Table Events:
Id [uniqueidentifier] NOT NULL,
TimeStamp [datetime] NOT NULL,
Name [varchar](max) NOT NULL,
Version [varchar](max) NOT NULL,
EventSourceId [uniqueidentifier] NOT NULL,
Sequence [bigint],
Data [nvarchar](max) NOT NULL
Table EventSources:
Id [uniqueidentifier] NOT NULL,
Type [nvarchar](255) NOT NULL,
Version [int] NOT NULL
The SQL persistence mechanism of Jonathan Oliver's Event Store implementation consists basically of one table called "Commits" with a BLOB field "Payload". This is pretty much the same as in Ncqrs, only that it serializes the event's properties in binary format (which, for instance, adds encryption support).
Greg Young recommends a similar approach, as extensively documented on Greg's website.
The schema of his prototypical "Events" table reads:
Table Events
AggregateId [Guid],
Data [Blob],
SequenceNumber [Long],
Version [Int]
I would go for an application service that is just responsible for generating unique ShortURL's. You can use a transactional DB to implement this behaviour. Typically this service would be used by the command handling part of the BlogPost aggregate. If there is a duplicate ShortURL, you can fire a DuplicateUrlErrorEvent.
You can pre-catch this in the UI (but never 100%) by creating a thin query-model using the same data-source, so you can query whether a shortified URL is unique before submitting the post (as described by @RyanR's answer).
Best Answer
May I introduce this .NET Core 2.x based event sourcing framework: https://github.com/jacqueskang/EventSourcing/
It provides base classes for implementing events, event-sourced entities, entity repositories, and several simple event stores to persist events in text file or in database (using EF Core).
It's especially easy to be integrated in a ASP.NET Core web application, I have a pretty simple demo here.
Welcome any contribution or comments!