Getting the PK at which a ForeignKey of the type EntityField2 is pointing

Posts   
 
    
petrutz
User
Posts: 10
Joined: 01-Sep-2008
# Posted on: 21-Feb-2011 05:21:36   

So to explain myself a little better... using the adapter if you have the value of a field in a EntityField2 variable is it possible to find out the EntityField2 of the entity at which this EntityField2 is pointing assuming the current field is actually a FK? The relation would be a m:1.

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 21-Feb-2011 09:12:39   

Sorry, I'm not following. Could you please explain with simple code snippets what are you trying to do.

petrutz
User
Posts: 10
Joined: 01-Sep-2008
# Posted on: 21-Feb-2011 10:17:36   

Because we are facing some tight deadlines we are on out way of reducing as much of the repetitive code in our forms as possible.

In most forms what we have is a grid that has some columns on it plus some textboxes or combos, each of which holds the data referenced in the selected row of the grid. What we have there is essentially something like:

EntityCollection allPFV = new EntityCollection(new PFV1EntityFactory());
...
ultraGridPFV.DataSource = allPFV;

When the user selects a given record of the datagrid the data is saved in a currentPF that's a PFEntity.

The mapping is then done to and from the entity to some combos and other needed components on the form.

In order to avoid Form's locking problems related derived from the Form running in a single thread we make each of these operations for each of the entities that we need to load data for, in a different thread.

As the binding code tends to be quite similar when we do the initialization of the form we pass in an array with the relevant information for each of the the components in the form along with the fields of the db from which we are going to read the data.

Continuing with the example above, once a record is selected what we use is it's ID, which is an ID because we set it as one on the designer. Remember the grid is built on a view hence it has no ID really.

That ID allows us to load the data from the table holding the data which in the above example would be PFEntity. Note it is not a PFVEntity, meaning by our naming convention it is not a view.

In general in the database if we have a table called TAB, it's PK will be named ID_TAB. A FK in a table called FTAB towards the table TAB will be again named ID_TAB. The problem appears when the table FTAB has two references toward the table TAB. In this case we call the first FK towards TAB ID_TAB1 and the second one ID_TAB2.

When doing the mappings and the validations one of the things we need to know is the name of the field that is a PK in the table TAB referenced by the field FTAB.ID_TAB2. We could then use that ID for the binding to the value property of the combo that will display it's data. For most of the fields as the name of the field is the same as the one in the FTAB we of course have no problem...

Right now one of the things we pass the binding, valdating, loading methods is the field on the table FTAB and we pass it as being of type EntityField2.

We do something like:

gf = new VaVGenericField( ref _bwdlRSVFull1XEntity, "RSVFull1", new RSVFullEntityFactory(), "DescripcionCompleta", PFFields.IdAS1,"IdActvsub1",
                    ref ultraComboEditorActividadSubactividad1, true); formFields.Add(gf);

then that is actually building a class with a constructor like this one:

public VaVGenericField(
            ref BackgroundWorker entityDataLoaderBackgroundWorker, //the background worker that will load the data
            String fieldName,  //a name for the field, not used in the model itself, just in error messages and logging
            IEntityFactory2 FieldEntityFactory, //the entity that is going to be loaded
            String DisplayField, //the field that is shown on the combo
            EntityField2 Field, // the field on the core entity upon which is built the view that is shown on the grid
            String DataFieldOnGrid,  //the name of column on the grid
            ref UltraComboEditor UltraComboEditor, // the combo that is going to get/set the data of this field
            bool LimitToList //set to false if user can enter new values on this combo
            ) {
...


Right now we are solving the problem by looking for the PK of the table from which we fill the combo:

xFieldEntityFactory = FieldEntityFactory;
...
pkFieldOnRefrencedTable = xFieldEntityFactory.Create().PrimaryKeyFields[0];

But it would be a lot nicer to be able to write up something that would get the PK at which the FK field Field is actually pointing to, by looking just at the <EntityField2> Field.

Not sure if I managed to explain myself clear enough flushed

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 21-Feb-2011 14:46:36   

But it would be a lot nicer to be able to write up something that would get the PK at which the FK field Field is actually pointing to, by looking just at the <EntityField2> Field.

This information is not available in the EntitFiled2 object.

petrutz
User
Posts: 10
Joined: 01-Sep-2008
# Posted on: 21-Feb-2011 19:40:04   

So the only workaround, reflection or overriding?

Looking around in the forum I found this thread that I think it's about the same problem essentially:

http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=2019

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 22-Feb-2011 04:56:09   

petrutz wrote:

But it would be a lot nicer to be able to write up something that would get the PK at which the FK field Field is actually pointing to, by looking just at the <EntityField2> Field.

There is not available in the field, but you can figure out the entity to which the field belongs to. and from that obtain the relations. With that you can investigate the relation where that field is the fk, and then obtain the other side (PK). This works I think:

/// <summary>
/// Get the PK field associated with some passed FK field.
/// This assumes the relation in single (just one field per side). 
/// It also assumes there is just one FK-side relation from this field.
/// It also assumes the fkField belongs to an Entity (not TypedView)
/// </summary>
/// <param name="fkField"></param>
/// <returns></returns>
public IEntityFieldCore GetThePKFromThisSingleFK(IEntityFieldCore fkField)
{
    // get the entity name
    string entityName = fkField.ContainingObjectName;
    IEntityFactory2 entityFactory = EntityFactoryFactory.GetFactory((EntityType) Enum.Parse(typeof (EntityType), entityName));
    IEntity2 theEntity = entityFactory.Create();
    
    // get the relation objects from OrderEntity
    List<IEntityRelation> relations = theEntity.GetAllRelations();

    // get all FK relations from Order where EmployeeId field is in the FK side and is single
    var pkField =
            (from r in theEntity.GetAllRelations()
            from fk in r.GetAllFKEntityFieldCoreObjects()
            where !r.StartEntityIsPkSide
                && fk.Name == fkField.Name
                && r.GetAllFKEntityFieldCoreObjects().Count == 1                        
            select r.GetPKEntityFieldCore(0)).First();

    // return the pk field
    return pkField;
}

[TestMethod]
public void GetPKFromAnyFK()
{
    IEntityFieldCore pkField = GetThePKFromThisSingleFK(OrderFields.ShipVia);
    Assert.AreEqual("ShipperId", pkField.Name);  // pass
}

Be aware of the assumptions. And that used Linq2Objects, but if you don't use .Net3.5 you can replace that with some loops.

David Elizondo | LLBLGen Support Team