public EMAIL_ALARM Dehydrate(EMAIL_ALARM alarm)
 {
     alarm.Attendees.Clear();
     alarm.Attachments.Clear();
     return alarm;
 }
        public void Save(EMAIL_ALARM entity)
        {
            manager.ExecTrans(transaction =>
            {
                #region retrieve attributes of entity

                var attendees = entity.Attendees;
                var attachbins = entity.Attachments.OfType<ATTACH_BINARY>();
                var attachuris = entity.Attachments.OfType<ATTACH_URI>();

                #endregion retrieve attributes of entity

                #region save normalized and non-normalized attributes

                var orattendees = redis.As<REL_EALARMS_ATTENDEES>().GetAll().Where(x => x.AlarmId == entity.Id);
                var orattachbins = redis.As<REL_EALARMS_ATTACHBINS>().GetAll().Where(x => x.AlarmId == entity.Id);
                var orattachuris = redis.As<REL_EALARMS_ATTACHURIS>().GetAll().Where(x => x.AlarmId == entity.Id);

                if (!attendees.NullOrEmpty())
                {
                    transaction.QueueCommand(x => x.StoreAll(attendees.Distinct()));
                    var rattendees = attendees.Select(x => new REL_EALARMS_ATTENDEES
                    {
                        Id = keygenerator.GetNext(),
                        AlarmId = 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_EALARMS_ATTACHBINS
                    {
                        Id = keygenerator.GetNext(),
                        AlarmId = 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_EALARMS_ATTACHURIS
                    {
                        Id = keygenerator.GetNext(),
                        AlarmId = entity.Id,
                        AttachmentId = x.Id
                    });

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

                #endregion save normalized and non-normalized attributes

                transaction.QueueCommand(x => x.Store(Dehydrate(entity)));
            });
        }
        public void Patch(EMAIL_ALARM source, IEnumerable<string> fields, IEnumerable<Guid> keys = null)
        {
            #region construct anonymous fields using expression lambdas

            var selection = fields as IList<string> ?? fields.ToList();

            Expression<Func<EMAIL_ALARM, object>> primitives = x => new
            {
                x.Action,
                x.Repeat,
                x.Trigger,
                x.Description,
                x.Duration
            };

            Expression<Func<EMAIL_ALARM, object>> relations = x => new
            {
                x.Attachments,
                x.Attendees
            };

            //4. Get list of selected relationals
            var srelation = relations.GetMemberNames().Intersect(selection).Distinct(StringComparer.OrdinalIgnoreCase);

            //5. Get list of selected primitives
            var sprimitives = primitives.GetMemberNames().Intersect(selection).Distinct(StringComparer.OrdinalIgnoreCase);

            #endregion construct anonymous fields using expression lambdas

            manager.ExecTrans(transaction =>
            {
                var eaclient = redis.As<EMAIL_ALARM>();
                var okeys = eaclient.GetAllKeys().ToArray();
                if (!okeys.NullOrEmpty()) redis.Watch(okeys);

                #region save (insert or update) relational attributes

                if (!srelation.NullOrEmpty())
                {
                    Expression<Func<EMAIL_ALARM, object>> attendsexpr = y => y.Attendees;
                    Expression<Func<EMAIL_ALARM, object>> attachsexpr = y => y.Attachments;

                    var orattendees = redis.As<REL_EALARMS_ATTENDEES>().GetAll().Where(x => x.AlarmId == source.Id);
                    var orattachbins = redis.As<REL_EALARMS_ATTACHBINS>().GetAll().Where(x => keys.Contains(x.AlarmId));
                    var orattachuris = redis.As<REL_EALARMS_ATTACHURIS>().GetAll().Where(x => keys.Contains(x.AlarmId));

                    if (selection.Contains(attendsexpr.GetMemberName()))
                    {
                        var attendees = source.Attendees;
                        if (!attendees.NullOrEmpty())
                        {
                            transaction.QueueCommand(x => redis.As<ATTENDEE>().StoreAll(attendees));
                            var rattendees = keys.SelectMany(x => attendees.Select(y => new REL_EALARMS_ATTENDEES
                            {
                                Id = keygenerator.GetNext(),
                                AlarmId = x,
                                AttendeeId = y.Id
                            }));

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

                    if (selection.Contains(attachsexpr.GetMemberName()))
                    {
                        var attachbins = source.Attachments.OfType<ATTACH_BINARY>();
                        if (attachbins.Any())
                        {
                            transaction.QueueCommand(x => redis.As<ATTACH_BINARY>().StoreAll(attachbins));
                            var rattachbins = keys.SelectMany(x => attachbins.Select(y => new REL_EALARMS_ATTACHBINS
                            {
                                Id = keygenerator.GetNext(),
                                AlarmId = x,
                                AttachmentId = y.Id
                            }));

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

                        var attachuris = source.Attachments.OfType<ATTACH_URI>();
                        if (attachuris.Any())
                        {
                            transaction.QueueCommand(x => redis.As<ATTACH_URI>().StoreAll(attachuris));
                            var rattachuris = keys.SelectMany(x => attachuris.Select(y => new REL_EALARMS_ATTACHURIS
                            {
                                Id = keygenerator.GetNext(),
                                AlarmId = x,
                                AttachmentId = y.Id
                            }));
                            redis.MergeAll(rattachuris, orattachuris, transaction);
                        }
                        else redis.RemoveAll(orattachuris, transaction);
                    }

                }

                #endregion save (insert or update) relational attributes

                #region save (insert or update) non-relational attributes

                if (!sprimitives.NullOrEmpty())
                {
                    Expression<Func<EMAIL_ALARM, object>> actionexpr = x => x.Action;
                    Expression<Func<EMAIL_ALARM, object>> repeatexpr = x => x.Repeat;
                    Expression<Func<EMAIL_ALARM, object>> durationexpr = x => x.Duration;
                    Expression<Func<EMAIL_ALARM, object>> triggerexpr = x => x.Trigger;
                    Expression<Func<EMAIL_ALARM, object>> descexpr = x => x.Description;
                    Expression<Func<EMAIL_ALARM, object>> summexpr = x => x.Summary;

                    var entities = !keys.NullOrEmpty() ? eaclient.GetByIds(keys).ToList() : eaclient.GetAll().ToList();
                    entities.ForEach(x =>
                    {
                        if (selection.Contains(actionexpr.GetMemberName())) x.Action = source.Action;
                        if (selection.Contains(repeatexpr.GetMemberName())) x.Repeat = source.Repeat;
                        if (selection.Contains(durationexpr.GetMemberName())) x.Duration = source.Duration;
                        if (selection.Contains(triggerexpr.GetMemberName())) x.Trigger = source.Trigger;
                        if (selection.Contains(descexpr.GetMemberName())) x.Description = source.Description;
                        if (selection.Contains(summexpr.GetMemberName())) x.Summary = source.Summary;
                    });

                    transaction.QueueCommand(x => x.StoreAll(DehydrateAll(entities)));
                }

                #endregion save (insert or update) non-relational attributes
            });
        }
        public EMAIL_ALARM Hydrate(EMAIL_ALARM alarm)
        {
            var full = redis.As<EMAIL_ALARM>().GetValue(alarm.Id.ToString());
            if (full != null)
            {
                var rattendees = redis.As<REL_EALARMS_ATTENDEES>().GetAll().Where(x => x.AlarmId == full.Id).ToList();
                var rattachbins = redis.As<REL_EALARMS_ATTACHBINS>().GetAll().Where(x => x.AlarmId == full.Id).ToList();
                var rattachuris = redis.As<REL_EALARMS_ATTACHURIS>().GetAll().Where(x => x.AlarmId == full.Id).ToList();

                if (!rattachbins.NullOrEmpty())
                {
                    full.Attachments.MergeRange(redis.As<ATTACH_BINARY>().GetValues(rattachbins.Select(x => x.AttachmentId.ToString()).ToList()));
                }
                if (!rattachuris.NullOrEmpty())
                {
                    full.Attachments.MergeRange(redis.As<ATTACH_URI>().GetValues(rattachuris.Select(x => x.AttachmentId.ToString()).ToList()));
                }
                if (!rattendees.NullOrEmpty())
                {
                    full.Attendees.MergeRange(redis.As<ATTENDEE>().GetValues(rattendees.Select(x => x.AttendeeId.ToString()).ToList()));
                }
            }
            return full ?? alarm;
        }
 public EMAIL_ALARM Dehydrate(EMAIL_ALARM alarm)
 {
     if (alarm.Attendees.Any()) alarm.Attendees.Clear();
     if (alarm.Attachments.Any()) alarm.Attachments.Clear();
     return alarm;
 }
        public void Patch(EMAIL_ALARM source, IEnumerable<string> fields, IEnumerable<Guid> keys = null)
        {
            var okeys = (keys != null)
                ? db.SelectParam<EMAIL_ALARM>(q => q.Id, p => Sql.In(p.Id, keys.ToArray())).ToArray()
                : db.SelectParam<EMAIL_ALARM>(q => q.Id).ToArray();

            var selection = fields as IList<string> ?? fields.ToList();

            //1. obtain primitives i.e. non-normalized properties
            Expression<Func<EMAIL_ALARM, object>> primitives = x => new
            {
                x.Action,
                x.Trigger,
                x.Duration,
                x.Repeat,
                x.Description,
                x.Summary
            };

            //2. obtain relations i.e. normalized properties
            Expression<Func<EMAIL_ALARM, object>> relations = x => new
            {
                x.Attendees,
                x.Attachments
            };

            //3. choose selected properties
            var srelations = relations.GetMemberNames().Intersect(selection, StringComparer.OrdinalIgnoreCase).ToList();
            var sprimitives =
                primitives.GetMemberNames().Intersect(selection, StringComparer.OrdinalIgnoreCase).ToList();

            //4. Patch relations
            if (!srelations.Empty())
            {
                Expression<Func<EMAIL_ALARM, object>> attendsexpr = y => y.Attendees;
                Expression<Func<EMAIL_ALARM, object>> attachsexpr = y => y.Attachments;

                if (srelations.Contains(attendsexpr.GetMemberName()))
                {
                    var orattendees = db.Select<REL_EALARMS_ATTENDEES>(q => Sql.In(q.AlarmId, okeys));
                    if (!source.Attendees.NullOrEmpty())
                    {
                        db.SaveAll(source.Attendees.Distinct());
                        var rattendees = okeys.SelectMany(x => source.Attendees.Select(
                            y => new REL_EALARMS_ATTENDEES
                            {
                                Id = keygenerator.GetNext(),
                                AlarmId = x,
                                AttendeeId = y.Id
                            }));
                        db.RemoveAll(orattendees);
                        db.SaveAll(rattendees);
                    }
                    else db.RemoveAll(orattendees);
                }

                if (srelations.Contains(attachsexpr.GetMemberName()))
                {
                    var attachbins = source.Attachments.OfType<ATTACH_BINARY>();
                    var attachuris = source.Attachments.OfType<ATTACH_URI>();

                    var orattachbins = db.Select<REL_EALARMS_ATTACHBINS>(q => Sql.In(q.AlarmId, okeys));
                    if (attachbins.Any())
                    {
                        db.SaveAll(attachbins);
                        var rattachbins =
                            okeys.SelectMany(x => attachbins.Select(y => new REL_EALARMS_ATTACHBINS
                            {
                                Id = keygenerator.GetNext(),
                                AlarmId = x,
                                AttachmentId = y.Id
                            }));
                        db.RemoveAll(orattachbins);
                        db.SaveAll(rattachbins);
                    }
                    else db.RemoveAll(orattachbins);

                    var orattachuris = db.Select<REL_EALARMS_ATTACHURIS>(q => Sql.In(q.AlarmId, okeys));
                    if (attachuris.Any())
                    {
                        db.SaveAll(attachuris);
                        var rattachuris =
                            okeys.SelectMany(x => attachuris.Select(y => new REL_EALARMS_ATTACHURIS
                            {
                                Id = keygenerator.GetNext(),
                                AlarmId = x,
                                AttachmentId = y.Id
                            }));
                        db.RemoveAll(orattachuris);
                        db.SaveAll(rattachuris);
                    }
                    else db.RemoveAll(orattachuris);

                }


            }

            //5. Patch primitives
            if (!sprimitives.Empty())
            {
                var patchstr = $"f => new {{ {string.Join(", ", sprimitives.Select(x => $"f.{x}"))} }}";
                var patchexpr = patchstr.CompileToExpressionFunc<EMAIL_ALARM, object>(
                    CodeDomLanguage.csharp,
                    "System.dll", "System.Core.dll",
                    typeof(CalendarWriter).Assembly.Location,
                    typeof (EMAIL_ALARM).Assembly.Location,
                    typeof (IContainsKey<Guid>).Assembly.Location);

                if (!okeys.NullOrEmpty()) db.UpdateOnly(source, patchexpr, q => Sql.In(q.Id, okeys.ToArray()));
                else db.UpdateOnly(source, patchexpr);
            }
        }
        public void Save(EMAIL_ALARM entity)
        {
            //Save dry event entity i.a. without related details
            db.Save(entity);

            //1. retrieve entity details
            var attendees = entity.Attendees;
            var attachbins = entity.Attachments.OfType<ATTACH_BINARY>();
            var attachuris = entity.Attachments.OfType<ATTACH_URI>();

            //2. save details
            if (!attendees.NullOrEmpty())
            {
                db.SaveAll(attendees);
                var rattendees =
                    attendees.Select(x => new REL_EALARMS_ATTENDEES {AlarmId = entity.Id, AttendeeId = x.Id});
                var orattendees =
                    db.Select<REL_EALARMS_ATTENDEES>(
                        q => q.Id == entity.Id && Sql.In(q.AttendeeId, attendees.Select(x => x.Id).ToArray()));
                db.MergeAll(rattendees, orattendees);
            }

            if (!attachbins.NullOrEmpty())
            {
                db.SaveAll(attachbins);
                var rattachbins =
                    attachbins.Select(x => new REL_EALARMS_ATTACHBINS {AlarmId = entity.Id, AttachmentId = x.Id});
                var orattachbins =
                    db.Select<REL_EALARMS_ATTACHBINS>(
                        q => q.Id == entity.Id && Sql.In(q.AttachmentId, attachbins.Select(x => x.Id).ToArray()));
                db.MergeAll(rattachbins, orattachbins);
            }

            if (!attachuris.NullOrEmpty())
            {
                db.SaveAll(attachuris);
                var rattachuris =
                    attachuris.Select(x => new REL_EALARMS_ATTACHURIS {AlarmId = entity.Id, AttachmentId = x.Id});
                var orattachuris =
                    db.Select<REL_EALARMS_ATTACHURIS>(
                        q => q.Id == entity.Id && Sql.In(q.AttachmentId, attachuris.Select(x => x.Id).ToArray()));
                db.MergeAll(rattachuris, orattachuris);
            }
        }
        public EMAIL_ALARM Hydrate(EMAIL_ALARM alarm)
        {
            var matches = db.Select<EMAIL_ALARM>(q => q.Id == alarm.Id);

            if (matches.NullOrEmpty()) return alarm;

            var attendees = db.Select<ATTENDEE, EMAIL_ALARM, REL_EALARMS_ATTENDEES>(
                r => r.AttendeeId,
                r => r.AlarmId,
                a => a.Id == alarm.Id);
            if (!attendees.NullOrEmpty()) alarm.Attendees.MergeRange(attendees);

            var attachbins = db.Select<ATTACH_BINARY, EMAIL_ALARM, REL_EALARMS_ATTACHBINS>(
                r => r.AttachmentId,
                r => r.AlarmId,
                a => a.Id == alarm.Id);
            if (!attachbins.NullOrEmpty()) alarm.Attachments.MergeRange(attachbins);

            var attachuris = db.Select<ATTACH_URI, EMAIL_ALARM, REL_EALARMS_ATTACHURIS>(
                r => r.AttachmentId,
                r => r.AlarmId,
                a => a.Id == alarm.Id);
            if (!attachuris.NullOrEmpty()) alarm.Attachments.MergeRange(attachuris);

            return alarm;
        }