Forums
Forums are Read-Only. Use the new Support Center. To start a general discussion, use the General category when submitting your question.

Loading a subset of appointments based on selected time interval, rather than all appointments

Last post 3/29/2012 3:44 PM by Ajay Singh Dhangar. 24 replies.
1 2 Next
Sort Posts: Previous Next
  • Ben Powell

    Loading a subset of appointments based on selected time interval, rather than all appointments

    4/11/2008 1:51 AM
    • Not Ranked
    • Joined on 4/4/2008
    • Posts 9

    The ASPxScheduler appears to be designed so that you must load all your appointments into its storage engine. From storage engine, the control will then filter those appointments based on the current ActiveView. That is great if you have 10 appointments, but what about large appointment datasets? What about 5 years of appointments? What about hundreds of thousands of appointments? Based on their own examples, the easiest way to do this is to restrict the user to a large enough dataset to be useful, without pulling too much data (e.g. the current week or month), but that isn't exactly flexible. It also means you are loading data unnecessarily, assuming most users might only view today's appointments when you loaded a month's worth of appointments.

    Using the ListBoundMode demo as a base, I have altered their call into their random data generator, and pulled data from my own database instead. I used custom object collections as they suggest (see code  below).

    Now, to get the selected start and end dates, you would think it would be fairly simple. Specifically I need to know the following two dates to be able to load my data:

    • the start datetime value of the user's current view
    • the end datetime value of the user's current view

    The problem is that I simply CANNOT find these values during this stage of the control's lifecycle. Hence, when I call LoadCustomEventList(), though I can get the previously selected dates (from the previous postback), I cannot get the newly selected time interval. Does anyone know which properties might hold this information, and at this point in the conrol's lifecycle? I've meandered though the debugger, but I can't find anything useful.

    There is of course another event that might be useful: the OnActiveViewChanged event. However, this gets called after my ObjectDataSet has been created, so my only option is to reload the data based on the newly selected start and end date (which is now correctly available). The problem with this is that you end up loading two sets of data, the first being a waste of time.

    I simply cannot make sense of this control. If I load all the appointments in my database, I'll get ~10,000 appointments per user group, which based on their own example, gets stored in a session value and reloaded every postback or callback. With 500 concurrent users, that is pretty quickly going to kill our servers.

    We are evaluating this control in comparison to Infragistics (which is also pretty fiddly to work with), but if I can't solve this one, we'll have to go back to Infragistics.

    I welcome any suggestions.

    Regards

    Ben

    P.S. I tried out FetchAppointments already, but it gets called multiple times.

    Anyway, code is here:

    protected void appointmentsDataSource_ObjectCreated(object sender, ObjectDataSourceEventArgs e)
    {
        e.ObjectInstance = new CustomEventDataSource(GetCustomEvents());
    }

    private CustomEventList GetCustomEvents()
    {
        /*CustomEventList events = Session["CustomEventList"] as CustomEventList;
        if (events == null)
        {
            events = LoadCustomEventList();
            Session["CustomEventList"] = events;
        }
        return events;*/
        return LoadCustomEventList();
    }

    private CustomEventList LoadCustomEventList()
    {

        DateTime dtStart = this.ASPxScheduler1.ActiveView.GetVisibleIntervals().Start; // This gives the wrong value
        DateTime dtEnd = this.ASPxScheduler1.ActiveView.GetVisibleIntervals().End; // This gives the wrong value

        List<Appointment> entities = AppointmentBusinessService.Instance.Find(dtStart, dtEnd);

        CustomEventList events = new CustomEventList();
        foreach (Appointment entity in entities)
        {
            CustomEvent evt = new CustomEvent();
            evt.Id = entity.AppointmentId;
            evt.AppointmentId = entity.AppointmentId;
            evt.StartTime = entity.DateStart;
            evt.EndTime = entity.DateEnd;
            evt.EventType = 0; // Normal

            evt.Label = 0; // Different types different colours
            TimeSpan ts = entity.DateEnd - entity.DateStart;
            evt.AllDay = (ts.TotalDays > 1) ? true : false;

            evt.Location = "No location";
            evt.Subject = entity.EventTypeText;
            evt.Status = 1;
            evt.Description = "None";

            // Get users
            CustomResourceList assigned = new CustomResourceList();
            foreach (AppointmentUserAccount account in entity.AppointmentUserAccountCollection)
            {
                UserAccount acc = UserBusinessService.Instance.GetByUserAccountId(account.UserAccountId);
                CustomResource user = new CustomResource();
                user.Id = acc.UserAccountId;
                user.ResourceId = acc.UserAccountId;
                user.ResourceName = acc.DisplayTitle;
                assigned.Add(user);
            }
            evt.Resources = assigned;

            events.Add(evt);
        }

        return events;
    }

    protected void ASPxScheduler1_ActiveViewChanged(object sender, EventArgs e)
    {
        this.ASPxScheduler1.DataBind();
    }

  • Sandra Llewellyn

    Re: Loading a subset of appointments based on selected time interval, rather than all appointments

    9/2/2008 9:14 PM
    • Not Ranked
    • Joined on 7/10/2008
    • Posts 19

    Did you ever manage to sort this out?  We have an almost identical scenario (we are binding to a objectdatasource and want to filter out the data at the SQL Server level rather than return 1000s of records to the Storage etc etc).

    We have used ASPxScheduler1.ActiveView.GetVisibleIntervals() to determine the start and end dates on the current view.  However, how does one get the newly selected time interval in the page cycle before the ObjectDataSource retrieves data from the underlying datasource?

    Can someone from Devexpress please enlighten us? 

    Regards

    Myles Johnson

     

  • Ben Powell

    Re: Loading a subset of appointments based on selected time interval, rather than all appointments

    9/3/2008 5:33 AM
    • Not Ranked
    • Joined on 4/4/2008
    • Posts 9

    Hi Miles,

    We ended up with a method that takes a start and end date, and returning the data based on the currently selected timeframe of the diary.

    We couldn't find an elegant solution in the end. The events exposed by the scheduler aren't logical, and we wasted a great deal of time trying to get this to work. DevExpress support tried to help as much as they could, but the bottom line is that the scheduler just isn't designed to load appointments on demand.

    We finally settled on the using the ActiveViewChanged and VisibleIntervalChanged events handlers. DevExpress suggested the use of the FetchAppointments event handler, but we found that this was called multiple times throughout the page life cycle. The events we hooked into aren't ideal, because they are called twice (note, if the DateNavigator BoldAppointments flag is set, these calls are even more numerous to FetchAppointments).

    We concluded that the control's problem, was not just that the events didn't seem to be well thought out, but that the control lifecycle was out of wack as well. We struggled to find a single DevExpress exposed event, that not only had the appropriate (and correct) selected timespan, and was called only once. There isn't one we could find. If you use events that are called once, such as OnLoad, you'll find that as the ActiveView changes (say day view from 17th to 18th), the dates selected in the ActiveView properties are still set to the previous dates (17th). The REAL changed dates aren't available until the ActiveViewChanged event is called. If you change the view type (e.g. day to week), the problem is the same, VisibleIntervalChanged is the event you need, but of course the ActiveViewChanged event also fires. Nightmare...

    We had simple requirements for a diary control:

    • Take the following as inputs: Start DateTime, End DateTime
    • Load appointments for the selected dates
    • Work with MVC / MVP patterns (no ObjectDataSource as it breaks our architecture rules)
    • Does not use Session state as part of the solution

    DevExpress has forced us down the ODS route, and we had to hack everything around to cope with this. Our design pattern uses getters and setters between the ASPX page and a presentation layer. Hence, our presenter sets a datasource value in the ASPX page. We would usually bind this result to a control, but with the scheduler you can't do that. Instead you need to hook into the ODS ObjectCreated and set the ObjectInstance to your datasource.

    Good luck. Let me know if you have any success. We'ed love to be able to use the controls, if only we could find an effective solution.

    For reference, our support queries were:

    Although these support questions are closed, none reached a conclusion we were happy with, and in truth I gave up trying to explain myself. It appears our architecture strayed from the DevExpress path....

    Regards

    Ben

    P.S. PreRender seemed like a good event to use to load the subset, in that only seemed to be called once. If you just want to display events, and not be able to do anything with them, then you can use this event to load your subset. However, if you want to do anything with these events (open them, edit them) then PreRender is too late in the control's lifecycle, hence all of the events such as AppointmentChanging (e.g. for changing the start and end time of an event), will never be called, because at that point in time when the event should be called, there are no events in the scheduler's storage mechanism.

  • Sandra Llewellyn

    Re: Loading a subset of appointments based on selected time interval, rather than all appointments

    9/4/2008 1:17 AM
    • Not Ranked
    • Joined on 7/10/2008
    • Posts 19

    Thanks for this Ben.  It sounds like I have been sharing your pain.

    I too have been forced to implement a similar less than satisfactory solution.

    The problem outlined in this post indicates that the controls architecture lacks scalability.  If Devexpress are serious about the future of this control then surely they need to address it as a high priority? 

    Regards

    Myles

  • Sandra Llewellyn

    Re: Loading a subset of appointments based on selected time interval, rather than all appointments

    9/8/2008 7:24 PM
    • Not Ranked
    • Joined on 7/10/2008
    • Posts 19

    OK it looks like we may have a solution for read only schedules i.e. updates and deletes are disabled.  We are still figuring out how this could possibly work if we need to enable updates (e.g. drag and drop) and deletes on the control.  The solution obviously fails for updates as the visible interval doesn't change for these events.  Here is a cut down version of our code:

            protected void Page_Load(object sender, EventArgs e)
            {

               private DateTime _lastStartDt;
               private DateTime _lastEndDt;

                if (Page.IsCallback)
                {
                    _lastStartDt = ASPxScheduler1.ActiveView.GetVisibleIntervals().Start;
                    _lastEndDt = ASPxScheduler1.ActiveView.GetVisibleIntervals().End;
                }

                //Wire up the required scheduler events

                ASPxScheduler1.AppointmentRowUpdated += new ASPxSchedulerDataUpdatedEventHandler(ASPxScheduler1_AppointmentRowUpdated);
                ASPxScheduler1.AppointmentChanging += new PersistentObjectCancelEventHandler(ASPxScheduler1_AppointmentChanging);
                ASPxScheduler1.ActiveViewChanging += new ActiveViewChangingEventHandler(ASPxScheduler1_ActiveViewChanging);
                ASPxScheduler1.FetchAppointments += new FetchAppointmentsEventHandler(ASPxScheduler1_FetchAppointments); ;

                //Wire up the required ODS events


                ObjectDataSource1.ObjectCreated += new ObjectDataSourceObjectEventHandler(ObjectDataSource1_ObjectCreated);
                ObjectDataSource1.Inserting += new ObjectDataSourceMethodEventHandler(ObjectDataSource1_Inserting);
                ObjectDataSource1.Inserted += new ObjectDataSourceStatusEventHandler(ObjectDataSource1_Inserted);
                ObjectDataSource1.Updating += new ObjectDataSourceMethodEventHandler(ObjectDataSource1_Updating);
                ObjectDataSource1.Updated += new ObjectDataSourceStatusEventHandler(ObjectDataSource1_Updated);
                ObjectDataSource1.Deleting += new ObjectDataSourceMethodEventHandler(ObjectDataSource1_Deleting);
                ObjectDataSource1.Deleted += new ObjectDataSourceStatusEventHandler(ObjectDataSource1_Deleted);
                ObjectDataSource1.Selecting += new ObjectDataSourceSelectingEventHandler(ObjectDataSource1_Selecting);
                ObjectDataSource1.Selected += new ObjectDataSourceStatusEventHandler(ObjectDataSource1_Selected);
                ObjectDataSource1.DataObjectCreated += new ObjectDataSourceDataObjectEventHandler(ObjectDataSource1_DataObjectCreated);
                ObjectDataSource1.DataBinding += new EventHandler(ObjectDataSource1_DataBinding);

            }

            void ASPxScheduler1_FetchAppointments(object sender, FetchAppointmentsEventArgs e)
            {
                DateTime startDt = e.Interval.Start;
                DateTime endDt = e.Interval.End;

                if ((!(startDt == _lastStartDt)) || (!(endDt == _lastEndDt)))
                {
                    _lastStartDt = startDt;
                    _lastEndDt = endDt;

                    SetupMappings();
                    SetupCustomMappings();

                    ASPxScheduler1.AppointmentDataSource = ObjectDataSource1;
                    ASPxScheduler1.DataBind();
                }
            }

            void ObjectDataSource1_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
            {
                e.InputParameters.Add("startDt", _lastStartDt);
                e.InputParameters.Add("endDt", _lastEndDt); 
            }

     

    Regards,

    Myles Johnson

     

    Filed under:
  • Sandra Llewellyn

    Re: Loading a subset of appointments based on selected time interval, rather than all appointments

    9/8/2008 11:24 PM
    • Not Ranked
    • Joined on 7/10/2008
    • Posts 19

     So the question remains.......how does one implement loading a subset of appointments when the Schedule control has to cater for updates.

    We look forward to a response from DevExpress................

     

  • Brian (DevExpress)

    Re: Loading a subset of appointments based on selected time interval, rather than all appointments

    9/18/2008 8:22 AM
    • Top 50 Contributor
    • Joined on 4/23/2007
    • Posts 546

     Hello,

    you've touched upon interesting issues. We believe that this discussion can be quite informative and useful. Please review the example E489 Use FetchAppointments event for handling large appointment sets. Your comments are greatly appreciated!

    Regards, Brian.
    R&D, .NET Team, Developer Express Inc.
  • Sandra Llewellyn

    Re: Loading a subset of appointments based on selected time interval, rather than all appointments

    9/19/2008 1:54 AM
    • Not Ranked
    • Joined on 7/10/2008
    • Posts 19

    I think this example is pretty pointless.  Rather than retrieving one excessive amount of data each time the active view changes this example (E489) retrieves two small amounts of data i.e. Two database calls every time the active view changes.  One call to retrieve data for the old duration and one to retrieve data for the new duration.  Why isn't it possible to simply make just one call to the backend database to retrieve the correct amount of data e.g. the date range of the new active view?  When the active view of the Scheduler is changing why should it need to retrieve data for the old active view?

     

  • Brian (DevExpress)

    Re: Loading a subset of appointments based on selected time interval, rather than all appointments

    9/19/2008 3:19 AM
    • Top 50 Contributor
    • Joined on 4/23/2007
    • Posts 546

     I believe this example describes everything that is required to implement the task. It shows exactly what we wanted to illustrate - a performance gain achieved due to FetchAppointments event handling using a custom data source.

    Concerning two data calls - one shouldn't consider a call for retrieving data for the previous view as excessive. It is necessary for restoring the control's state before a callback is sent and, therefore, we cannot avoid it.

    Regards, Brian.
    R&D, .NET Team, Developer Express Inc.
  • Ben Powell

    Re: Loading a subset of appointments based on selected time interval, rather than all appointments

    1/17/2009 7:50 AM
    • Not Ranked
    • Joined on 4/4/2008
    • Posts 9

    1 year later and we are still struggling to use the ASPxScheduler. Everything about it is overly complicated. How difficult can it be to have a List of events and resources and bind them to a control? All we need is to load new data from the database when the selected dates or resources are changed. ObjectDataSources are a pig to work with, and break tiered development methodology. Our development model does not give us direct access to our data layer, so at the moment we have to play along with the ObjectDataSource and inject the data into it, just to get the control to semi-work. All I want is this:

    void Page_Load(object sender, EventArgs e)
    {
    ClaimEventBusinessService service = new ClaimEventBusinessService();
    TList<ClaimEvent> events = service.Find(this.fetchInterval.Start, this.fetchInterval.End);
    this.SetMappings(this.ASPxScheduler1);
    this.ASPxScheduler1.AppointmentDataSource = new DiaryEventDataSource(events);
    this.ASPxScheduler1.DataBind();
    }

    Instead I have reems of extra code to work around the ObjectDataSource. We just want to load the data once, and only the data that is needed, based on the dates active in the control display and the resources that are visible.

    I understand why the storage concept works for Windows Forms, but for the web it simply is a worthless layer. All we are doing is reloading the data in the storage every time the page loads.

    Arrrrrrrrrrrrgh!

    Filed under:
  • James Frank

    Re: Loading a subset of appointments based on selected time interval, rather than all appointments

    3/19/2009 12:03 PM
    • Not Ranked
    • Joined on 11/8/2008
    • Posts 3

     Why not just limit the number of appointments and resources loaded with your database query? Something like this:

                Dim sbApptsQuery As New StringBuilder
                Dim sbResourceQuery As New StringBuilder
                Dim startdate As Date
                Dim enddate As Date

                sbResourceQuery.Length = 0
                sbResourceQuery.Append("SELECT ")
                sbResourceQuery.Append(Mid(SiteGlobals.Resources_SQLInsertPrefix, 26, ((SiteGlobals.Resources_SQLInsertPrefix.Length - 10) - 26)))
                sbResourceQuery.Append(" FROM [Resources] WHERE [ResourceID] LIKE '")

                sbApptsQuery.Length = 0
                sbApptsQuery.Append("SELECT ")
                sbApptsQuery.Append(Mid(SiteGlobals.Appointments_SQLInsertPrefix, 29, ((SiteGlobals.Appointments_SQLInsertPrefix.Length - 10) - 29)))
                sbApptsQuery.Append(" FROM [Appointments] WHERE [ResourceID] LIKE '")
                If Session("SelectedAgencyID") = -1 Then
                    sbApptsQuery.Append("%'")
                    sbResourceQuery.Append("%'")
                Else
                    sbApptsQuery.Append(Session("SelectedAgencyID").ToString)
                    sbResourceQuery.Append(Session("SelectedAgencyID").ToString)
                    If Session("SelectedSiteID") = -1 Then
                        sbApptsQuery.Append("-%'")
                        sbResourceQuery.Append("-%'")
                    Else
                        sbApptsQuery.Append("-")
                        sbApptsQuery.Append(Session("SelectedSiteID").ToString)
                        sbApptsQuery.Append("-%'")
                        sbResourceQuery.Append("-")
                        sbResourceQuery.Append(Session("SelectedSiteID").ToString)
                        sbResourceQuery.Append("-%'")
                    End If
                End If
                startdate = Session("ApptsFilterStartDate")
                enddate = Session("ApptsFilterEndDate")
                If (Not startdate = Nothing) And (Not enddate = Nothing) Then
                    sbApptsQuery.Append(" AND [StartDate] BETWEEN '" & Format(startdate.Date, "yyyy/MM/dd") & "' AND '" & Format(enddate.Date.AddDays(1), "yyyy/MM/dd") & "'")
                End If
                sbApptsQuery.Append(" ORDER BY [StartDate] ASC")
                SqlDataSourceAppointments.SelectCommand = sbApptsQuery.ToString
                SqlDataSourceAppointments.ConnectionString = ConfigurationManager.ConnectionStrings("Scheduler").ConnectionString
                SqlDataSourceAppointments.DataBind()

                SqlDataSourceResources.SelectCommand = sbResourceQuery.ToString
                SqlDataSourceResources.ConnectionString = ConfigurationManager.ConnectionStrings("Scheduler").ConnectionString
                SqlDataSourceResources.DataBind()

                ASPxScheduler1.AppointmentDataSource = SqlDataSourceAppointments
                ASPxScheduler1.ResourceDataSource = SqlDataSourceResources
                ASPxScheduler1.DataBind()

  • Aaron Smith

    Re: Loading a subset of appointments based on selected time interval, rather than all appointments

    9/21/2009 2:46 PM
    • Top 500 Contributor
    • Joined on 5/4/2007
    • Posts 48

    I'm going to be a pain in someone's backside and resurrect this thread.

    I do not have any access to the SQL Server. I cannot use ObjectDataSources. I connect to a WCF service and every single one of my bindings are to either generic collections or bindinglists. I am having all sorts of problems with this control because of the way it fetches data multiple times and I can never find a good spot to do a DataBind and get it to work every time in every scenario. Now that I've added a couple ASPxCallbackPanels it has made it even worse...

  • Aaron Smith

    Re: Loading a subset of appointments based on selected time interval, rather than all appointments

    9/21/2009 5:55 PM
    • Top 500 Contributor
    • Joined on 5/4/2007
    • Posts 48

    I retract my previous post. I sorted out all my issues including being able to get rid of the FetchAppointments event while still only connecting to my lists of custom objects.

  • Marc Greiner [DX-Squad]

    Re: Loading a subset of appointments based on selected time interval,rather than all appointments

    9/22/2009 6:55 PM
    • Top 25 Contributor
    • Joined on 5/4/2007
    • France
    • Posts 1,195
    Hi Aaron ;

    Do you mean that you found a way to bind the AspxScheduler at runtime to a subset of your appointments without using the FetchAppointments() event ?
    In this case, I am curious to know how.

    Actually, using the FetchAppointments() event works quite well.

    Regards,
    Marc Greiner [DX-Squad]
  • Aaron Smith

    Re: Loading a subset of appointments based on selected time interval,rather than all appointments

    9/23/2009 9:18 AM
    • Top 500 Contributor
    • Joined on 5/4/2007
    • Posts 48

     Actually, the FetchAppointments event does not work well. I have noted before in support requests that the event fires anywhere from 2 - 6 times, sometimes with invalid dates, and sometimes with the same dates multiple times. This is highly inefficient and what caused me to go looking for some other way to do things. What I had to do to overcome this issue was create my own caching system for caching the data. Had I realized that I could do it the way I am doing it now, I wouldn't need that cache.

    What I did was place the calendar in a ASPxCallbackPanel. Then in the client side event for active date range changed I do a PerformCallback on the panel. The panel callback then gets the current active date range, fetches the data from the cache and rebinds the calendar to that data. After watching this event, it gets called once to fetch the data and bind it to the calendar, which is much more efficient, and in fact it is much faster now.

1 2 Next
More from DevExpress
Live Chat
Have a pre-sales question?
Need assistance with your evaluation?
We are here to help.
Chat is one of the many ways you can contact members of the DevExpress Team. We are available Monday-Friday between 8:30am and 5:00pm Pacific Time.
If you need additional product information, require pre-sales assistance, or want help with your order, write to us at info@devexpress.com or call us at
+1 (818) 844-3383.