public void Delete(IEnumerable<long> ids)
        {
            if (ids == null)
                throw new ArgumentNullException("ids");

            try
            {
                logger.Info("SQLiteTagRepository.Delete(IEnumerable<long>)");

                var builders = new List<ICommandBuilder>();

                foreach (var id in ids)
                {
                    var builder = new CommandBuilder();
                    builder.AppendLine("delete from Tag where Id = @Id;");
                    builder.AddParameter("@Id", id);
                    builders.Add(builder);
                }

                if (builders.Count == 0)
                    return;

                ExecuteTransaction(builders);
            }
            catch (Exception ex)
            {
                logger.Error("  Delete(IEnumerable<long>)", ex);
                throw;
            }
        }
        public void Overwrite(Uri target, ITagType type, IEnumerable<Gnosis.ITag> tags)
        {
            if (target == null)
                throw new ArgumentNullException("target");
            if (type == null)
                throw new ArgumentNullException("type");

            try
            {
                var builders = new List<ICommandBuilder>();

                var deleteBuilder = new CommandBuilder("delete from Tag where Target = @Target and Type = @Type;");
                deleteBuilder.AddParameter("@Target", target.ToString());
                deleteBuilder.AddParameter("@Type", type.Id);
                builders.Add(deleteBuilder);
                
                foreach (var tag in tags.Where(x => x.Target == target && x.Type == type))
                {
                    var insertBuilder = new CommandBuilder("insert into Tag (Target, Algorithm, Domain, Type, Value, Data) values (@Target, @Algorithm, @Domain, @Type, @Value, @Data);");
                    insertBuilder.AddParameter("@Target", tag.Target.ToString());
                    insertBuilder.AddParameter("@Algorithm", tag.Algorithm.Id);
                    insertBuilder.AddParameter("@Domain", (int)tag.Type.Domain);
                    insertBuilder.AddParameter("@Type", tag.Type.Id);
                    insertBuilder.AddParameter("@Value", tag.Value);
                    insertBuilder.AddParameter("@Data", tag.Data);

                    builders.Add(insertBuilder);
                }

                if (builders.Count < 2)
                    return;

                ExecuteTransaction(builders);
            }
            catch (Exception ex)
            {
                logger.Error("  Overwrite", ex);
                throw;
            }
        }
        public void Save(IEnumerable<Gnosis.ITag> tags)
        {
            if (tags == null)
                throw new ArgumentNullException("tags");

            try
            {
                logger.Info("SQLiteTagRepository.Save(IEnumerable<ITag>)");

                var builders = new List<ICommandBuilder>();

                foreach (var tag in tags)
                {
                    var builder = new CommandBuilder();
                    builder.AppendLine("replace into Tag (Id, Target, Algorithm, Domain, Type, Value, Data) values (@Id, @Target, @Algorithm, @Domain, @Type, @Value, @Data);");
                    builder.AddParameter("@Id", tag.Id > 0 ? (object)tag.Id : (object)DBNull.Value);
                    builder.AddParameter("@Target", tag.Target.ToString());
                    builder.AddParameter("@Algorithm", tag.Algorithm.Id);
                    builder.AddParameter("@Domain", (int)tag.Type.Domain);
                    builder.AddParameter("@Type", tag.Type.Id);
                    builder.AddParameter("@Value", tag.Value);
                    builder.AddParameter("@Data", tag.Data);

                    builders.Add(builder);
                }

                if (builders.Count == 0)
                    return;

                ExecuteTransaction(builders);
            }
            catch (Exception ex)
            {
                logger.Error("  Save(IEnumerable<ITag>)", ex);
                throw;
            }
        }
        public IEnumerable<Gnosis.ITag> GetByAlgorithm(IAlgorithm algorithm, TagDomain domain, string pattern)
        {
            if (algorithm == null)
                throw new ArgumentNullException("algorithm");
            if (pattern == null)
                throw new ArgumentNullException("pattern");

            try
            {
                logger.Info("SQLiteTagRepository.GetByAlgorithm(IAlgorithm, TagDomain, string)");

                var builder = new CommandBuilder("select * from Tag where Algorithm = @Algorithm and Domain = @Domain and Value like @Pattern;");
                builder.AddParameter("@Algorithm", algorithm.Id);
                builder.AddParameter("@Domain", (int)domain);
                builder.AddParameter("@Pattern", pattern);

                return GetTags(builder);
            }
            catch (Exception ex)
            {
                logger.Error("  GetByAlgorithm(IAlgorithm, TagDomain, string)", ex);
                throw;
            }
        }
        public IEnumerable<Gnosis.ITag> GetByTarget(Uri target, ITagType type)
        {
            if (target == null)
                throw new ArgumentNullException("target");
            if (type == null)
                throw new ArgumentNullException("type");

            try
            {
                logger.Info("SQLiteTagRepository.GetByTarget(Uri, ITagType)");

                var builder = new CommandBuilder("select * from Tag where Target = @Target and Type = @Type;");
                builder.AddParameter("@Target", target.ToString());
                builder.AddParameter("@Type", type.Id);

                return GetTags(builder);
            }
            catch (Exception ex)
            {
                logger.Error("  GetByTarget(Uri, ITagType)", ex);
                throw;
            }
        }
        public IEnumerable<Gnosis.ITag> GetByTarget(Uri target, TagDomain domain)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            try
            {
                logger.Info("SQLiteTagRepository.GetByTarget(Uri, TagDomain)");

                var builder = new CommandBuilder("select * Tag where Target = @Target and Domain = @Domain;");
                builder.AddParameter("@Target", target.ToString());
                builder.AddParameter("@Domain", (int)domain);

                return GetTags(builder);
            }
            catch (Exception ex)
            {
                logger.Error("  GetByTarget(Uri, TagDomain)", ex);
                throw;
            }
        }
        //private IEnumerable<ITag> GetId3v1SimpleGenreTags(IAlgorithm algorithm, string pattern)
        //{
        //    var builder = new CommandBuilder("select * from Tag where Algorithm = @Algorithm and Domain = @Domain and Value1 like @Pattern;");
        //    builder.AddParameter("@Algorithm", algorithm.Id);
        //    builder.AddParameter("@Domain", TagDomain.Id3v1SimpleGenre.Id);
        //    builder.AddParameter("@Pattern", pattern);
        //    return GetTags(builder);
        //}

        //private IEnumerable<ITag> GetStringTags(IAlgorithm algorithm, string pattern)
        //{
        //    var builder = new CommandBuilder("select * from Tag where Algorithm = @Algorithm and Domain = @Domain and Value1 like @Pattern;");
        //    builder.AddParameter("@Algorithm", algorithm.Id);
        //    builder.AddParameter("@Domain", TagDomain.String.Id);
        //    builder.AddParameter("@Pattern", pattern);
        //    return GetTags(builder);
        //}

        /*
        private IEnumerable<ITag> GetStringArrayTags1(IAlgorithm algorithm, string pattern)
        {
            var builder = new CommandBuilder("select * from Tag where Algorithm = @Algorithm and Domain = @Domain and Value1 like @Pattern;");
            builder.AddParameter("@Algorithm", algorithm.Id);
            builder.AddParameter("@Domain", TagDomain.StringArray.Id);
            builder.AddParameter("@Pattern", pattern);
            return GetTags(builder);
        }

        private IEnumerable<ITag> GetStringArrayTags2(IAlgorithm algorithm, string pattern)
        {
            var builder = new CommandBuilder("select * from Tag where Algorithm = @Algorithm and Domain = @Domain and Value2 like @Pattern;");
            builder.AddParameter("@Algorithm", algorithm.Id);
            builder.AddParameter("@Domain", TagDomain.StringArray.Id);
            builder.AddParameter("@Pattern", pattern);
            return GetTags(builder);
        }

        private IEnumerable<ITag> GetStringArrayTags3(IAlgorithm algorithm, string pattern)
        {
            var builder = new CommandBuilder("select * from Tag where Algorithm = @Algorithm and Domain = @Domain and Value3 like @Pattern;");
            builder.AddParameter("@Algorithm", algorithm.Id);
            builder.AddParameter("@Domain", TagDomain.StringArray.Id);
            builder.AddParameter("@Pattern", pattern);
            return GetTags(builder);
        }

        private IEnumerable<ITag> GetStringArrayTags4(IAlgorithm algorithm, string pattern)
        {
            var builder = new CommandBuilder("select * from Tag where Algorithm = @Algorithm and Domain = @Domain and Value4 like @Pattern;");
            builder.AddParameter("@Algorithm", algorithm.Id);
            builder.AddParameter("@Domain", TagDomain.StringArray.Id);
            builder.AddParameter("@Pattern", pattern);
            return GetTags(builder);
        }

        private IEnumerable<ITag> GetStringArrayTags5(IAlgorithm algorithm, string pattern)
        {
            var builder = new CommandBuilder("select * from Tag where Algorithm = @Algorithm and Domain = @Domain and Value5 like @Pattern;");
            builder.AddParameter("@Algorithm", algorithm.Id);
            builder.AddParameter("@Domain", TagDomain.StringArray.Id);
            builder.AddParameter("@Pattern", pattern);
            return GetTags(builder);
        }

        private IEnumerable<ITag> GetStringArrayTags6(IAlgorithm algorithm, string pattern)
        {
            var builder = new CommandBuilder("select * from Tag where Algorithm = @Algorithm and Domain = @Domain and Value6 like @Pattern;");
            builder.AddParameter("@Algorithm", algorithm.Id);
            builder.AddParameter("@Domain", TagDomain.StringArray.Id);
            builder.AddParameter("@Pattern", pattern);
            return GetTags(builder);
        }

        private IEnumerable<ITag> GetStringArrayTags7(IAlgorithm algorithm, string pattern)
        {
            var builder = new CommandBuilder("select * from Tag where Algorithm = @Algorithm and Domain = @Domain and Value7 like @Pattern;");
            builder.AddParameter("@Algorithm", algorithm.Id);
            builder.AddParameter("@Domain", TagDomain.StringArray.Id);
            builder.AddParameter("@Pattern", pattern);
            return GetTags(builder);
        }
        */

        #endregion

        public Gnosis.ITag GetById(long id)
        {
            try
            {
                logger.Info("SQLiteTagRepository.GetById");

                var builder = new CommandBuilder("select * from Tag where Id = @Id;");
                builder.AddParameter("@Id", id);

                return GetTags(builder).FirstOrDefault();
            }
            catch (Exception ex)
            {
                logger.Error("  GetById", ex);
                throw;
            }
        }