Added DbIntermediateForeignObject and resolver
Set version to 1.5.20
This commit is contained in:
parent
4f7495ea68
commit
3a0af04b1c
@ -0,0 +1,80 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace eu.railduction.netcore.dll.Database_Attribute_System.Attributes
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
|
||||||
|
public class DbIntermediateForeignObject : Attribute
|
||||||
|
{
|
||||||
|
public Type foreignObjectType;
|
||||||
|
|
||||||
|
public string _intermediateTableName;
|
||||||
|
|
||||||
|
public string _keyName;
|
||||||
|
public string _foreignKeyName;
|
||||||
|
|
||||||
|
|
||||||
|
public DbPrimaryKey foreignPrimaryKeyAttribute;
|
||||||
|
|
||||||
|
public FieldInfo parentField;
|
||||||
|
public DbObject classAttribute;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks variable as intermediate-object of an dbObject
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="intermediateTableName">Table-name of intermediate-table. Must contain primaryKey of this class & target class</param>
|
||||||
|
/// <param name="keyName">Fieldname of primaryKey associated with the IntermediateObject on this side [m]:n (null if same as primary key) [Only works with 1 primaryKey]</param>
|
||||||
|
/// <param name="foreignKeyName">Fieldname of primaryKey associated with the IntermediateObject on the other side m:[n] (null if same as primary key) [Only works with 1 primaryKey]</param>
|
||||||
|
public DbIntermediateForeignObject(string intermediateTableName, string keyName = null, string foreignKeyName = null)
|
||||||
|
{
|
||||||
|
this._intermediateTableName = intermediateTableName;
|
||||||
|
this._foreignKeyName = foreignKeyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init(FieldInfo fi, DbObject classAttribute)
|
||||||
|
{
|
||||||
|
this.parentField = fi;
|
||||||
|
this.classAttribute = classAttribute;
|
||||||
|
this.foreignObjectType = fi.FieldType;
|
||||||
|
|
||||||
|
// Init foreign-object class
|
||||||
|
DbObject foreignClassAttribute = ClassAction.Init(this.foreignObjectType);
|
||||||
|
|
||||||
|
if (classAttribute.primaryKeyAttributes.Count < 1) throw new InvalidOperationException($"'{classAttribute.parentClassType.Name}' does not have a primaryKey.");
|
||||||
|
if (classAttribute.primaryKeyAttributes.Count > 1) throw new InvalidOperationException($"IntermediateObject does not support multiple primaryKeys.");
|
||||||
|
// Get primaryKey name if none is set
|
||||||
|
if (_keyName == null) _keyName = classAttribute.primaryKeyAttributes[0]._attributeName;
|
||||||
|
|
||||||
|
if (!(fi.FieldType is IList && fi.FieldType.IsGenericType)) // 1:m
|
||||||
|
throw new InvalidOperationException($"IntermediateObject has to be typeof(List<T>). Maybe you meant to use DbForeignObject or DbReverseForeignObject for 1:m or 1:1 relations.");
|
||||||
|
|
||||||
|
// Check the generic list and get inner-type
|
||||||
|
Type foreignObjectType = null;
|
||||||
|
foreach (Type interfaceType in fi.FieldType.GetInterfaces())
|
||||||
|
{
|
||||||
|
if (interfaceType.IsGenericType &&
|
||||||
|
interfaceType.GetGenericTypeDefinition()
|
||||||
|
== typeof(IList<>))
|
||||||
|
{
|
||||||
|
foreignObjectType = fi.FieldType.GetGenericArguments()[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foreignObjectType == null) throw new InvalidOperationException("Could not read innter-type of generic-list!");
|
||||||
|
|
||||||
|
// Now get the primaryKey from my foreignObject
|
||||||
|
DbObject foreignDbObject = ClassAction.Init(foreignObjectType);
|
||||||
|
// Check the primaryKey/s
|
||||||
|
if (foreignDbObject.primaryKeyAttributes.Count < 1) throw new InvalidOperationException($"'{foreignDbObject.parentClassType.Name}' does not have a primaryKey.");
|
||||||
|
if (foreignDbObject.primaryKeyAttributes.Count > 1) throw new InvalidOperationException($"IntermediateObject does not support multiple primaryKeys. (Found '{foreignDbObject.primaryKeyAttributes.Count}' in '{foreignDbObject.parentClassType.Name}')");
|
||||||
|
// Save it
|
||||||
|
foreignPrimaryKeyAttribute = foreignDbObject.primaryKeyAttributes[0];
|
||||||
|
|
||||||
|
if (_foreignKeyName == null) _foreignKeyName = foreignPrimaryKeyAttribute._attributeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System.Attributes
|
|||||||
public List<DbForeignKey> foreignKeyAttributes = new List<DbForeignKey>() { };
|
public List<DbForeignKey> foreignKeyAttributes = new List<DbForeignKey>() { };
|
||||||
public List<DbForeignObject> foreignObjectAttributes = new List<DbForeignObject>() { };
|
public List<DbForeignObject> foreignObjectAttributes = new List<DbForeignObject>() { };
|
||||||
public List<DbReverseForeignObject> reverseForeignObjectAttributes = new List<DbReverseForeignObject>() { };
|
public List<DbReverseForeignObject> reverseForeignObjectAttributes = new List<DbReverseForeignObject>() { };
|
||||||
|
public List<DbIntermediateForeignObject> intermediateObjectAttributes = new List<DbIntermediateForeignObject>() { };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Marks variable as database-table
|
/// Marks variable as database-table
|
||||||
@ -74,6 +75,11 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System.Attributes
|
|||||||
rfobj.Init(fi, this);
|
rfobj.Init(fi, this);
|
||||||
this.reverseForeignObjectAttributes.Add(rfobj);
|
this.reverseForeignObjectAttributes.Add(rfobj);
|
||||||
}
|
}
|
||||||
|
else if (fi.GetCustomAttribute(typeof(DbIntermediateForeignObject), true) is DbIntermediateForeignObject iobj) // ReverseForeignObjects
|
||||||
|
{
|
||||||
|
iobj.Init(fi, this);
|
||||||
|
this.intermediateObjectAttributes.Add(iobj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(InvalidOperationException ex)
|
catch(InvalidOperationException ex)
|
||||||
{
|
{
|
||||||
|
@ -278,7 +278,6 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System
|
|||||||
DbObject dbObject = ClassAction.Init(classType);
|
DbObject dbObject = ClassAction.Init(classType);
|
||||||
|
|
||||||
// Resolve foreignObjects
|
// Resolve foreignObjects
|
||||||
|
|
||||||
foreach (DbForeignObject foreignObjectAtt in dbObject.foreignObjectAttributes)
|
foreach (DbForeignObject foreignObjectAtt in dbObject.foreignObjectAttributes)
|
||||||
{
|
{
|
||||||
object foreignObject_value = foreignObjectAtt.parentField.GetValue(classObject);
|
object foreignObject_value = foreignObjectAtt.parentField.GetValue(classObject);
|
||||||
@ -322,6 +321,62 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve intermediateForeignObjects
|
||||||
|
foreach (DbIntermediateForeignObject intermediateForeignObjectAtt in dbObject.intermediateObjectAttributes)
|
||||||
|
{
|
||||||
|
object intermediateForeignObject_value = intermediateForeignObjectAtt.parentField.GetValue(classObject);
|
||||||
|
|
||||||
|
// When its empty, get it & set it
|
||||||
|
if (intermediateForeignObject_value == null)
|
||||||
|
{
|
||||||
|
// Generate & set attribute-set
|
||||||
|
Dictionary<string, object> attributes = new Dictionary<string, object>();
|
||||||
|
attributes.Add(intermediateForeignObjectAtt._keyName, dbObject.primaryKeyAttributes[0].parentField.GetValue(classObject));
|
||||||
|
|
||||||
|
string query = QueryBuilder.SelectByAttribute(intermediateForeignObjectAtt._intermediateTableName, attributes); // Generate query
|
||||||
|
List<Dictionary<string, object>> dataSet = queryExecutor(query); // Execute
|
||||||
|
// Extract data
|
||||||
|
List<object> values = new List<object>();
|
||||||
|
for (int i=0; i<dataSet.Count; i++)
|
||||||
|
{
|
||||||
|
Dictionary<string, object> data = dataSet[i];
|
||||||
|
object primaryKeyValue = data[intermediateForeignObjectAtt.foreignPrimaryKeyAttribute._attributeName];
|
||||||
|
|
||||||
|
values.Add(GetByPrimaryKey<object>(intermediateForeignObjectAtt.foreignPrimaryKeyAttribute.classAttribute.parentClassType, primaryKeyValue, queryExecutor));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now scan the just resolved class to be able to set myself
|
||||||
|
DbObject foreignDbObject = Init(intermediateForeignObjectAtt.foreignPrimaryKeyAttribute.classAttribute.parentClassType);
|
||||||
|
foreach (DbForeignObject dbForeignObject in foreignDbObject.foreignObjectAttributes)
|
||||||
|
{
|
||||||
|
// If the field-names match
|
||||||
|
if (dbForeignObject._foreignKeyName.ToLower() == dbObject.primaryKeyAttributes[0]._attributeName.ToLower())
|
||||||
|
{
|
||||||
|
object myReference = classObject;
|
||||||
|
foreach (object value in values)
|
||||||
|
{
|
||||||
|
dbForeignObject.parentField.SetValue(value, myReference);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set value
|
||||||
|
intermediateForeignObject_value = values;
|
||||||
|
intermediateForeignObjectAtt.parentField.SetValue(classObject, intermediateForeignObject_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursive resolving
|
||||||
|
if (max_depth > 1)
|
||||||
|
{
|
||||||
|
// If we have a list of objects, we need to recursively go into each one
|
||||||
|
foreach (object value in (IList)intermediateForeignObject_value)
|
||||||
|
{
|
||||||
|
ResolveForeignKeys(value, queryExecutor, max_depth - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve reverseForeignObjects
|
// Resolve reverseForeignObjects
|
||||||
foreach (DbReverseForeignObject reverseForeignObjectAtt in dbObject.reverseForeignObjectAttributes)
|
foreach (DbReverseForeignObject reverseForeignObjectAtt in dbObject.reverseForeignObjectAttributes)
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
<RootNamespace>eu.railduction.netcore.dll.Database_Attribute_System</RootNamespace>
|
<RootNamespace>eu.railduction.netcore.dll.Database_Attribute_System</RootNamespace>
|
||||||
<SignAssembly>false</SignAssembly>
|
<SignAssembly>false</SignAssembly>
|
||||||
<Version>1.5.15</Version>
|
<Version>1.5.20</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user