Instantiating an existing entity instance

To load the entity's data from the persistent storage, we use the generated class related to this entity's definition, create an instance of that class and load the data (the actual entity instance) of the particular entity using a DataAccessAdapter object. As an example we're loading the entity identified with the customerID "CHOPS" into an object.

Using the primary key value

One way to instantiate the entity in an object is by passing all primary key values to the constructor of the entity class to use:

CustomerEntity customer = new CustomerEntity("CHOPS");
using(DataAccessAdapter adapter = new DataAccessAdapter())
{
    adapter.FetchEntity(customer);
}
Dim customer As New CustomerEntity("CHOPS")
Using adapter As New DataAccessAdapter()
    adapter.FetchEntity(customer)
End Using

This will load the entity with the primary key value of "CHOPS" into the object named customer.

FetchEntity has several overloads which offer different additional features. See the DataAccessAdapterBase class in the LLBLGen Pro runtime framework reference manual for details.

Using Linq / QuerySpec

There are other ways to fetch an entity using the PK value. LLBLGen Pro supports Linq and has its own high-level query system QuerySpec. The example below looks like the following in these two query systems.

CustomerEntity customer = null;
using(var adapter = new DataAccessAdapter())
{
    var metaData = new LinqMetaData(adapter);
    customer = metaData.Customer.FirstOrDefault(c=>c.CustomerId=="CHOPS);
}
var qf = new QueryFactory();
var q = qf.Customer.Where(CustomerFields.CustomerId=="CHOPS");
CustomerEntity customer = null;
using(var adapter = new DataAccessAdapter())
{
    customer = adapter.FetchFirst(q);
}

Another way to instantiate this same entity is via a related entity. Adapter however doesn't support automatic data loading when you traverse a relationship (lazy loading), all data has to be fetched up-front. A related entity offers a way to formulate the exact filters to fetch a specific entity very easily.

Let's load the order with ID 10254, which is an order of customer CHOPS. We can now use the loaded order to load an instance of the entity CHOPS. The example uses the KeepConnectionOpen feature by passing true to the constructor of the DataAccessAdapter object. The example explicitly closes the connection after the DataAccessAdapter usage is finished as we've ordered it to keep it open.

OrderEntity order = new OrderEntity(10254);
using(DataAccessAdapter adapter = new DataAccessAdapter(true))
{
    adapter.FetchEntity(order);
    order.Customer = adapter.FetchNewEntity<CustomerEntity>(order.GetRelationInfoCustomer());
    adapter.CloseConnection();
}
Dim order As New OrderEntity(10254)
Using adapter As New DataAccessAdapter(True)
    adapter.FetchEntity(order)
    order.Customer = adapter.FetchNewEntity(Of CustomerEntity)(order.GetRelationInfoCustomer())
    adapter.CloseConnection()
End Using

By setting order.Customer to an instance of CustomerEntity, the logic automatically sets the CustomerID field of order to the CustomerID of the specified CustomerEntity instance. Also the order object will be added to the CustomerEntity instance's Orders collection. This means that the following is true after the above code snippet:

  • order.CustomerID is equal to order.Customer.CustomerID
  • order.Customer.Orders.Contains(order) is true

The framework keeps the two in sync as well. Consider the following situation: a new EmployeeEntity instance employee, which has an autonumber primary key field, and a new OrderEntity instance order. When the following is done: order.Employee = employee;, and the order is saved (or the employee), the field order.EmployeeID is automatically set to the new key field of the employee object after employee is saved.

If CustomerEntity is in an inheritance hierarchy, the fetch is polymorphic. This means that if the Order entity, in this case the entity with PK value 10254, has a reference to a derived type of CustomerEntity, for example GoldCustomer, the entity returned will be of type GoldCustomer. See also Polymorphic fetches below.

Using a unique constraint's value

Entities can have other unique identifying attributes which are defined in the database and the LLBLGen Pro designer as unique constraints. In addition to the primary key these unique values can be used to load an entity. In our example, the CustomerEntity entity has a unique constraint defined on its field CompanyName, so we can use that field to load the same entity that the CHOPS example loaded above.

Fetching the entity using a unique constraint is done via these steps: first create an empty entity class instance, set the fields which form the unique constraint to the lookup value, then fetch the entity data using a special method call of the DataAccessAdapter.

Because an entity can have more than one unique constraint, you have to specify which unique constraint to use, which means: specify a filter for the unique constraint columns. Entities with unique constraints have methods to construct these filters automatically as shown in the following example.

CustomerEntity customer = new CustomerEntity();
using(DataAccessAdapter adapter = new DataAccessAdapter())
{
    customer.CompanyName = "Chop-suey Chinese";
    adapter.FetchEntityUsingUniqueConstraint(customer, customer.ConstructFilterForUCCompanyName());
}
Dim customer As New CustomerEntity()
Using adapter As New DataAccessAdapter()
    customer.CompanyName = "Chop-suey Chinese"
    adapter.FetchEntityUsingUniqueConstraint(customer, customer.ConstructFilterForUCCompanyName())
End Using

Using a prefetch path

An easy way to instantiate an entity can be by using a Prefetch Path, to read related entities together with the entity or entities to fetch. See for more information about Prefetch Paths and how to use them: Prefetch Paths.

Using a collection class

Another way to instantiate an entity is by instantiating a collection class and fetch one or more entity definitions into that collection. This method is described in detail in the section about collection classes. You can also see Tutorials and Examples: How Do I? - Read all entities into a collection.

Using a Context object

If you want to get a reference to an entity object already in memory, you can use a Context object, if that object was added to that particular Context object. The example below retrieves a reference to the customer object with PK CHOPS, if that entity was previously loaded into an entity object which was added to that Context object. If the entity object isn't in the Context object, a new entity object is returned. An example usage is shown below.

CustomerEntity customer = (CustomerEntity)myContext.Get(new CustomerEntityFactory(), "CHOPS");
if(customer.IsNew)
{
    // not found in context, fetch from database (assumes 'adapter' is a 
    // DataAccessAdapter instance)
    adapter.FetchEntity(customer);
}
Dim customer As CustomerEntity = CType(myContext.Get(New CustomerEntityFactory(), "CHOPS"), CustomerEntity)
If customer.IsNew Then
    ' not found in context, fetch from database (assumes 'adapter' is a DataAccessAdapter instance)
    adapter.FetchEntity(customer)
End If

Polymorphic fetches

Already mentioned early in this section is the phenomenon called 'Polymorphic fetches'. Imagine the following entity setup: BoardMember entity has a relationship (m:1) with CompanyCar. CompanyCar is the root of a TargetPerEntityHierarchy inheritance hierarchy and has two subtypes: FamilyCar and SportsCar. Because BoardMember has the relationship with CompanyCar, a field called CompanyCar is created in the BoardMember entity which is mapped onto the m:1 relationship BoardMember - CompanyCar.

In the database, several BoardMember instances have been stored, as well as several different CompanyCar instances, of type FamilyCar or SportsCar. Using DataAccessAdapter.FetchNewEntity, you can load the related CompanyCar instance of a given BoardMember's instance by using the following code:

CompanyCarEntity car = 
    adapter.FetchNewEntity<CompanyCarEntity>(myBoardMember.GetRelationInfoCompanyCar());
Dim car As CompanyCarEntity = _
    adapter.FetchNewEntity(Of CompanyCarEntity)(myBoardMember.GetRelationInfoCompanyCar())

However, car in the example above, can be of a different type. If for example the BoardMember instance in myBoardMember has a FamilyCar as company car set, car is of type FamilyCar. Because the fetch action can result in multiple types, the fetch is called polymorphic. So, in our example, if car is of type FamilyCar, the following code would also be correct:

FamilyCarEntity car = adapter.FetchNewEntity<FamilyCarEntity>(myBoardMember.GetRelationInfoCompanyCar());
Dim car As FamilyCarEntity = adapter.FetchNewEntity(Of FamilyCarEntity)(myBoardMember.GetRelationInfoCompanyCar()))

Would this BoardMember instance have a SportsCar set as company car, this code would fail at runtime with a specified cast not valid exception.

DataAccessAdapter.FetchEntity and inheritance

DataAccessAdapter.FetchEntity() is not polymorphic. This is by design as it fetches the entity data into the passed in entity object. As it's already an instance, it would be impossible to change that instance' type to a derived type if the PK values identify an entity which is of a subtype of the type of the passed in entity instance.

In our previous example about BoardMember and CompanyCar, BoardMember is a derived type of Manager which is a derived type of Employee. If FetchEntity is called by passing in an Employee instance, and the PK identifies a BoardMember, only the Employee's fields are loaded, however if the entity is in a hierarchy of type TargetPerEntity, LLBLGen Pro will perform joins with all subtypes from the supertype, to make sure a type is stored OK.

Info

Be aware of the fact that polymorphic fetches of entities in a TargetPerEntity hierarchy use JOINs between the root entity's target and all subtype targets when the root type is specified for the fetch. This can have an inpact on performance.