Otis wrote:
The information isn't present in an entity instance, only in code for example through the relation objects.
The problem isn't that easy to solve, as compound foreign keys for example will result in 1 m:1 or 1:1 relation so what to do with those? Also, entities which are on the PK side of a relation (1:n or 1:1), don't have fk fields but do have fields mapped on relations.
'best' way to solve this is through code generation.
Actually, I am interested in m:1 (maybe 1:1) relations at the moment. The goal is to fill-in a dropdownlist or similar controls like checkboxlist.
I was looking and the Template Studio and was able to add my custom template into the entity class. But this would still require either Reflection or editing the entityAdapter template itself to implement my custom Interface. And I am trying to leave the original templates alone this time.
So I took the advice from lethologica and ended with this (it's based on analysis of the original templates):
private IEntityRelation[] GetEntityRelations(System.Type entityType)
{
ArrayList arrRel = new ArrayList();
PropertyInfo pi = entityType.GetProperty ("Relations", BindingFlags.Static | BindingFlags.Public);
if (pi != null)
{
//Get Relations Class
object rels = pi.GetValue(null, new object[] {});
if (rels != null) {
foreach (PropertyInfo info in rels.GetType().GetProperties()) {
if (info.PropertyType.Equals(typeof(IEntityRelation))
|| info.PropertyType.IsSubclassOf(typeof(IEntityRelation))) {
arrRel.Add ((IEntityRelation) info.GetValue(rels, new object[]{}));
}
}
}
}
return (IEntityRelation[]) arrRel.ToArray (typeof(IEntityRelation));
}
as this is used only for m:1 relations, I can choose appropriete relation based on IEntityFieldCore:
private IEntityRelation GetRelationByField (IEntityRelation[] relations, IEntityFieldCore field) {
for (int i = 0; i < relations.Length; i++)
{
IEntityRelation rel = relations[i];
if ((rel.TypeOfRelation == RelationType.ManyToOne) &&
(rel.GetAllFKEntityFieldCoreObjects().Count == 1) &&
(rel.GetFKEntityFieldCore(0).Name == field.Name))
return rel;
}
return null;
}
Keep in mind that I am using System.Type of a EntityClass as a template for a form creation. I am assuming that I have all the entities in one namespace and assembly. Than I use relation for some "nasty" stuff I am not really proud of but it makes the job done.
System.Type classType = my original entity type
IEntityRelation relation = GetRelationByField(relations, srcField);
IEntityFieldCore primField= relation.GetPKEntityFieldCore(0);
string factoryName = classType.AssemblyQualifiedName.Replace ("EntityClasses." + classType.Name, "FactoryClasses." + primField.ContainingObjectName + "Factory");
string collName = classType.AssemblyQualifiedName.Replace ("EntityClasses." + classType.Name, "HelperClasses.EntityCollection");
EntityCollectionBase2 coll = GetCollection(collName, factoryName);
Collection is created using code from this: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=712
private EntityCollectionBase2 GetCollection (string collectionName, string factoryName) {
EntityCollectionBase2 ents = null;
System.Type factoryType = System.Type.GetType(factoryName, true, true);
System.Type collectionType = System.Type.GetType(collectionName, true, true);
IEntityFactory2 fac = (IEntityFactory2) factoryType.GetConstructor(new System.Type[]{}).Invoke(null);
if (fac != null)
{
ConstructorInfo ctor = collectionType.GetConstructor(new System.Type[]{typeof(IEntityFactory2)});
ents = (EntityCollectionBase2) ctor.Invoke(new object[] {fac});
}
if (ents != null)
Adapter.FetchEntityCollection(ents, new RelationPredicateBucket());
return ents;
}
This way I can create the form and fill it with data while using already compiled LLBLGen generated projects. I am planning to use class and field Custom properties to set some specific information (like what field should be used for text value in dropdownlist, whether to create dropdownlist or checkboxlist, etc.) but the basic settings will be done using standard field properties (I can use first string field for a text value,...)
I think I will look more into the code generation and try to extend or add factory classes this time - it may be easier and less intrusive this way - but it will have to wait for a while.
Anyway, thanks for all the help.
Jakub