'Marten: Define schema stuff (like indexes etc) not in the constructor/factory call to create the DocumentStore
I just started testing Marten (2.9), and so far I am loving it. However, I am not sure I am following the DocumentStore.For
method. For example, in my "dbhandler" for Marten, I can write:
public MartenDbHandler()
{
store = DocumentStore.For(_ =>
{
_.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate;
_.Connection("host=localhost;database=marten;password=root;username=postgres");
_.Schema.For<Customer>().Index(x => x.PopulationRegistryNumber);
});
}
but naturally, I do not want to have all that schema code when I initialize the database and supply the connection string.
So I thought, maybe I can pass on the store
variable, and do the same, but then the For
thing doesn't exist:
... and I haven't really found a way to set the Schema in any other way.
What I really want to do is to have an Interface, that is dynamically loaded and executed (via Reflection) when I start my application, that handles those things, like an IMartenMetaData
that looks something like:
public interface IMartenMetaData
{
SetMetaData(DocumentStore store);
}
and then implement the schema things in that/those classes, but that doesn't work because I can't use the DocumentStore to set the meta.
Solution 1:[1]
I managed to do a much nice approach to keep it more dynamic and not all in the construction of DocumentStore.
Please see code below. The idea is straightforward:
Create the StoreOptions separately
Before creation of the DocumentStore, run method that via Reflection finds all classes of a certain Type that will add table meta data
Create the DocumentStore
public MartenDbHandler() { StoreOptions so = new StoreOptions(); so.Connection("host=localhost;database=marten;password=root;username=postgres"); so.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate; SetTableMeta(so); store = new DocumentStore(so); } private void SetTableMeta(StoreOptions storeOptions) { // We get the current assembly through the current class var currentAssembly = Assembly.GetExecutingAssembly(); // we filter the defined classes according to the interfaces they implement var stuff = currentAssembly.DefinedTypes.Where(type => type.IsSubclassOf(typeof(MartenTableMetaDataBase))).ToList(); foreach (Type type in stuff) { IMartenTableMetaData temp = (IMartenTableMetaData)Activator.CreateInstance(type); temp.SetTableMetaData(storeOptions); } OnLogEvent?.Invoke(this, $"{stuff.Count} table meta data initialized"); }
The IMartenTableMetaData is a base class for the IMartenTableMetaData interface. In the example below, the base class isn't used, but I normally find it good to have a base class (I use a similar approach to another ORM, where I actually use the base class). But, the base class can of course be removed if you have no use for it.
internal abstract class MartenTableMetaDataBase : IMartenTableMetaData
{
public void SetTableMetaData(StoreOptions storeOptions)
{
SetSpecificTableMetaData(storeOptions);
}
protected abstract void SetSpecificTableMetaData(StoreOptions storeOptions);
}
and the interface:
public interface IMartenTableMetaData
{
void SetTableMetaData(StoreOptions storeOptions);
}
So, I can now create a class for each Type I want to add meta data too, like this:
internal class MartenTableMetaDataCustomer : MartenTableMetaDataBase
{
protected override void SetSpecificTableMetaData(StoreOptions storeOptions)
{
storeOptions.Schema.For<Customer>().Index(x => x.Muni);
}
}
or
internal class MartenTableMetaDataDriver : MartenTableMetaDataBase
{
protected override void SetSpecificTableMetaData(StoreOptions storeOptions)
{
storeOptions.Schema.For<Driver>().Index(x => x.Username);
}
}
etc.
This will keep the Marten DB handler clean and meta data separated into specific classes for readability, clarity and all that stuff =)
Solution 2:[2]
Keep it simple. The document store is supposed to have a single instance in your app and you define the schema properties during construction. No need to abstract the store.
One way is you can create your own implementation of DocumentStore. You can refer to the test document store classes in the source code.
Update: You can find the sample here https://github.com/JasperFx/marten/blob/master/src/Marten.Testing/TestingDocumentStore.cs
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | halfer |
Solution 2 |