public void Save(AUDIO_ALARM entity)
        {
            if (entity.Attachment == null) return;

            manager.ExecTrans(transaction =>
            {
                var orattachbins = redis.As<REL_AALARMS_ATTACHBINS>().GetAll().Where(x => x.AlarmId == entity.Id);
                var orattachuris = redis.As<REL_AALARMS_ATTACHURIS>().GetAll().Where(x => x.AlarmId == entity.Id);
                var attachbin = entity.Attachment as ATTACH_BINARY;
                if (attachbin != null)
                {
                    transaction.QueueCommand(x => x.Store(attachbin));
                    var rattachbin = new REL_AALARMS_ATTACHBINS
                    {
                        Id = keygenerator.GetNext(),
                        AlarmId = entity.Id,
                        AttachmentId = attachbin.Id
                    };

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

                var attachuri = entity.Attachment as ATTACH_URI;
                if (attachuri != null)
                {
                    transaction.QueueCommand(x => x.Store(attachuri));
                    var rattachuri = new REL_AALARMS_ATTACHURIS
                    {
                        Id = keygenerator.GetNext(),
                        AlarmId = entity.Id,
                        AttachmentId = attachuri.Id
                    };

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


                transaction.QueueCommand(x => x.Store(Dehydrate(entity)));
            });
        }
        /// <summary>
        ///     Inserts a new entity or updates an existing one in the repository
        /// </summary>
        /// <param name="alarm">The entity to save</param>
        public void Save(AUDIO_ALARM alarm)
        {
            db.Save(alarm);

            if (alarm.Attachment == null) return;

            var orattachbins = db.Select<REL_AALARMS_ATTACHBINS>(q => q.Id == alarm.Id);
            var orattachuris = db.Select<REL_AALARMS_ATTACHURIS>(q => q.Id == alarm.Id);

            var attachbin = alarm.Attachment as ATTACH_BINARY;
            if (attachbin != null)
            {
                db.Save(attachbin);
                var rattachbin = new REL_AALARMS_ATTACHBINS
                {
                    Id = keygenerator.GetNext(),
                    AlarmId = alarm.Id,
                    AttachmentId = attachbin.Id
                };

                db.MergeAll(rattachbin.ToSingleton(), orattachbins);
            }
            else db.RemoveAll(orattachbins);

            var attachuri = alarm.Attachment as ATTACH_URI;
            if (attachuri != null)
            {
                db.Save(attachuri);
                var rattachuri = new REL_AALARMS_ATTACHURIS
                {
                    Id = keygenerator.GetNext(),
                    AlarmId = alarm.Id,
                    AttachmentId = attachuri.Id
                };

                db.MergeAll(rattachuri.ToSingleton(), orattachuris);
            }
            else db.RemoveAll(orattachuris);
        }
 public AUDIO_ALARM Dehydrate(AUDIO_ALARM alarm)
 {
     alarm.Attachment = null;
     return alarm;
 }
        public AUDIO_ALARM Hydrate(AUDIO_ALARM alarm)
        {
            var match = redis.As<AUDIO_ALARM>().GetValue(alarm.Id.ToString());
            if (match != null)
            {
                var rattachbins = redis.As<REL_AALARMS_ATTACHBINS>().GetAll().Where(x => x.AlarmId == match.Id).ToList();
                var rattachuris = redis.As<REL_AALARMS_ATTACHURIS>().GetAll().Where(x => x.AlarmId == match.Id).ToList();

                if (rattachbins.Any())
                {
                    match.Attachment = redis.As<ATTACH_BINARY>().GetValues(rattachbins.Select(x => x.AttachmentId.ToString()).ToList()).First();
                }
                if (rattachuris.Any())
                {
                    match.Attachment = redis.As<ATTACH_URI>().GetValues(rattachuris.Select(x => x.AttachmentId.ToString()).ToList()).First();
                }
            }
            return match ?? alarm;
        }
        public void Patch(AUDIO_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<AUDIO_ALARM, object>> primitives = x => new
            {
                x.Action,
                x.Duration,
                x.Trigger,
                x.Repeat
            };

            Expression<Func<AUDIO_ALARM, object>> relations = x => new
            {
                x.Attachment,
            };

            var sprimitives = primitives.GetMemberNames().Intersect(selection);
            var srelations = relations.GetMemberNames().Intersect(selection);

            #endregion construct anonymous fields using expression lambdas

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

                #region save (insert or update) normalized attributes

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

                    var orattachbins = redis.As<REL_AALARMS_ATTACHBINS>().GetAll().Where(x => keys.Contains(x.AlarmId));
                    var orattachuris = redis.As<REL_AALARMS_ATTACHURIS>().GetAll().Where(x => keys.Contains(x.AlarmId));

                    if (srelations.Contains(attachsexpr.GetMemberName()))
                    {
                        var attachbin = source.Attachment as ATTACH_BINARY;
                        if (attachbin != null)
                        {
                            transaction.QueueCommand(x => redis.As<ATTACH_BINARY>().Store(attachbin));
                            var rattachbins = keys.Select(x => new REL_AALARMS_ATTACHBINS
                            {
                                Id = keygenerator.GetNext(),
                                AlarmId = x,
                                AttachmentId = attachbin.Id
                            });

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

                        var attachuri = source.Attachment as ATTACH_URI;
                        if (attachuri != null)
                        {
                            transaction.QueueCommand(x => redis.As<ATTACH_URI>().Store(attachuri));
                            var rattachuris = keys.Select(x => new REL_AALARMS_ATTACHURIS
                            {
                                Id = keygenerator.GetNext(),
                                AlarmId = x,
                                AttachmentId = attachuri.Id
                            });

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

                #endregion save (insert or update) normalized attributes

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

                var lsprimitives = sprimitives as IList<string> ?? sprimitives.ToList();
                if (!lsprimitives.NullOrEmpty())
                {
                    Expression<Func<AUDIO_ALARM, object>> actionexpr = x => x.Action;
                    Expression<Func<AUDIO_ALARM, object>> repeatexpr = x => x.Repeat;
                    Expression<Func<AUDIO_ALARM, object>> durationexpr = x => x.Duration;
                    Expression<Func<AUDIO_ALARM, object>> triggerexpr = x => x.Trigger;

                    var entities = aclient.GetByIds(keys).ToList();
                    entities.ForEach(x =>
                    {
                        if (lsprimitives.Contains(actionexpr.GetMemberName())) x.Action = source.Action;
                        if (lsprimitives.Contains(repeatexpr.GetMemberName())) x.Repeat = source.Repeat;
                        if (lsprimitives.Contains(durationexpr.GetMemberName())) x.Duration = source.Duration;
                        if (lsprimitives.Contains(triggerexpr.GetMemberName())) x.Trigger = source.Trigger;
                    });

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

                #endregion save (insert or update) non-normalized attributes
            });
        }
        public AUDIO_ALARM Hydrate(AUDIO_ALARM alarm)
        {
            if (db.Select<AUDIO_ALARM>(q => q.Id == alarm.Id).Any())
            {
                var attachbins = db.Select<ATTACH_BINARY, AUDIO_ALARM, REL_AALARMS_ATTACHBINS>(
                    r => r.AttachmentId,
                    r => r.AlarmId,
                    x => x.Id == alarm.Id);
                if (attachbins.Any()) alarm.Attachment = new ATTACH_BINARY(attachbins.First());

                var attachuris = db.Select<ATTACH_URI, AUDIO_ALARM, REL_AALARMS_ATTACHURIS>(
                    r => r.AttachmentId,
                    r => r.AlarmId,
                    x => x.Id == alarm.Id);
                if (!attachuris.NullOrEmpty()) alarm.Attachment = new ATTACH_URI(attachuris.First());
            }
            return alarm;
        }
        /// <summary>
        ///     Patches fields of an entity in the repository
        /// </summary>
        /// <param name="source">The source containing patch details</param>
        /// <param name="fields">Specfies which fields are used for the patching. The fields are specified in an anonymous variable</param>
        /// <param name="keys">Filters the entities to patch by keys. No filter implies all entities are patched</param>
        public void Patch(AUDIO_ALARM source, IEnumerable<string> fields, IEnumerable<Guid> keys = null)
        {
            var okeys = (keys != null)
                ? db.SelectParam<AUDIO_ALARM, Guid>(q => q.Id, p => Sql.In(p.Id, keys.ToArray())).ToArray()
                : db.SelectParam<AUDIO_ALARM>(q => q.Id).ToArray();

            //1. Get fields slected for patching
            var selection = fields as IList<string> ?? fields.ToList();

            //2.Get list of all non-related event details (primitives)
            Expression<Func<AUDIO_ALARM, object>> primitives = x => new
            {
                x.Action,
                x.Trigger,
                x.Duration,
                x.Repeat
            };

            Expression<Func<AUDIO_ALARM, object>> relations = x => x.Attachment;

            var sprimitives =  primitives
                .GetMemberNames()
                .Intersect(selection, StringComparer.OrdinalIgnoreCase)
                .ToList();

            var srelations = relations
                .GetMemberNames()
                .Intersect(selection, StringComparer.OrdinalIgnoreCase)
                .ToList();

            //4. Patch relations
            if (!srelations.NullOrEmpty())
            {
                Expression<Func<AUDIO_ALARM, object>> attachexpr = x => x.Attachment;

                if (srelations.Contains(attachexpr.GetMemberName()))
                {
                    var orattachbins = db.Select<REL_AALARMS_ATTACHBINS>(q => Sql.In(q.AlarmId, okeys));
                    var attachbin = source.Attachment as ATTACH_BINARY;
                    if (attachbin != null)
                    {
                        db.Save(attachbin);
                        var rattachbins = okeys.Select(x => new REL_AALARMS_ATTACHBINS
                        {
                            Id = keygenerator.GetNext(),
                            AlarmId = x,
                            AttachmentId = attachbin.Id
                        });
                        db.RemoveAll(orattachbins);
                        db.SaveAll(rattachbins);
                    }
                    else db.RemoveAll(orattachbins);

                    var orattachuris = db.Select<REL_AALARMS_ATTACHURIS>(q => Sql.In(q.AlarmId, okeys));
                    var attachuri = source.Attachment as ATTACH_URI;
                    if (attachuri != null)
                    {
                        db.Save(attachuri);
                        var rattachuris = okeys.Select(x => new REL_AALARMS_ATTACHURIS
                        {
                            Id = keygenerator.GetNext(),
                            AlarmId = x,
                            AttachmentId = attachuri.Id
                        });
                        db.RemoveAll(rattachuris);
                        db.SaveAll(rattachuris);
                    }
                    else db.RemoveAll(orattachuris);
                }
            }

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

                if (okeys.Any())
                    db.UpdateOnly(source, patchexpr, q => Sql.In(q.Id, okeys.ToArray()));
                else
                    db.UpdateOnly(source, patchexpr);
            }
        }