Monday, June 15, 2015

Binding ScheduleView to Database part 6: Resources

The RadScheduleView allows you to define custom resources that can be assigned to the appointments. For example: you can assigned appointment to specific man or specific location.

You can read about Resources in this article writen by Telerik team. The article is very simple, and I recommend to read it before this post. 

But as you can see, the Telerik's article [and other Telerik's samples] defines the resources as in-memory collection, while in the real world we want store the resources in the database.

In this post we will see how to do it, simply and easily.


Let's start with a small diagram.


This diagram shows the Resources schema from database perspective.
The Resources table depends on ResourceTypes table with one-to-many relationship.
The Resources and Appointments tables, has many-to-many relationship, using junction table named "ResourceModelAppointmentModel".

Now, let's define the models.

1. ResourceTypeModel


[Table("ResourceTypes")]
public class ResourceTypeModel : IResourceType
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool AllowMultipleSelection { get; set; }

    [NotMapped]
    public string DisplayName
    {
        get { return this.Name; }
        set { this.Name = value; }
    }

    public virtual List Resources<ResourceModel> { get; set; }

    System.Collections.IList IResourceType.Resources
    {
        get { return this.Resources; }
    }
}



2. ResourceModel


[Table("Resources")]
public class ResourceModel : IResource
{
    public int Id { get; set; }
    public string ResourceName { get; set; }
    public int ResourceTypeId { get; set; }

    [ForeignKey("ResourceTypeId")]
    public virtual ResourceTypeModel ResourceType { get; set; }

    public virtual ICollection<AppointmentModel> Appointments { get; set; }


    [NotMapped]
    public string DisplayName
    {
        get { return this.ResourceName; }
        set { this.ResourceName = value; }
    }

    // It is NOT necessary
    string IResource.ResourceType
    {
        get { return this.ResourceType.Name; }
        set { throw new System.NotImplementedException(); }
    }

    public bool Equals(IResource other)
    {
        ResourceModel resource = other as ResourceModel;

        return resource != null
            && resource.Id == this.Id;
    }
}



3. Changes in AppointmentModel


//ctor
public AppointmentModel()
{
    this.Resources = new List();
}

public virtual List<ResourceModel> Resources { get; set; }

IList IAppointment.Resources
{
    get { return this.Resources; }
}



4. Add entities to the context


public DbSet ResourceTypes<ResourceTypeModel> { get; set; }
public DbSet Resources<ResourceModel> { get; set; }



5. Migration

Add-migration, and update database. Entity-framework will create for you three tables. two for new types, and another one as junction table between Resources & Appointments.

It may be useful to insert default resources by Seed method in Configuration class:

protected override void Seed(SchedulingDbContext context)
{
    ...... 

    context.ResourceTypes.AddOrUpdate(
        type => type.Name,
        new ResourceTypeModel()
        {
            Name = "Room",
            Resources = new List<ResourceModel>
            {
                new ResourceModel(){ResourceName = "Room1"},
                new ResourceModel(){ResourceName = "Room2"}
            }
        },
        new ResourceTypeModel()
        {
            Name = "Agent",
            Resources = new List<ResourceModel>
            {
                new ResourceModel(){ResourceName = "John"},
                new ResourceModel(){ResourceName = "Scott"}
            }
        }
        );
}



6. MainViewModel


public ObservableCollection<ResourceTypeModel> ResourceTypes
{
    get
    {
        context.ResourceTypes.Load();
        return context.ResourceTypes.Local;
    }
}



7. MainWindow


<telerik:RadScheduleView AppointmentsSource="{Binding Appointments,Mode=OneTime}"
                            CategoriesSource="{Binding Categories,Mode=OneTime}"
                            ResourceTypesSource="{Binding ResourceTypes,Mode=OneTime}"
                            VisibleRangeChangedCommand="{Binding LoadAppointmentsCommand}"
                            VisibleRangeChangedCommandParameter="{Binding VisibleRange, RelativeSource={RelativeSource Self}}"
                            Grid.Row="0">




That's it!

No comments:

Post a Comment