Added DbIntermediateForeignObject and resolver

Set version to 1.5.20
master v1.5.20
Railz 6 years ago
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<DbForeignObject> foreignObjectAttributes = new List<DbForeignObject>() { };
public List<DbReverseForeignObject> reverseForeignObjectAttributes = new List<DbReverseForeignObject>() { };
public List<DbIntermediateForeignObject> intermediateObjectAttributes = new List<DbIntermediateForeignObject>() { };
/// <summary>
/// Marks variable as database-table
@ -74,6 +75,11 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System.Attributes
rfobj.Init(fi, this);
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)
{

@ -278,7 +278,6 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System
DbObject dbObject = ClassAction.Init(classType);
// Resolve foreignObjects
foreach (DbForeignObject foreignObjectAtt in dbObject.foreignObjectAttributes)
{
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
foreach (DbReverseForeignObject reverseForeignObjectAtt in dbObject.reverseForeignObjectAttributes)
{

@ -4,7 +4,7 @@
<TargetFramework>netcoreapp2.1</TargetFramework>
<RootNamespace>eu.railduction.netcore.dll.Database_Attribute_System</RootNamespace>
<SignAssembly>false</SignAssembly>
<Version>1.5.15</Version>
<Version>1.5.20</Version>
</PropertyGroup>
</Project>

Loading…
Cancel
Save