📜 ⬆️ ⬇️

Department of Database Logic (Attempt # 2)

The first attempt was a bit messy, so I decided to write more consistently.

We will repeat the main idea: work with the database should be organized through a specially sharpened class, and not spread the call code throughout the project .

But this can be hindered by the interface that database vendors offer. We will practice on the basis of MongoDB .
')
Here I will propose the implementation of the following logic:

There should be a base class from which all classes are inherited, which we will save in the database, let it be DBData. Then he will have just 3 methods: Load, Save, Delete. And the address to base already will be business DBData.


The benefits of such a concept should be obvious - the user of objects can, without thinking about the implementation and nuances of databases, simply save and restore their objects. But there are a number of difficulties along the way. Consider them.

upd The discussion on my part is over. Thank you all for your attention, but the truth is too much time was spent on discussion.



Let's start with our control class in our software. It should always be in one form or another. His responsibility is quite extensive - he is engaged in gluing all the system classes in our software, in our case also manages the databases.

public class TaskManager
{
/// Link Task Manager
private static TaskManager thisInstance ;
/// Link to our adapter to MongoDB
private Database currentDatabase ;
public TaskManager ( )
{
thisInstance = this ;
currentDatabase = new Database ( ) ;
currentDatabase. RunServer ( ) ;
}
/// Get a pointer to the task manager
public static TaskManager GetInstance ( )
{
return thisInstance ;
}
/// Get a pointer to the database
public Database GetDatabase ( )
{
return currentDatabase ;
}
public void CloseDBServer ( )
{
if ( currentDatabase ! = null )
{ currentDatabase. CloseServer ( ) ; }
}
}


Now the adapter itself to MongoDB. As we see here, you may need to use the mapping for generalized methods, and in a variety of variations.

public class Database
{
/// MongoDB server process
private Process MongoDBProcess ;
/// Connect to MongoDB server
Mongo mongo = new Mongo ( ) ;
/// Current database
IMongoDatabase db ;

/// Start the server
public void RunServer ( )
{ ... }
/// Disable server
public void CloseServer ( )
{ ... }

/// Load object by ID
public DBData Load ( DBData argObject )
{
MethodInfo locMethodGetCollection = GetCollection ( argObject ) ;
var locCollection = locMethodGetCollection. Invoke ( db, null ) ;
MethodInfo locMethodLoad = GetMethod ( locCollection, "FindOne" , 1 , "Object" ) ;
object [ ] locArgs = { new { ID = argObject. ID } } ;
return ( DBData ) locMethodLoad. Invoke ( locCollection, locArgs ) ;
}
/// Save the object
public void Save ( DBData argObject )
{
MethodInfo locMethodGetCollection = GetCollection ( argObject ) ;
var locCollection = locMethodGetCollection. Invoke ( db, null ) ;
MethodInfo locMethodSave = GetMethod ( locCollection, "Save" , 1 , "Object" ) ;
object [ ] locArgs = { argObject } ;
locMethodSave. Invoke ( locCollection, locArgs ) ;
}
/// Delete object
public void Delete ( DBData argObject )
{
MethodInfo locMethodGetCollection = GetCollection ( argObject ) ;
var locCollection = locMethodGetCollection. Invoke ( db, null ) ;
MethodInfo locMethodDelete = GetMethod ( locCollection, "Delete" , 1 , "Object" ) ;
object [ ] locArgs = { new { ID = argObject. ID } } ;
locMethodDelete. Invoke ( locCollection, locArgs ) ;
}

/// Get the number of objects
public long Count ( DBData argObject )
{
MethodInfo locMethodGetCollection = GetCollection ( argObject ) ;
var locCollection = locMethodGetCollection. Invoke ( db, null ) ;
MethodInfo locMethodCount = GetMethod ( locCollection, "Count" ) ;
return ( long ) locMethodCount. Invoke ( locCollection, null ) ;
}

/// Download the identification of all objects
public ArrayList LoadAllID ( DBData argObject )
{
MethodInfo locMethodGeneric = InstantiationLoadAllID ( argObject ) ;
object [ ] locArgs = { argObject } ;
return ( ArrayList ) locMethodGeneric. Invoke ( this , locArgs ) ;
}

/// Download the identification of all objects
private ArrayList LoadAllID < T > ( DBData argObject ) where T : DBData
{
ArrayList retArray = new ArrayList ( ) ;
MethodInfo locMethodGetCollection = GetCollection ( argObject ) ;
var locCollection = locMethodGetCollection. Invoke ( db, null ) ;

MethodInfo locMethodFindAll = GetMethod ( locCollection, "FindAll" ) ;
ICursor < T > locCursor = locMethodFindAll. Invoke ( locCollection, null ) as ICursor < T >;

foreach ( DBData d in locCursor. Documents )
{ retArray. Add ( d. ID ) ; }
return retArray ;
}

private MethodInfo GetCollection ( object argObject )
{
MethodInfo locMethodGetCollectionGeneric = null ;

Type locType = typeof ( IMongoDatabase ) ;
MethodInfo [ ] myMethod = locType. GetMethods ( ) ;
foreach ( MethodInfo m in myMethod )
{
if ( m. Name == "GetCollection" )
{
ParameterInfo [ ] pi = m. GetParameters ( ) ;
if ( m. ReturnType . IsGenericType && pi. Length == 0 )
{
locMethodGetCollectionGeneric = m ;
break ;
}
}
}
Type locObjectType = argObject. GetType ( ) ;
Type [ ] locTypeArgs = { locObjectType } ;
return locMethodGetCollectionGeneric. MakeGenericMethod ( locTypeArgs ) ;
}

private MethodInfo InstantiationLoadAllID ( object argObject )
{
MethodInfo locMethodGeneric = null ;
Type locType = typeof ( Database ) ;
MethodInfo [ ] locMethod = locType. GetMethods ( BindingFlags. NonPublic | BindingFlags. Instance ) ;
foreach ( MethodInfo m in locMethod )
{
if ( m. Name == "LoadAllID" )
{
ParameterInfo [ ] pi = m. GetParameters ( ) ;
if ( m. IsGenericMethod && pi. Length == 1 )
{
locMethodGeneric = m ;
break ;
}
}
}
Type locObjectType = argObject. GetType ( ) ;
Type [ ] locTypeArgs = { locObjectType } ;
return locMethodGeneric. MakeGenericMethod ( locTypeArgs ) ;
}

private MethodInfo GetMethod ( object argObject, string argMethodName )
{
return GetMethod ( argObject, argMethodName, 0 , null ) ;
}

private MethodInfo GetMethod ( object argObject, string argMethodName, int argParamCount, string artTypeP1 )
{
MethodInfo locMethod = null ;

Type locType = argObject. GetType ( ) ;
MethodInfo [ ] locMethods = locType. GetMethods ( ) ;
foreach ( MethodInfo m in locMethods )
{
if ( m. Name == argMethodName )
{
ParameterInfo [ ] pi = m. GetParameters ( ) ;
if ( pi. Length == argParamCount )
{
if ( pi. Length == 1 )
{
if ( pi [ 0 ] . ParameterType . Name ! = artTypeP1 )
{ continue ; }
}
locMethod = m ;
break ;
}
}
}
return locMethod ;
}
}


But the bottom line is that no one appeals to the adapter. We have a parent class whose heirs can be saved and restored from the database. Here is the parent class:

public class DBData
{
public int ID ;
public DBData ( )
{ }

public DBData ( int argID )
{ Id = argID ; }

private Database GetDB ( )
{
return TaskManager. GetInstance ( ) . GetDatabase ( ) ;
}

public int Count ( )
{
return ( int ) GetDB ( ) . Count ( this ) ;
}
public void Save ( )
{
GetDB ( ) . Save ( this ) ;
}
public void Delete ( )
{
GetDB ( ) . Delete ( this ) ;
}
public object Load ( )
{
return GetDB ( ) . Load ( this ) ;
}
public ArrayList LoadAllID ( )
{
return GetDB ( ) . LoadAllID ( this ) ;
}
}


Next, create a successor:

public class StrategiesData : DBData
{
public string Name ;

public StrategiesData ( ) : base ( )
{ }

public StrategiesData ( int argID ) : base ( argID )
{ }

public StrategiesData ( int argID, string argName )
{
ID = argID ;
Name = argName ;
}
}


and then we work with it in an elementary way:

StrategiesData SD = new StrategiesData ( 1 , "Test1" ) ;
SD. Save ( ) ;



etc. What could be easier and more pleasant :)

upd. Here I will throw the code that will change if there are several different bases (we see that the interfaces are completely superfluous, and are not needed)

public abstract class Database
{

public abstract DBData Load ( DBData argObject )
{ }
public abstract void Save ( DBData argObject )
{ }
public abstract void Delete ( DBData argObject )
{ }
}
public class MongoDb : Database
{
public DBData Load ( DBData argObject )
{ }
public void Save ( DBData argObject )
{ }
public void Delete ( DBData argObject )
{ }
}
public class AnyDb : Database
{
public DBData Load ( DBData argObject )
{ }
public void Save ( DBData argObject )
{ }
public void Delete ( DBData argObject )
{ }
}
public class TaskManager
{
private Database currentDatabase ;
/// Get a pointer to the database
public Database GetDatabase ( )
{
return currentDatabase ;
}
public void ChangeDB ( )
{
if ( conditions when Mongo )
{
currentDatabase = new MongoDb ( )
}
if ( conditions when any other )
{
currentDatabase = new AnyDb ( )
}
}
}

Source: https://habr.com/ru/post/144645/


All Articles