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<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…
x
Reference in New Issue
Block a user