Skip to main content
All docs
V23.2

Load Objects

  • 6 minutes to read

In your business logic you may need to fetch another object or a collection of objects to calculated values based on that object properties. You can implement the logic to obtain an existing object in a Controller or in a business class.

Load Objects in a Controller

Useful API

Object Space exposes the following methods to find an existing object.

IObjectSpace.FirstOrDefault<ObjectType>
Searches for the first object that matches the specified lambda expression. The generic parameter determines the object’s type.
IObjectSpace.FindObject
Searches for the first object that matches the specified criteria and is of the specified type.
IObjectSpace.FindObject<ObjectType>
Searches for the first object that matches the specified criteria. The object’s type is designated by the specified generic type parameter.
IObjectSpace.GetObject
Retrieves an object that corresponds to an IObjectRecord wrapper or object from another Object Space.
IObjectSpace.GetObjectByKey
Returns the persistent object that has the specified value for its key property.
IObjectSpace.GetObjectByKey<ObjectType>
Returns a persistent object of the type designated by the specified generic type parameter, with the specified value for its key property.
IObjectSpace.GetObjectByHandle
Returns the object with the specified handle.
IObjectSpace.IsObjectFitForCriteria
Specifies whether a particular object satisfies the specified criteria.

The following Object Space methods return a collection of objects.

IObjectSpace.GetObjects
Retrieves objects of the specified type from the current Object Space. Returns an IList collection.
IObjectSpace.GetObjects<T>
Retrieves objects of the specified type from the current Object Space. Returns an IList collection.
IObjectSpace.CreateCollection
Creates and initializes a collection of objects of the specified type, filtered according to the specified criteria and sorted according to the given sorting list.
IObjectSpace.GetObjectsQuery<T>
Gets a queryable data structure that provides functionality to evaluate queries against a specific business object type.

The following example uses a Parametrized Action to search for a Person by LastName, and then assigns all deferred tasks to that person.

using System.Collections;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.Base.General;
using DevExpress.Persistent.BaseImpl;
// ...
public class AssignTasksController : ObjectViewController<ListView, MainDemo.Module.BusinessObjects.DemoTask> {
    public AssignTasksController() {
        ParametrizedAction assignTasksAction = new ParametrizedAction(
            this, "AssignTasks", PredefinedCategory.Edit, typeof(string));
        assignTasksAction.Execute += AssignTasksAction_Execute;
    }
    private void AssignTasksAction_Execute(object sender, ParametrizedActionExecuteEventArgs e) {
        IObjectSpace objectSpace = View.ObjectSpace;
        string personParamValue = e.ParameterCurrentValue as string;
        CriteriaOperator personCriteria = CriteriaOperator.Parse("Contains([LastName], ?)", personParamValue);
        Person person = (Person)objectSpace.FindObject(typeof(Person), personCriteria);
        if(person != null) {
            CriteriaOperator taskCriteria = CriteriaOperator.Parse("[Status] = ?", TaskStatus.Deferred);
            IList tasks = objectSpace.GetObjects(
                typeof(MainDemo.Module.BusinessObjects.DemoTask), taskCriteria);
            foreach(MainDemo.Module.BusinessObjects.DemoTask task in tasks) {
                task.AssignedTo = person;
            }
        }
    }
}

You can use the IObjectSpace.GetObjectsQuery<T> method to load objects. It allows you to use LINQ expressions to specify the required request.

IQueryable<Product> query = this.ObjectSpace.GetObjectsQuery<Product>();

Business logic can depend on a number of records in a database. In this scenario, use the IObjectSpace.GetObjectsCount method to get a number of records without fetching records.

In a Data Model (in an XPO Business Class)

An XPO Session available via the Session property in a business class implements methods to find and read an object from a database.

The following code snippet demonstrates how to initialize Employee‘s Address1 and Manager reference properties with new and existing objects:

File: MySolution.Module\BusinessObjects\Contact.cs(.vb)

using DevExpress.Data.Filtering;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Xpo;
// ...
public class Employee : Person {
    //...
    public override void AfterConstruction() {
        base.AfterConstruction();
        Address1 = new Address(Session);
        Address1.Country = Session.FindObject<Country>(CriteriaOperator.Parse("Name = 'USA'"));
        if(Address1.Country == null) {
            Address1.Country = new Country(Session);
            Address1.Country.Name = "USA";
        }
        Manager = Session.FindObject<Employee>(CriteriaOperator.Parse(
            "FirstName = 'John' && LastName = 'Doe'"));
    }
}

To get a collection of objects in an XPO business class, instantiate a new XPCollection.

using DevExpress.Persistent.BaseImpl;
using DevExpress.Xpo;
// ...
public class Order : BaseObject {    
    private XPCollection<Accessory> fAvailableAccessories;
    public XPCollection<Accessory> AvailableAccessories {
        get {
            if (fAvailableAccessories == null) {
                fAvailableAccessories = new XPCollection<Accessory>(Session);
            }
            return fAvailableAccessories;
        }
    }
}

public class Accessory : BaseObject { }

It’s possible to use the Session methods like GetObjects to fetch a collection of objects.

In an EF Core Business Class

Inside an EF Core business class, implement the IObjectSpaceLink interface in the class. XAF will automatically assign an Object Space instance to the IObjectSpaceLink.ObjectSpace property. Use the assigned Object Space APIs listed above to get an existing object.

The following code snippet demonstrates how to initialize the Address1 reference property with a new or existing object:

File: MySolution.Module\BusinessObjects\Employee.cs

using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl.EF;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YourSolutionName.Module.BusinessObjects;
[DefaultClassOptions]
public class Employee : IXafEntityObject {
    [Key]
    public virtual Guid ID { get; set; }

    public virtual string Manager { get; set; }
    public void OnCreated() {
        // ...
        var address = ObjectSpace.FindObject<Address>(CriteriaOperator.FromLambda<Address>(a => a.Country == "USA"));
        if(address == null) {
            address = ObjectSpace.CreateObject<Address>();
            address.Country = "USA";
        }
        Address1 = address;
    }
    public virtual Address Address1 { get; set; }
    public void OnLoaded() { }
    public void OnSaving() { }
    public IObjectSpace ObjectSpace {
        get {
            return ((IObjectSpaceLink)this).ObjectSpace;
        }
    }
}
[DefaultClassOptions]
[DefaultProperty(nameof(Country))]
public class Address : BaseObject {
    public virtual string Country { get; set; }
    // ...
}
// Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.

Alternatively, you can inherit your class from the DevExpress.Persistent.BaseImpl.EF.BaseObject class as follows:

using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl.EF;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YourSolutionName.Module.BusinessObjects;
[DefaultClassOptions]
public class Employee : BaseObject {
    public virtual string Manager { get; set; }
    public override void OnCreated() {
        // ...
        var address = ObjectSpace.FindObject<Address>(CriteriaOperator.FromLambda<Address>(a => a.Country == "USA"));
        if(address == null) {
            address = ObjectSpace.CreateObject<Address>();
            address.Country = "USA";
        }
        Address1 = address;
    }
    public virtual Address Address1 { get; set; }

}
[DefaultClassOptions]
[DefaultProperty(nameof(Country))]
public class Address : BaseObject {
    public virtual string Country { get; set; }
    // ...
}


// Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.