# Setting Appointment and Resource Relations

## One to Many Relations

This covers the case of assigning a single resource to many appointments. When you have a two table relation (one to many) then you should have an *Appointments* and a *Resources* tables. *Appointments* should have a field name that relates to the *Resources* table id (for example **ResourceId**). If you set a resource to the appointment, the **ResourceId** field should be updated with the correct value. For **AppointmentMappingInfo** you should set the **ResourceId** field with the column name that contains the resosurce id (the **ResourceId** column in the picture below). The *Resources* field of the **AppointmentMappingInfo** should NOT be set to anything.

> caption Figure 1: One to Many Relation

![WinForms RadScheduler One to Many Relation](https://www.telerik.com/products/winforms/documentation/assets/3bc9db3db37da278f48943a7c5308fb7/scheduler-data-binding-setting-appointment-and-resource-relations001.png)

Additionally, since the type of the **ResourceId** property in the **Appointment** class is of type **EventId** but in the database it is stored as an integer, you should create the following convert methods:

#### Convert Methods

```C#
private void SettingAppointmentAndResourceRelations_Load(object sender, EventArgs e)
{
    // TODO: This line of code loads data into the 'schedulerDataOneToManyDataSet.Resources' table. You can move, or remove it, as needed.
    this.resourcesTableAdapter.Fill(this.schedulerDataOneToManyDataSet.Resources);
    // TODO: This line of code loads data into the 'schedulerDataOneToManyDataSet.Appointments' table. You can move, or remove it, as needed.
    this.appointmentsTableAdapter.Fill(this.schedulerDataOneToManyDataSet.Appointments);

    AppointmentMappingInfo appointmentMapping = new AppointmentMappingInfo();
    ResourceMappingInfo resourceMapping = new ResourceMappingInfo();

    appointmentMapping.Start = "Start";
    appointmentMapping.End = "End";
    appointmentMapping.Summary = "Summary";
    appointmentMapping.Description = "Description";
    appointmentMapping.Location = "Location";
    appointmentMapping.BackgroundId = "BackgroundID";
    appointmentMapping.StatusId = "StatusID";
    appointmentMapping.RecurrenceRule = "RecurrenceRule";
    appointmentMapping.ResourceId = "ResourceID";

    appointmentMapping.FindBySchedulerProperty("ResourceId").ConvertToDataSource = ConvertResourceToDataSource;
    appointmentMapping.FindBySchedulerProperty("ResourceId").ConvertToScheduler = ConvertResourceToScheduler;

    resourceMapping.Name = "ResourceName";
    resourceMapping.Id = "ID";

    this.schedulerBindingDataSource1.ResourceProvider.Mapping = resourceMapping;
    this.schedulerBindingDataSource1.ResourceProvider.DataSource = this.schedulerDataOneToManyDataSet.Resources;

    this.schedulerBindingDataSource1.EventProvider.Mapping = appointmentMapping;
    this.schedulerBindingDataSource1.EventProvider.DataSource = this.schedulerDataOneToManyDataSet.Appointments;

    this.radScheduler1.DataSource = this.schedulerBindingDataSource1;
    this.radScheduler1.GroupType = GroupType.Resource;

}

private object ConvertResourceToScheduler(object item)
{
    return new EventId(item);
}

private object ConvertResourceToDataSource(object item)
{
    EventId resourceId = item as EventId;
    if (item != null && resourceId.KeyValue is int)
    {
        return resourceId.KeyValue;
    }

    return DBNull.Value;
}
```

```VB.NET
Private Sub SettingAppointmentAndResourceRelations_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    'TODO: This line of code loads data into the 'SchedulerDataOneToManyDataSet.Resources' table. You can move, or remove it, as needed.
    Me.ResourcesTableAdapter.Fill(Me.SchedulerDataOneToManyDataSet.Resources)
    'TODO: This line of code loads data into the 'SchedulerDataOneToManyDataSet.Appointments' table. You can move, or remove it, as needed.
    Me.AppointmentsTableAdapter.Fill(Me.SchedulerDataOneToManyDataSet.Appointments)

    Dim appointmentMapping As New AppointmentMappingInfo()
    Dim resourceMapping As New ResourceMappingInfo()

    appointmentMapping.Start = "Start"
    appointmentMapping.[End] = "End"
    appointmentMapping.Summary = "Summary"
    appointmentMapping.Description = "Description"
    appointmentMapping.Location = "Location"
    appointmentMapping.BackgroundId = "BackgroundID"
    appointmentMapping.StatusId = "StatusID"
    appointmentMapping.RecurrenceRule = "RecurrenceRule"
    appointmentMapping.ResourceId = "ResourceID"

    appointmentMapping.FindBySchedulerProperty("ResourceId").ConvertToDataSource = AddressOf ConvertResourceToDataSource
    appointmentMapping.FindBySchedulerProperty("ResourceId").ConvertToScheduler = AddressOf ConvertResourceToScheduler

    resourceMapping.Name = "ResourceName"
    resourceMapping.Id = "ID"

    Me.SchedulerBindingDataSource1.ResourceProvider.Mapping = resourceMapping
    Me.SchedulerBindingDataSource1.ResourceProvider.DataSource = Me.SchedulerDataOneToManyDataSet.Resources

    Me.SchedulerBindingDataSource1.EventProvider.Mapping = appointmentMapping
    Me.SchedulerBindingDataSource1.EventProvider.DataSource = Me.SchedulerDataOneToManyDataSet.Appointments

    Me.RadScheduler1.DataSource = Me.SchedulerBindingDataSource1
    Me.RadScheduler1.GroupType = GroupType.Resource

End Sub

Private Function ConvertResourceToScheduler(ByVal item As Object) As Object
    Return New EventId(item)
End Function

Private Function ConvertResourceToDataSource(ByVal item As Object) As Object
    Dim resourceId As EventId = TryCast(item, EventId)
    If Not item Is Nothing AndAlso TypeOf resourceId.KeyValue Is Integer Then
        Return resourceId.KeyValue
    End If

    Return DBNull.Value
End Function
```

> important A common case is that the resource_id field is stored as an integer field in your DataSource. But **RadScheduler** needs **EventId** type. You can have a look at the Appointment.**ResourceId** property which expects **EventId** value, not an integer. That is why it is necessary to use a **SchedulerMapping** in this case and convert the integer value to **EventId** used by **RadScheduler** and convert the **EventId** to an integer used by your **DataSource**. This conversion is performed by the **ConvertToDataSource** and **ConvertToScheduler** callbacks. Additional information for the **SchedulerMapping** is available [here](https://www.telerik.com/products/winforms/documentation/controls/scheduler/data-binding/scheduler-mapping)

## Many to Many Relations

This covers the case of assigning many resources to many appointments. When you have relations between three tables (many to many) then you should have three tables: *Appointments*, *Resources* and  *AppointmentsResources*. *AppointmentResouces* should have two field names: one for the id of the appointment (**AppointmentId**), and one for id of the resource (**ResourceId**). Here we should have two relations: one between *Appointments* and *AppointmentsResources*, and one between *Resources* and *AppointmentsResources*.

For the **AppointmentMappingInfo** you should set the **ResourceId** property to the **ResourceId** field name in the *AppointmentsResources* table, and for the **Resources** you should set the name of the relation between \*AppointmentsResources \*and *Appointments*. When you associate the resource to the appointment, a new record will be added to *AppointmentsResources* if there is not such.

This scenario is also demonstrated in the [Data Binding Walkthrough article](https://www.telerik.com/products/winforms/documentation/controls/scheduler/data-binding/data-binding-walkthrough).

> caption Figure 2: Many to Many Relation

![WinForms RadScheduler Many to Many Relation](https://www.telerik.com/products/winforms/documentation/assets/21cd29dee1cc4d961b22fddb5bea7f3a/scheduler-data-binding-setting-appointment-and-resource-relations002.png)

> important As of **R1 2021** the EditAppointmentDialog provides UI for selecting multiple resources per appointment. In certain cases (e.g. unbound mode), the *Resource* **RadDropDownList** is replaced with a **RadCheckedDropDownList**. Otherwise, the default drop down with single selection for resources is shown. To enable the multiple resources selection in bound mode, it is necessary to specify the AppointmentMappingInfo. **Resources** property. The **Resources** property should be set to the name of the relation that connects the **Appointments** and the **AppointmentsResources** tables.

#### EditAppointmentDialog with multiple resources

![WinForms RadScheduler EditAppointmentDialog with multiple resources](https://www.telerik.com/products/winforms/documentation/assets/3499872d18522eb49ce46b4177c06e02/scheduler-winforms-scheduler-dialogs-editappointmentdialog003.png)

## See Also

* [Design Time](https://www.telerik.com/products/winforms/documentation/controls/scheduler/design-time/smart-tag)
* [Views](https://www.telerik.com/products/winforms/documentation/controls/scheduler/views/overview-and-structure)
* [Scheduler Mapping](https://www.telerik.com/products/winforms/documentation/controls/scheduler/data-binding/scheduler-mapping)
* [Working with Resources](https://www.telerik.com/products/winforms/documentation/controls/scheduler/data-binding/working-with-resources)
