Download Projects from GitHub

How to use DataFS

After installing DataFS and creating a new instance (see DataFS Setup) you need to prepare the instance by extending the schema and create some named objects that your application can use as entry point.

Create a DTDL file

A DTDL file defines the data types of your application. Those types form the 'schema' of a domain. You can share types with other applications (e.g. in common files and #include them into your project). But every application should bring its own shema extension in form of a bdtd file that contains the full set of types it needs. During the schema extension process duplicated types are detected and reused.

You can create a DTDL file in a text editor or in Visual Studio. If you use Visual Studio, create a C++ or C# project and then add a new item. Then select 'DTDL file'. This will add a file that will be compiled, when the project compiles (or by right clicking the file and selecting 'compile' in C++ projects). If you build the file in a text editor, you can also call the DTDL compiler yourself.

Sample DTDL file:
DTDL - DataDefinition.dtdl
["root object"]
class TestRoot [id({1B013DB1-5219-4363-9E02-BD85D7E24413})]
{
    wstring           RootName;
    TestObjectList    AllObjects;
};

["object list"]
list TestObjectList [id({3F96FB26-623E-4C52-86AF-2CBC89F5C23A}), ck]
{
    object            anObject;
    int32             theType;
};

/*
    the idea is to store objects of type 'TestObject'
    in the 'anObject' variable of the 'TestObjectList'
    items

    remark: it is no restriction!
*/
objecttype TestObjectList.anObject(TestObject);

// this class has no description
class TestObject [id({B06E97E6-15D7-4B70-B94F-679F858E0FE8})]
{
    wstring           Text;
    int32             Number;
};

This sample DTDL file defines 2 classes and a list. The idea is to build an object of type 'TestRoot' and then create multiple objects of type 'TestObject' and add them to the 'AllObjects' list attribute.

Extending the schema

After compiling the DTDL file you receive a BDTD file. This file can be used to extend the schema of the domain. To do that you can either use DataFS_Tools or you can write a program that does it for you.

Remarks: The following sample program does almost not catch any errors. This is done to make it easier to see the main function. It's not recommended to do that in production.

C++
C#
#include "stdafx.h"

#include <DataFS\Client\DataFS Client.h>
//using namespace DataFoundation;

int _tmain(int argc, wchar_t* argv[])
{
    const wchar_t* strServerAddress = argv[1];

    UINT16 usServerPort = (UINT16)_wtoi(argv[2]);

    GUID guidDomainId;
    ::CLSIDFromString(argv[3], &guidDomainId);

    // connect
    DataFoundation::InitializeThread();

    DataFoundation::Connection* pConnection;
    DataFoundation::Connection_Create(&pConnection);

    if(FAILED(pConnection->ConnectW(strServerAddress, usServerPort, NULL)))
    {
        DataFoundation::Connection_Destroy(pConnection);
        DataFoundation::UninitializeThread();
        return -1;
    }

    // extend schema
    HRSRC hBdtd = ::FindResource(::GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_RT_BDTD1), L"RT_BDTD");
    void* pBdtd = ::LockResource(::LoadResource(::GetModuleHandle(NULL), hBdtd));
    int iBdtdSize = ::SizeofResource(::GetModuleHandle(NULL), hBdtd);

    DataFoundation::USchemaEdit* pSchema;
        
    if(SUCCEEDED(pConnection->QuerySchemaEdit(&pSchema, &guidDomainId)))
    {
        pSchema->CreateFromBinary(pBdtd, iBdtdSize);
        pSchema->Commit();
        pSchema->Release();
    }

    pConnection->Disconnect();
    DataFoundation::Connection_Destroy(pConnection);
    DataFoundation::UninitializeThread();

    return 0;
}
class Program
{
    static void Main(string[] args)
    {
        String strServerAddress = args[0];
        UInt16 usServerPort = UInt16.Parse(args[1]);
        Guid guidDomainId = Guid.Parse(args[2]);

        // connect
        DataFoundation.ThreadInit.InitializeThread();

        DataFoundation.Connection pConnection = DataFoundation.Connection.Create();

        if (0 > (pConnection.Connect(strServerAddress, usServerPort, null)))
        {
            DataFoundation.Connection.Destroy(pConnection);
            DataFoundation.ThreadInit.UninitializeThread();
            return;
        }

        // extend schema
        Stream sBdtd = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("DataDefinition");

        Byte[] pBdtd = new Byte[sBdtd.Length];
        sBdtd.Read(pBdtd, 0, (int)sBdtd.Length);

        DataFoundation.USchemaEdit pSchema;

        if (0 <= (pConnection.QuerySchemaEdit(out pSchema, guidDomainId)))
        {
            pSchema.CreateFromBinary(pBdtd);
            pSchema.Commit();
            pSchema.Release();
        }

        pConnection.Disconnect();
        DataFoundation.Connection.Destroy(pConnection);
        DataFoundation.ThreadInit.UninitializeThread();
    }
}

Create a DADL file

A DADL file defines how you use the data types that you defined in the DTDL file. DADL files are specific for every application. Even when using the same DTDL types, you can use different DADL files and definitions. The DADL file is a way to generate access classes for your application so that you don't have to write them by hand.

In theory you don't need DADL to work with DataFS. But it makes it much easier because a lot of functions are generated.

You can create a DADL file in a text editor or in Visual Studio. If you use Visual Studio, create a C++ or C# project and then add a new item. Then select 'DADL file'. This will add a file that will be compiled, when the project compiles (or by right clicking the file and selecting 'compile' in C++ projects). If you build the file in a text editor, you can also call the DADL compiler yourself.

Preparing the database

After compiling the DADL file you can use the classes it generated. The first step is to create all the objects that your application will need as entry points in normal operation.

Remarks: The following sample program does almost not catch any errors. This is done to make it easier to see the main function. It's not recommended to do that in production.

DADL - PrepareDefinition.dadl
#import <DataDefinition.bdtd>

object ITestRoot
{
    TestRoot
    {
        RootName            [ get, set ];
    }
};

create (ITestRoot);

C++
C#
#include "stdafx.h"

#include <DataFS\Client\DataFS Client.h>
//using namespace DataFoundation;

#include <DataFS\Access\DataFS Access.h>
using namespace DataFoundationAccess;

#include "_data\PrepareDefinition.h"

// {56F8EB44-B7E3-4564-B9A6-22E5E1B9110C}
const GUID guidRootName = 
{ 0x56f8eb44, 0xb7e3, 0x4564, { 0xb9, 0xa6, 0x22, 0xe5, 0xe1, 0xb9, 0x11, 0xc } };

int _tmain(int argc, wchar_t* argv[])
{
    const wchar_t* strServerAddress = argv[1];

    UINT16 usServerPort = (UINT16)_wtoi(argv[2]);

    GUID guidDomainId;
    ::CLSIDFromString(argv[3], &guidDomainId);

    UINT32 ulStorageId = 0;

    // connect
    DataFoundation::InitializeThread();

    WDomain* pWDomain = NewWDomain(0);
    if(FAILED(pWDomain->Initialize()))
    {
        DeleteWDomain(pWDomain);
        DataFoundation::UninitializeThread();
        return -1;
    }

    if(FAILED(pWDomain->Connect(strServerAddress, usServerPort, &guidDomainId, NULL)))
    {
        pWDomain->Uninitialize();
        DeleteWDomain(pWDomain);
        DataFoundation::UninitializeThread();
        return -1;
    }

    if(FAILED(pWDomain->QueryStorage(ulStorageId, false)))
    {
        pWDomain->DisconnectAll();
        pWDomain->Uninitialize();
        DeleteWDomain(pWDomain);
        DataFoundation::UninitializeThread();
        return -1;
    }

    // bind types
    PrepareDefinition::Bind(pWDomain);

    // create named object

    ITestRoot* pRootObject;

    PrepareDefinition::Create(pWDomain, &pRootObject);

    pRootObject->SetRootName(L"first test root");

    pRootObject->StoreData();

    pWDomain->InsertNamedObject(&pRootObject->BuildLink(true), &guidRootName, L"first entry point");

    pWDomain->Execute(TRANSACTION_STORE);

    pRootObject->Release();

    // unbind types
    PrepareDefinition::Unbind();

    // disconnect

    pWDomain->ReleaseStorage(ulStorageId);
    pWDomain->DisconnectAll();
    pWDomain->Uninitialize();
    DeleteWDomain(pWDomain);
    DataFoundation::UninitializeThread();

    return 0;
}
using DataFoundationAccess;

class Program
{
    static readonly Guid guidRootName = new Guid("{56F8EB44-B7E3-4564-B9A6-22E5E1B9110C}");

    static void Main(string[] args)
    {
        String strServerAddress = args[0];
        UInt16 usServerPort = UInt16.Parse(args[1]);
        Guid guidDomainId = Guid.Parse(args[2]);

        UInt32 ulStorageId = 0;

        // connect
        DataFoundation.ThreadInit.InitializeThread();

        WDomain pWDomain = WDomain.New();
        if (0 > (pWDomain.Initialize()))
        {
            WDomain.Delete(pWDomain);
            DataFoundation.ThreadInit.UninitializeThread();
            return;
        }

        if (0 > (pWDomain.Connect(strServerAddress, usServerPort, guidDomainId, null)))
        {
            pWDomain.Uninitialize();
            WDomain.Delete(pWDomain);
            DataFoundation.ThreadInit.UninitializeThread();
            return;
        }

        if (0 > (pWDomain.QueryStorage(ulStorageId, false, null)))
        {
            pWDomain.DisconnectAll();
            pWDomain.Uninitialize();
            WDomain.Delete(pWDomain);
            DataFoundation.ThreadInit.UninitializeThread();
            return;
        }

        // bind types
        PrepareDefinition.Bind(pWDomain);

        // create named object

        ITestRoot pRootObject;

        PrepareDefinition.Create(pWDomain, out pRootObject);

        pRootObject.SetRootName("first test root");

        pRootObject.StoreData(WDomain.TRANSACTION_STORE);

        pWDomain.InsertNamedObject(pRootObject.BuildLink(true), guidRootName, "first entry point", WDomain.TRANSACTION_STORE);

        pWDomain.Execute(WDomain.TRANSACTION_STORE);

        pRootObject.Release();

        // unbind types
        PrepareDefinition.Unbind();

        // disconnect

        pWDomain.ReleaseStorage(ulStorageId);
        pWDomain.DisconnectAll();
        pWDomain.Uninitialize();
        WDomain.Delete(pWDomain);
        DataFoundation.ThreadInit.UninitializeThread();
    }
}

Using the database

After the database is built, you can use it by simply working with the generated W-Classes.

Remarks: The following sample program does almost not catch any errors. This is done to make it easier to see the main function. It's not recommended to do that in production.

DADL - AccessDefinition.dadl
#import <DataDefinition.bdtd>

object ITestRoot
{
    TestRoot
    {
        RootName            [ get, set ];
        AllObjects          [ get, set ];
    }

    create(ITestObject); open(ITestObject);
};

open(ITestRoot);

object ITestObject
{
    TestObject
    {
        Text                [ get, set ];
        Number              [ get, set ];
    }
};

C++
C#
#include "stdafx.h"

#include <DataFS\Client\DataFS Client.h>
//using namespace DataFoundation;

#include <DataFS\Access\DataFS Access.h>
using namespace DataFoundationAccess;

#include "_data\AccessDefinition.h"

// {56F8EB44-B7E3-4564-B9A6-22E5E1B9110C}
const GUID guidRootName = 
{ 0x56f8eb44, 0xb7e3, 0x4564, { 0xb9, 0xa6, 0x22, 0xe5, 0xe1, 0xb9, 0x11, 0xc } };

int _tmain(int argc, wchar_t* argv[])
{
    const wchar_t* strServerAddress = argv[1];

    UINT16 usServerPort = (UINT16)_wtoi(argv[2]);

    GUID guidDomainId;
    ::CLSIDFromString(argv[3], &guidDomainId);

    UINT32 ulStorageId = 0;

    // connect
    DataFoundation::InitializeThread();

    WDomain* pWDomain = NewWDomain(0);
    if(FAILED(pWDomain->Initialize()))
    {
        DeleteWDomain(pWDomain);
        DataFoundation::UninitializeThread();
        return -1;
    }

    if(FAILED(pWDomain->Connect(strServerAddress, usServerPort, &guidDomainId, NULL)))
    {
        pWDomain->Uninitialize();
        DeleteWDomain(pWDomain);
        DataFoundation::UninitializeThread();
        return -1;
    }

    if(FAILED(pWDomain->QueryStorage(ulStorageId, false)))
    {
        pWDomain->DisconnectAll();
        pWDomain->Uninitialize();
        DeleteWDomain(pWDomain);
        DataFoundation::UninitializeThread();
        return -1;
    }

    // bind types
    AccessDefinition::Bind(pWDomain);

    // open named object

    DataFoundation::ObjectId oiRootObject;

    pWDomain->QueryNamedObjectId(&guidRootName, &oiRootObject);

    ITestRoot* pRootObject;
    AccessDefinition::Open(pWDomain, &pRootObject, &oiRootObject);

    pRootObject->Load();
    pWDomain->Execute(TRANSACTION_LOAD);

    // open the list for writing

    TestObjectList* pList;
    pRootObject->SetAllObjects(&pList);

    // create an add a new object

    ITestObject* pTestObject;

    pRootObject->Create(&pTestObject);

    TestObjectListItem itm;
    itm.anObject = pTestObject->BuildLink(true);
    itm.theType = 12;

    pList->Insert(NULL, &itm);

    pTestObject->SetText(L"something");
    pTestObject->SetNumber(343);

    pTestObject->StoreData();
    pRootObject->StoreData();

    pWDomain->Execute(TRANSACTION_STORE);

    pTestObject->Release();
    pRootObject->Release();

    // unbind types
    AccessDefinition::Unbind();

    // disconnect

    pWDomain->ReleaseStorage(ulStorageId);
    pWDomain->DisconnectAll();
    pWDomain->Uninitialize();
    DeleteWDomain(pWDomain);
    DataFoundation::UninitializeThread();

    return 0;
}
using DataFoundationAccess;

class Program
{
    static readonly Guid guidRootName = new Guid("{56F8EB44-B7E3-4564-B9A6-22E5E1B9110C}");

    static void Main(string[] args)
    {
        String strServerAddress = args[0];
        UInt16 usServerPort = UInt16.Parse(args[1]);
        Guid guidDomainId = Guid.Parse(args[2]);

        UInt32 ulStorageId = 0;

        // connect
        DataFoundation.ThreadInit.InitializeThread();

        WDomain pWDomain = WDomain.New();
        if (0 > (pWDomain.Initialize()))
        {
            WDomain.Delete(pWDomain);
            DataFoundation.ThreadInit.UninitializeThread();
            return;
        }

        if (0 > (pWDomain.Connect(strServerAddress, usServerPort, guidDomainId, null)))
        {
            pWDomain.Uninitialize();
            WDomain.Delete(pWDomain);
            DataFoundation.ThreadInit.UninitializeThread();
            return;
        }

        if (0 > (pWDomain.QueryStorage(ulStorageId, false, null)))
        {
            pWDomain.DisconnectAll();
            pWDomain.Uninitialize();
            WDomain.Delete(pWDomain);
            DataFoundation.ThreadInit.UninitializeThread();
            return;
        }

        // bind types
        AccessDefinition.Bind(pWDomain);

        // open named object

        DataFoundation.ObjectId oiRootObject;

        pWDomain.QueryNamedObjectId(guidRootName, out oiRootObject);

        ITestRoot pRootObject;
        AccessDefinition.Open(pWDomain, out pRootObject, oiRootObject, WDomain.TRANSACTION_LOAD);

        pRootObject.Load(_ITestRoot.ALL_ATTRIBUTES, WDomain.TRANSACTION_LOAD);
        pWDomain.Execute(WDomain.TRANSACTION_LOAD);

        // open the list for writing

        TestObjectList pList;
        pRootObject.SetAllObjects(out pList);

        // create an add a new object

        ITestObject pTestObject;

        pRootObject.Create(out pTestObject);

        TestObjectListItem itm = new TestObjectListItem();
        itm.anObject = pTestObject.BuildLink(true);
        itm.theType = 12;

        uint idx;
        pList.Insert(out idx, itm);

        pTestObject.SetText("something");
        pTestObject.SetNumber(343);

        pTestObject.StoreData(WDomain.TRANSACTION_STORE);
        pRootObject.StoreData(WDomain.TRANSACTION_STORE);

        pWDomain.Execute(WDomain.TRANSACTION_STORE);

        pTestObject.Release();
        pRootObject.Release();

        // unbind types
        AccessDefinition.Unbind();

        // disconnect

        pWDomain.ReleaseStorage(ulStorageId);
        pWDomain.DisconnectAll();
        pWDomain.Uninitialize();
        WDomain.Delete(pWDomain);
        DataFoundation.ThreadInit.UninitializeThread();
    }
}
© 2021 Mobiland AG