Skip to main content
All docs
V24.1

Configure a Many-to-Many Relationship

  • 3 minutes to read

This lesson explains how to create a Many-to-Many relationship between two entities and how XAF generates the UI for such relationships.

Note

Before you proceed, take a moment to review the previous lessons:

Step-by-Step Instructions

  1. In the MySolution.Module\Business Objects folder, create the DemoTask class. Replace the generated class declaration with the code sample below:

    using DevExpress.ExpressApp.Model;
    using DevExpress.Persistent.Base;
    using DevExpress.Persistent.BaseImpl.EF;
    using DevExpress.ExpressApp.DC;
    using System.Collections.ObjectModel;
    
    namespace MySolution.Module.BusinessObjects
    {
        [DefaultClassOptions]
        //Use this attribute to define the name of the objects of this type in the user interface.
        [ModelDefault("Caption", "Task")]
        public class DemoTask : BaseObject
        {
            public virtual DateTime? DateCompleted { get; set; }
    
            public virtual String Subject { get; set; }
    
            [FieldSize(FieldSizeAttribute.Unlimited)]
            public virtual String Description { get; set; }
    
            public virtual DateTime? DueDate { get; set; }
    
            public virtual DateTime? StartDate { get; set; }
    
            public virtual int PercentCompleted { get; set; }
    
            private TaskStatus status;
    
            public virtual TaskStatus Status
            {
                get { return status; }
                set
                {
                    status = value;
                    if (isLoaded)
                    {
                        if (value == TaskStatus.Completed)
                        {
                            DateCompleted = DateTime.Now;
                        }
                        else
                        {
                            DateCompleted = null;
                        }
                    }
                }
            }
    
            [Action(ImageName = "State_Task_Completed")]
            public void MarkCompleted()
            {
                Status = TaskStatus.Completed;
            }
    
            private bool isLoaded = false;
            public override void OnLoaded()
            {
                isLoaded = true;
            }
    
         }
         public enum TaskStatus
         {
             [ImageName("State_Task_NotStarted")]
             NotStarted,
             [ImageName("State_Task_InProgress")]
             InProgress,
             [ImageName("State_Task_WaitingForSomeoneElse")]
             WaitingForSomeoneElse,
             [ImageName("State_Task_Deferred")]
             Deferred,
             [ImageName("State_Task_Completed")]
             Completed
         }
    }
    
  2. Add the Employees collection property to the DemoTask class. This way, you define the first part of the relationship between the DemoTask and Employee entities:

    // ...
    using System.Collections.ObjectModel;
    
    namespace MySolution.Module.BusinessObjects
    {
        [DefaultClassOptions]
        //Use this attribute to define the name of the objects of this type in the user interface.
        [ModelDefault("Caption", "Task")]
        public class DemoTask : BaseObject
        {
            // ...
            public virtual IList<Employee> Employees { get; set; } = new ObservableCollection<Employee>();
    
        }
        // ...
    }
    
  3. Add the Tasks collection to the Employee class implementation:

    // ...
    using System.Collections.ObjectModel;
    //...
    public class Employee : BaseObject {
        public Employee() {
            //...
            public virtual IList<DemoTask> DemoTasks { get; set; } = new ObservableCollection<DemoTask>();
        }
        //...
    }
    

    This declaration of the Tasks collection property completes the relationship. Now the classes reference each other.

  4. Go to the MySolution.Module\MySolutionDbContext file and add a DbSet of the Task type:

    public class MySolutionEFCoreDbContext : DbContext {
       //...
       public DbSet<DemoTask> DemoTasks { get; set; }
    
    }
    
  5. Add a migration and update the database. See the following section for details: Use a DBMS: Setup Migrations.

  6. Run the application.

    In the Employee detail view, the application displays the following elements:

    • A list of assigned tasks.
    • The New button — allows users to add a new assigned task.
    • The Link button — allows users to assign the current employee an existing task.
    ASP.NET Core Blazor
    ASP.NET Core Blazor Collection Property in the UI
    Windows Forms
    Windows Forms Collection Property in the UI

    You can find the same UI in the Tasks detail view.

    ASP.NET Core Blazor
    ASP.NET Core Blazor Collection Property in the UI
    Windows Forms
    Windows Forms Collection Property in the UI

Next Lesson

Implement Reference Properties

See Also