public void Save(VEVENT entity)
        {
            #region retrieve attributes of entity

            var organizer = entity.Organizer;
            var recur = entity.RecurrenceRule;
            var attendees = entity.Attendees;
            var attachbins = entity.Attachments.OfType<ATTACH_BINARY>().ToList();
            var attachuris = entity.Attachments.OfType<ATTACH_URI>().ToList();
            var contacts = entity.Contacts;
            var comments = entity.Comments;
            var rdates = entity.RecurrenceDates;
            var exdates = entity.ExceptionDates;
            var relateds = entity.RelatedTos;
            var resources = entity.Resources;
            var reqstats = entity.RequestStatuses;
            var aalarms = entity.Alarms.OfType<AUDIO_ALARM>().ToList();
            var dalarms = entity.Alarms.OfType<DISPLAY_ALARM>().ToList();
            var ealarms = entity.Alarms.OfType<EMAIL_ALARM>().ToList();

            #endregion retrieve attributes of entity

            #region save event and its attributes

            using (var db = factory.OpenDbConnection())
            {
                db.Save(entity);

                var ororgs = db.Select<REL_EVENTS_ORGANIZERS>(q => q.EventId == entity.Id);
                var orrecurs = db.Select<REL_EVENTS_RECURS>(q => q.EventId == entity.Id);
                var orattendees = db.Select<REL_EVENTS_ATTENDEES>(q => q.EventId == entity.Id);
                var orattachbins = db.Select<REL_EVENTS_ATTACHBINS>(q => q.EventId == entity.Id);
                var orattachuris = db.Select<REL_EVENTS_ATTACHURIS>(q => q.EventId == entity.Id);
                var orcontacts = db.Select<REL_EVENTS_CONTACTS>(q => q.EventId == entity.Id);
                var orcomments = db.Select<REL_EVENTS_COMMENTS>(q => q.EventId == entity.Id);
                var orrdates = db.Select<REL_EVENTS_RDATES>(q => q.EventId == entity.Id);
                var orexdates = db.Select<REL_EVENTS_EXDATES>(q => q.EventId == entity.Id);
                var orrelateds = db.Select<REL_EVENTS_RELATEDTOS>(q => q.EventId == entity.Id);
                var orresources = db.Select<REL_EVENTS_RESOURCES>(q => q.EventId == entity.Id);
                var orreqstats = db.Select<REL_EVENTS_REQSTATS>(q => q.EventId == entity.Id);
                var oraalarms = db.Select<REL_EVENTS_AUDIO_ALARMS>(q => q.EventId == entity.Id);
                var ordalarms = db.Select<REL_EVENTS_DISPLAY_ALARMS>(q => q.EventId == entity.Id);
                var orealarms = db.Select<REL_EVENTS_EMAIL_ALARMS>(q => q.EventId == entity.Id);

                if (organizer != null)
                {
                    db.Save(organizer);
                    var rorg = new REL_EVENTS_ORGANIZERS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        OrganizerId = organizer.Id
                    };

                    db.MergeAll<REL_EVENTS_ORGANIZERS, Guid>(rorg.ToSingleton(), ororgs);
                }
                else db.RemoveAll<REL_EVENTS_ORGANIZERS, Guid>(ororgs);

                if (recur != null)
                {
                    db.Save(recur);
                    var rrecur = new REL_EVENTS_RECURS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        RecurId = recur.Id
                    };

                    db.MergeAll<REL_EVENTS_RECURS, Guid>(rrecur.ToSingleton(), orrecurs);
                }
                else db.RemoveAll<REL_EVENTS_RECURS, Guid>(orrecurs);

                if (!attendees.NullOrEmpty())
                {
                    db.SaveAll(attendees.Distinct());
                    var rattendees = attendees.Select(x => new REL_EVENTS_ATTENDEES
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        AttendeeId = x.Id
                    });

                    db.MergeAll<REL_EVENTS_ATTENDEES, Guid>(rattendees, orattendees);
                }
                else db.RemoveAll<REL_EVENTS_ATTENDEES, Guid>(orattendees);

                if (!attachbins.NullOrEmpty())
                {
                    db.SaveAll(attachbins.Distinct());
                    var rattachbins = attachbins.Select(x => new REL_EVENTS_ATTACHBINS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        AttachmentId = x.Id
                    });
                    db.MergeAll<REL_EVENTS_ATTACHBINS, Guid>(rattachbins, orattachbins);
                }
                else db.RemoveAll<REL_EVENTS_ATTACHBINS, Guid>(orattachbins);

                if (!attachuris.NullOrEmpty())
                {
                    db.SaveAll(attachuris.Distinct());
                    var rattachuris = attachuris.Select(x => new REL_EVENTS_ATTACHURIS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        AttachmentId = x.Id
                    });
                    db.MergeAll(rattachuris, orattachuris);
                }
                else db.RemoveAll(orattachuris);

                if (!contacts.NullOrEmpty())
                {
                    db.SaveAll(contacts.Distinct());
                    var rcontacts = contacts.Select(x => new REL_EVENTS_CONTACTS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        ContactId = x.Id
                    });
                    db.MergeAll(rcontacts, orcontacts);
                }
                else db.RemoveAll(orcontacts);

                if (!comments.NullOrEmpty())
                {
                    db.SaveAll(comments.Distinct());
                    var rcomments = comments.Select(x => new REL_EVENTS_COMMENTS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        CommentId = x.Id
                    });
                    db.MergeAll(rcomments, orcomments);
                }
                else db.RemoveAll(orcomments);

                if (!rdates.NullOrEmpty())
                {
                    db.SaveAll(rdates.Distinct());
                    var rrdates = rdates.Select(x => new REL_EVENTS_RDATES
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        RecurrenceDateId = x.Id
                    });
                    db.MergeAll(rrdates, orrdates);
                }
                else db.RemoveAll(orrdates);

                if (!exdates.NullOrEmpty())
                {
                    db.SaveAll(exdates.Distinct());
                    var rexdates = exdates.Select(x => new REL_EVENTS_EXDATES
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        ExceptionDateId = x.Id
                    });
                    db.MergeAll(rexdates, orexdates);
                }
                else db.RemoveAll(orexdates);

                if (!relateds.NullOrEmpty())
                {
                    db.SaveAll(relateds.Distinct());
                    var rrelateds = relateds.Select(x => new REL_EVENTS_RELATEDTOS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        RelatedToId = x.Id
                    });
                    db.MergeAll(rrelateds, orrelateds);
                }
                else db.RemoveAll(orrelateds);

                if (!resources.NullOrEmpty())
                {
                    db.SaveAll(resources.Distinct());
                    var rresources = resources.Select(x => new REL_EVENTS_RESOURCES
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        ResourcesId = x.Id
                    });
                    db.MergeAll(rresources, orresources);
                }
                else db.RemoveAll(orresources);

                if (!reqstats.NullOrEmpty())
                {
                    db.SaveAll(reqstats.Distinct());
                    var rreqstats = reqstats.Select(x => new REL_EVENTS_REQSTATS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        ReqStatsId = x.Id
                    });
                    db.MergeAll(rreqstats, orreqstats);
                }
                else db.RemoveAll(orreqstats);

                if (!aalarms.NullOrEmpty())
                {
                    aalarmrepository.SaveAll(aalarms.Distinct());
                    var raalarms = aalarms.Select(x => new REL_EVENTS_AUDIO_ALARMS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        AlarmId = x.Id
                    });
                    db.MergeAll(raalarms, oraalarms);
                }
                else db.RemoveAll(orealarms);

                if (!dalarms.NullOrEmpty())
                {
                    dalarmrepository.SaveAll(dalarms.Distinct());
                    var rdalarms = dalarms.Select(x => new REL_EVENTS_DISPLAY_ALARMS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        AlarmId = x.Id
                    });
                    db.MergeAll(rdalarms, ordalarms);
                }
                else db.RemoveAll(ordalarms);

                if (!ealarms.NullOrEmpty())
                {
                    ealarmrepository.SaveAll(ealarms.Distinct());
                    var realarms = ealarms.Select(x => new REL_EVENTS_EMAIL_ALARMS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        AlarmId = x.Id
                    });
                    db.MergeAll(realarms, orealarms);
                }
                else db.RemoveAll(orealarms); 
            }

            #endregion save event and its attributes
        }
        public void Save(VEVENT entity)
        {
            var keys = redis.As<VEVENT>().GetAllKeys().ToArray();
            var guids = keys.Select(x => new Guid(x));
            if (!keys.NullOrEmpty())
            {
                redis.Watch(keys);
            }

            #region retrieve attributes of event

            var recur = entity.RecurrenceRule;
            var organizer = entity.Organizer;
            var attendees = entity.Attendees;
            var attachbins = entity.Attachments.OfType<ATTACH_BINARY>();
            var attachuris = entity.Attachments.OfType<ATTACH_URI>();
            var contacts = entity.Contacts;
            var comments = entity.Comments;
            var rdates = entity.RecurrenceDates;
            var exdates = entity.ExceptionDates;
            var relatedtos = entity.RelatedTos;
            var resources = entity.Resources;
            var reqstats = entity.RequestStatuses;
            var aalarms = entity.Alarms.OfType<AUDIO_ALARM>();
            var dalarms = entity.Alarms.OfType<DISPLAY_ALARM>();
            var ealarms = entity.Alarms.OfType<EMAIL_ALARM>();

            #endregion retrieve attributes of event

            manager.ExecTrans(transaction =>
            {
                var orrecurs = redis.As<REL_EVENTS_RECURS>().GetAll().Where(x => x.EventId == entity.Id);
                var ororgs = redis.As<REL_EVENTS_ORGANIZERS>().GetAll().Where(x => x.EventId == entity.Id);
                var orattendees = redis.As<REL_EVENTS_ATTENDEES>().GetAll().Where(x => x.EventId == entity.Id);
                var orattachbins = redis.As<REL_EVENTS_ATTACHBINS>().GetAll().Where(x => x.EventId == entity.Id);
                var orattachuris = redis.As<REL_EVENTS_ATTACHURIS>().GetAll().Where(x => x.EventId == entity.Id);
                var orcontacts = redis.As<REL_EVENTS_CONTACTS>().GetAll().Where(x => x.EventId == entity.Id);
                var orcomments = redis.As<REL_EVENTS_COMMENTS>().GetAll().Where(x => x.EventId == entity.Id);
                var orrdates = redis.As<REL_EVENTS_RDATES>().GetAll().Where(x => x.EventId == entity.Id);
                var orexdates = redis.As<REL_EVENTS_EXDATES>().GetAll().Where(x => x.EventId == entity.Id);
                var orrelatedtos = redis.As<REL_EVENTS_RELATEDTOS>().GetAll().Where(x => x.EventId == entity.Id);
                var orresources = redis.As<REL_EVENTS_RESOURCES>().GetAll().Where(x => x.EventId == entity.Id);
                var orreqstats = redis.As<REL_EVENTS_REQSTATS>().GetAll().Where(x => x.EventId == entity.Id);
                var oraalarms = redis.As<REL_EVENTS_AUDIO_ALARMS>().GetAll().Where(x => x.EventId == entity.Id);
                var ordalarms = redis.As<REL_EVENTS_DISPLAY_ALARMS>().GetAll().Where(x => x.EventId == entity.Id);
                var orealarms = redis.As<REL_EVENTS_EMAIL_ALARMS>().GetAll().Where(x => x.EventId == entity.Id);
                if (organizer != null)
                {
                    transaction.QueueCommand(x => x.Store(organizer));
                    var rorganizer = new REL_EVENTS_ORGANIZERS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        OrganizerId = organizer.Id,
                    };

                    redis.MergeAll(rorganizer.ToSingleton(), ororgs, transaction);
                }
                else redis.RemoveAll(ororgs, transaction);

                if (recur != null)
                {
                    transaction.QueueCommand(x => x.Store(recur));
                    var rrecur = new REL_EVENTS_RECURS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        RecurId = recur.Id,
                    };

                    redis.MergeAll(rrecur.ToSingleton(), orrecurs, transaction);
                }
                else redis.RemoveAll(orrecurs, transaction);

                if (!attendees.NullOrEmpty())
                {
                    transaction.QueueCommand(x => x.StoreAll(attendees));
                    var rattendees = attendees.Select(x => new REL_EVENTS_ATTENDEES
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        AttendeeId = x.Id,
                    });

                    redis.MergeAll(rattendees, orattendees, transaction);
                }
                else redis.RemoveAll(orattendees, transaction);

                if (!attachbins.NullOrEmpty())
                {
                    transaction.QueueCommand(x => x.StoreAll(attachbins.Distinct()));
                    var rattachbins = attachbins.Select(x => new REL_EVENTS_ATTACHBINS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        AttachmentId = x.Id,
                    });

                    redis.MergeAll(rattachbins, orattachbins, transaction);
                }
                else redis.RemoveAll(orattachbins, transaction);

                if (!attachuris.NullOrEmpty())
                {
                    transaction.QueueCommand(x => x.StoreAll(attachuris.Distinct()));
                    var rattachuris = attachuris.Select(x => new REL_EVENTS_ATTACHURIS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        AttachmentId = x.Id,
                    });

                    redis.MergeAll(rattachuris, orattachuris, transaction);
                }
                else redis.RemoveAll(orattachuris, transaction);

                if (!contacts.NullOrEmpty())
                {
                    transaction.QueueCommand(x => x.StoreAll(contacts.Distinct()));
                    var rcontacts = contacts.Select(x => new REL_EVENTS_CONTACTS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        ContactId = x.Id,
                    });

                    redis.MergeAll(rcontacts, orcontacts, transaction);
                }
                else redis.RemoveAll(orcontacts, transaction);

                if (!comments.NullOrEmpty())
                {
                    transaction.QueueCommand(x => x.StoreAll(comments.Distinct()));
                    var rcomments = comments.Select(x => new REL_EVENTS_COMMENTS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        CommentId = x.Id,
                    });

                    redis.MergeAll(rcomments, orcomments, transaction);
                }
                else redis.RemoveAll(orcomments, transaction);

                if (!rdates.NullOrEmpty())
                {
                    transaction.QueueCommand(x => x.StoreAll(rdates.Distinct()));
                    var rrdates = rdates.Select(x => new REL_EVENTS_RDATES
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        RecurrenceDateId = x.Id,
                    });
                    redis.MergeAll(rrdates, orrdates, transaction);
                }
                else redis.RemoveAll(orrdates, transaction);

                if (!exdates.NullOrEmpty())
                {
                    transaction.QueueCommand(x => x.StoreAll(exdates.Distinct()));
                    var rexdates = exdates.Select(x => new REL_EVENTS_EXDATES
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        ExceptionDateId = x.Id,
                    });

                    redis.MergeAll(rexdates, orexdates, transaction);
                }
                else redis.RemoveAll(oraalarms, transaction);

                if (!relatedtos.NullOrEmpty())
                {
                    transaction.QueueCommand(x => x.StoreAll(relatedtos.Distinct()));
                    var rrelatedtos = relatedtos.Select(x => new REL_EVENTS_RELATEDTOS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        RelatedToId = x.Id,
                    });
                    redis.MergeAll(rrelatedtos, orrelatedtos, transaction);
                }
                else redis.RemoveAll(oraalarms, transaction);
                if (!resources.NullOrEmpty())
                {
                    transaction.QueueCommand(x => x.StoreAll(resources.Distinct()));
                    var rresources = resources.Select(x => new REL_EVENTS_RESOURCES
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        ResourcesId = x.Id,
                    });
                    redis.MergeAll(rresources, orresources, transaction);
                }
                else redis.RemoveAll(oraalarms, transaction);

                if (!reqstats.NullOrEmpty())
                {
                    transaction.QueueCommand(x => x.StoreAll(reqstats.Distinct()));
                    var rreqstats = reqstats.Select(x => new REL_EVENTS_REQSTATS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        ReqStatsId = x.Id,
                    });
                    redis.MergeAll(rreqstats, orreqstats, transaction);
                }
                else redis.RemoveAll(orreqstats, transaction);

                if (!aalarms.NullOrEmpty())
                {
                    aalarmrepository.SaveAll(aalarms.Distinct());
                    var raalarms = aalarms.Select(x => new REL_EVENTS_AUDIO_ALARMS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        AlarmId = x.Id
                    });
                    redis.MergeAll(raalarms, oraalarms, transaction);
                }
                else redis.RemoveAll(oraalarms, transaction);

                if (!dalarms.NullOrEmpty())
                {
                    dalarmrepository.SaveAll(dalarms.Distinct());
                    var rdalarms = dalarms.Select(x => new REL_EVENTS_DISPLAY_ALARMS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        AlarmId = x.Id
                    });
                    redis.MergeAll(rdalarms, ordalarms, transaction);
                }
                else redis.RemoveAll(ordalarms, transaction);

                if (!ealarms.NullOrEmpty())
                {
                    ealarmrepository.SaveAll(ealarms.Distinct());
                    var realarms = ealarms.Select(x => new REL_EVENTS_EMAIL_ALARMS
                    {
                        Id = keygenerator.GetNext(),
                        EventId = entity.Id,
                        AlarmId = x.Id
                    });
                    redis.MergeAll(realarms, orealarms, transaction);
                }
                else redis.RemoveAll(orealarms, transaction);

                transaction.QueueCommand(x => x.Store(Dehydrate(entity)));
            });
        }