/// <summary>
        /// Обновляет кэш отсутвующих
        /// </summary>
        /// <param name="query"></param>
        /// <param name="options"></param>
        /// <param name="connection"></param>
        protected long[] UpdateCache(string query, ObjectDataCacheHints options = null, IDbConnection connection = null)
        {
            lock (_nativeCache){
                var  allids  = new List <long>();
                bool cascade = true;
                if (null == connection)
                {
                    if (string.IsNullOrWhiteSpace(ConnectionString))
                    {
                        UpdateSingleQuery(query, options, null, allids, cascade);
                    }
                    else
                    {
                        //no self created
                        using (var c = ConnectionProvider.GetConnection(ConnectionString)){
                            if (string.IsNullOrWhiteSpace(c.ConnectionString))
                            {
                                throw new Exception("bad connection!");
                            }
                            UpdateSingleQuery(query, options, c, allids, cascade);
                            c.Close();
                        }
                    }
                }
                else
                {
                    UpdateSingleQuery(query, options, connection, allids, cascade);
                }

                return(allids.ToArray());
            }
        }
        /// <summary>
        /// Возвращает сущность по коду или ID
        /// </summary>
        /// <param name="key"></param>
        /// <param name="connection"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public T Get(object key, IDbConnection connection = null, ObjectDataCacheHints options = null)
        {
            options = options ?? ObjectDataCacheHints.Empty;
            int id; string code;
            var isid = IsId(key, out id, out code);

            if (isid)
            {
                if (!_nativeCache.ContainsKey(id) || options.ForceUpdate)
                {
                    UpdateCache("(Id = " + id + ")", connection: connection, options: new ObjectDataCacheHints {
                        KeyQuery = true, Key = id
                    });
                }
                if (!_nativeCache.ContainsKey(id))
                {
                    _nativeCache[id] = null;
                }
                return(_nativeCache[id]);
            }
            else
            {
                if (!_nativeCodeCache.ContainsKey(code) || options.ForceUpdate)
                {
                    UpdateCache("(Code = '" + code.ToSqlString() + "')", connection: connection, options: new ObjectDataCacheHints {
                        KeyQuery = true, Key = code
                    });
                }
                if (!_nativeCodeCache.ContainsKey(code))
                {
                    _nativeCodeCache[code] = null;
                }
                return(_nativeCodeCache[code]);
            }
        }
        /// <summary>
        /// Возвращает все по запросу
        /// </summary>
        /// <param name="query"></param>
        /// <param name="options"></param>
        /// <param name="connection"></param>
        /// <returns></returns>
        public T[] GetAll(object query = null, IDbConnection connection = null, ObjectDataCacheHints options = null)
        {
            options = options ?? ObjectDataCacheHints.Empty;
            if (null == query || (query is string && string.IsNullOrWhiteSpace((string)query)))
            {
                if (_allLoadWasCalled)
                {
                    return(_nativeCache.Values.ToArray());
                }
                UpdateCache("", options, connection);
                _allLoadWasCalled = true;
                return(_nativeCache.Values.ToArray());
            }
            var nativequery = query as Func <T, bool>;

            if (null != nativequery)
            {
                return(_nativeCache.Values.Where(nativequery).ToArray());
            }
            var ids = UpdateCache(query as string, options, connection);

            return(ids.Select(_ => _nativeCache[_]).ToArray());
        }
 /// <summary>
 /// Выполняет действия после обновления кэша с учетом текущего соединения для оптимизации,
 /// позволяет донастроить кастомные биндинги и увязки с моделью
 /// </summary>
 /// <param name="ids"></param>
 /// <param name="dbConnection"></param>
 /// <param name="context"></param>
 protected virtual void AfterUpdateCache(IList <long> ids, IDbConnection dbConnection, ObjectDataCacheHints context)
 {
     if (null != OnAfterUpdateCache)
     {
         OnAfterUpdateCache.Invoke(this, ids, dbConnection, context);
     }
 }
        /// <summary>
        /// Низкоуровневый метод обновления после запроса
        /// </summary>
        /// <param name="query"></param>
        /// <param name="options"></param>
        /// <param name="c"></param>
        /// <param name="allids"></param>
        /// <param name="cascade"></param>
        public List <long> UpdateSingleQuery(string query, ObjectDataCacheHints options, IDbConnection c, List <long> allids, bool cascade)
        {
            options = options ?? ObjectDataCacheHints.Empty;
            object eq = query;

            if (options.KeyQuery)
            {
                eq = options.Key;
                var external = GetByExternals(eq);
                if (null != external)
                {
                    Set(external);
                    var exids = new[] { ((IWithId)external).Id };
                    if (cascade)
                    {
                        AfterUpdateCache(exids, c, new ObjectDataCacheHints {
                            NoChildren = true
                        });
                    }
                    return(exids.ToList());
                }
            }
            else
            {
                var externals = FindByExternals(eq).ToArray();
                if (externals.Any())
                {
                    var exarray = externals.ToArray();
                    foreach (var e in externals.ToArray())
                    {
                        Set(e);
                    }
                    var exids = exarray.OfType <IWithId>().Select(_ => _.Id).ToArray();
                    if (cascade)
                    {
                        AfterUpdateCache(exids, c, new ObjectDataCacheHints {
                            NoChildren = true
                        });
                    }
                    return(exids.ToList());
                }
            }



            allids = allids ?? new List <long>();
            if (null == c)
            {
                return(allids);
            }
            var q = query;

            if (!q.Contains("from"))
            {
                q = "select Id from " + Adapter.GetTableName();
                if (!string.IsNullOrWhiteSpace(query))
                {
                    q += " where " + query;
                }
            }

            if (string.IsNullOrWhiteSpace(c.ConnectionString))
            {
                throw new Exception("bad connection string!!!");
            }
            c.WellOpen();
            var cmd = c.CreateCommand(q);
            var ids = new List <long>();

            SqlLog.Trace(q);
            using (var idsReader = cmd.ExecuteReader()){
                while (idsReader.Read())
                {
                    var id = Convert.ToInt64(idsReader.GetValue(0));
                    if (!_nativeCache.ContainsKey(id))
                    {
                        ids.Add(id);
                    }
                    if (!allids.Contains(id))
                    {
                        allids.Add(id);
                    }
                }
            }
            if (ids.Count != 0)
            {
                q = "(Id in (" + string.Join(",", ids) + "))";

                cmd = c.CreateCommand(Adapter.PrepareSelectQuery(q));
                SqlLog.Trace(cmd.CommandText);
                using (var reader = cmd.ExecuteReader()){
                    var items = Adapter.ProcessRecordSet(reader, true).ToArray();
                    foreach (var item in items)
                    {
                        Set(item);
                    }
                }
                if (cascade)
                {
                    AfterUpdateCache(ids, c, options);
                }
            }
            return(allids);
        }