BulkDB.cs 14.3 KB
Newer Older
1 2
using FLY.Thick.Blowing.IService;
using FObjBase;
3
using FObjBase.Reflect;
4
using Misc;
5
using SQLite;
6 7 8 9 10 11 12 13 14 15 16
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FLY.Thick.Blowing.Server.Model
{
    /// <summary>
    /// 提供接口,让别人获取 整理好的 当前生产,或之前生产的数据。
潘栩锋's avatar
潘栩锋 committed
17
    /// 从LocalDb 获取数据, 或从 直接从数据获取数据
18
    /// 
潘栩锋's avatar
潘栩锋 committed
19 20 21
    /// 与HistoryDb,成对。 
    /// HistoryDb 是写
    /// BulkDb 是读
22
    /// </summary>
潘栩锋's avatar
潘栩锋 committed
23
    public class BulkDb : IBulkDbService
24
    {
潘栩锋's avatar
潘栩锋 committed
25 26 27
        /// <summary>
        /// 本地数据库
        /// </summary>
28
        LocalDb localDb;
潘栩锋's avatar
潘栩锋 committed
29 30
        DbModel dbModel;
        IShareDbService shareDb;
31 32 33 34 35 36 37 38 39

        /// <summary>
        /// 最后一条扫描数据Id
        /// </summary>
        public long LastScanDataId { get; private set; } = -1;
        /// <summary>
        /// 最后一条产品Id
        /// </summary>
        public long LastProfileId { get; private set; } = -1;
40
        /// <summary>
41
        /// 数据库最后一次被修改时间
42
        /// </summary>
43 44
        public DateTime LastTimestamp { get; private set; }

45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60

        /// <summary>
        /// 开始产生数据时间
        /// </summary>
        public DateTime StartTime { get; private set; }

        /// <summary>
        /// 最后产生数据时间
        /// </summary>
        public DateTime EndTime { get; private set; }

        /// <summary>
        /// 当前生产,已经结束,已经下辊了
        /// </summary>
        public bool IsFinished { get; private set; }

潘栩锋's avatar
潘栩锋 committed
61 62 63
        /// <summary>
        /// 
        /// </summary>
64 65
        public event PropertyChangedEventHandler PropertyChanged;

潘栩锋's avatar
潘栩锋 committed
66
        /// <summary>
67
        /// 临时数据改变
潘栩锋's avatar
潘栩锋 committed
68
        /// </summary>
69 70
        [Push(typeof(BulkDbTempFrameChangedEventArgs))]
        public event EventHandler TempFrameChanged;
潘栩锋's avatar
潘栩锋 committed
71

72
        public Func<BulkDbTempFrameChangedEventArgs> GetTempFrameAction;
潘栩锋's avatar
潘栩锋 committed
73 74 75 76
        /// <summary>
        /// 
        /// </summary>
        public BulkDb()
77 78 79 80
        {

        }

潘栩锋's avatar
潘栩锋 committed
81 82 83 84 85
        /// <summary>
        /// 写入动态数据
        /// </summary>
        /// <param name="startIndex"></param>
        /// <param name="D"></param>
86
        public void SetTempFrame(DateTime time, DateTime endTime, int startIndex, double[] D)
87
        {
88
            TempFrameChanged?.Invoke(this, new BulkDbTempFrameChangedEventArgs() { Time = time, EndTime = endTime, StartIndex = startIndex, D = D });
89 90
        }

91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
        /// <summary>
        /// 获取临时数据
        /// </summary>
        /// <param name="request"></param>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        [Call(typeof(BulkDbTempFrameChangedEventArgs))]
        public void GetTempFrame(
            AsyncCBHandler asyncDelegate, object asyncContext)
        {
            BulkDbTempFrameChangedEventArgs e;
            if (GetTempFrameAction != null)
                e = GetTempFrameAction();
            else
                e = new BulkDbTempFrameChangedEventArgs();
            asyncDelegate?.Invoke(asyncContext, e);
        }
潘栩锋's avatar
潘栩锋 committed
108 109 110 111 112 113 114

        /// <summary>
        /// 
        /// </summary>
        /// <param name="shareDb"></param>
        /// <param name="localDb"></param>
        /// <param name="dbModel"></param>
115
        public void Init(IShareDbService shareDb,
潘栩锋's avatar
潘栩锋 committed
116
             LocalDb localDb, DbModel dbModel)
117
        {
潘栩锋's avatar
潘栩锋 committed
118
            this.localDb = localDb;
119

潘栩锋's avatar
潘栩锋 committed
120 121
            this.dbModel = dbModel;
            this.shareDb = shareDb;
122 123 124 125

            LocalDBLoad();


126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
            Misc.BindingOperations.SetBinding(localDb, nameof(localDb.ProfileStartTime), this, nameof(StartTime));
            Misc.BindingOperations.SetBinding(localDb, nameof(localDb.ProfileEndTime), this, nameof(EndTime));
            Misc.BindingOperations.SetBinding(localDb, nameof(localDb.IsProfileFinished), this, nameof(IsFinished));

            this.shareDb.ProfileChanged += ShareDB_ProfileChanged;
            this.shareDb.ScanDataAdded += ShareDB_ScanDataAdded;

        }

        private void ShareDB_ProfileChanged(object sender, EventArgs _e)
        {
            ProfileChangedEventArgs e = (ProfileChangedEventArgs)_e;

            var profile = e.profile;
            //清除本地缓存
            localDb.CurrProfile = profile;
            localDb.ProfileStartTime = profile.StartTime;
            localDb.ProfileEndTime = profile.EndTime;
            localDb.IsProfileFinished = profile.IsFinished;
145

146 147
            LastProfileId = profile.ID;
            LastTimestamp = DateTime.Now;
148 149
        }

150
        private void ShareDB_ScanDataAdded(object sender, EventArgs _e)
151
        {
152 153 154 155
            ScanDataAddedEventArgs e = (ScanDataAddedEventArgs)_e;

            LastScanDataId = e.scandata.ID;
            LastTimestamp = DateTime.Now;
156 157 158 159 160 161 162
        }

        /// <summary>
        /// 加载数据库中最后1次订单数据到 本地
        /// </summary>
        void LocalDBLoad()
        {
163
            var reponse = dbModel.sqliteHelper.ExecuteScalar($"SELECT MAX({nameof(Db_Profile.ID)}) FROM {dbModel.TbProfile.TableName}");
164 165
            if (reponse is DBNull)
            {
潘栩锋's avatar
潘栩锋 committed
166 167 168
                localDb.ProfileStartTime = DateTime.MinValue;
                localDb.ProfileEndTime = DateTime.MinValue;
                localDb.IsProfileFinished = true;
169
                return;
170
            }
171 172 173 174 175 176 177

            long maxid = System.Convert.ToInt64(reponse);
            var profile = dbModel.TbProfile.Find($"WHERE {nameof(Db_Profile.ID)} = {maxid}").First();


            reponse = dbModel.sqliteHelper.ExecuteScalar($"SELECT MAX({nameof(Db_ScanData.ID)}) FROM {dbModel.TbScanData.TableName}");
            if (!(reponse is DBNull))
178
            {
179 180
                maxid = System.Convert.ToInt64(reponse);
                LastScanDataId = maxid;
181
            }
182 183 184 185 186 187

            localDb.CurrProfile = profile;
            localDb.ProfileStartTime = profile.StartTime;
            localDb.ProfileEndTime = profile.EndTime;
            localDb.IsProfileFinished = profile.IsFinished;
            LastProfileId = profile.ID;
188
        }
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216

        /// <summary>
        /// 获取profile
        /// </summary>
        /// <param name="request"></param>
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        [Call(typeof(Pack_GetProfileReponse))]
        public async void GetProfile(
            Pack_GetProfileRequest request,
            AsyncCBHandler asyncDelegate, object asyncContext)
        {
            Pack_GetProfileReponse reponse = new Pack_GetProfileReponse();
            reponse.Request = request;

            await Task.Factory.StartNew(() =>
            {
                List<Db_Profile> db_profiles = dbModel.TbProfile.Find($"WHERE {nameof(Db_Profile.ID)} = {request.Id}");

                if (db_profiles.Count() == 0)
                    return;

                reponse.profile = db_profiles.First();
            });

            asyncDelegate(asyncContext, reponse);
        }

217 218 219 220 221 222
        /// <summary>
        /// 获取N幅数据,需要异步
        /// </summary>
        /// <param name="request"></param>
        /// <param name="AsyncDelegate"></param>
        /// <param name="AsyncContext"></param>
223
        public async void GetFrame(Pack_GetFrameRequest request, AsyncCBHandler asyncDelegate, object asyncContext)
224 225 226
        {
            Pack_GetFrameReponse reponse = new Pack_GetFrameReponse();
            reponse.Request = request;
227 228 229 230
            if (request.Mix > 10)//数量限制,避免死机
                request.Mix = 10;
            else if (request.Mix < 1)
                request.Mix = 1;
231 232 233

            await Task.Factory.StartNew(() =>
            {
234 235 236 237 238 239 240 241 242 243 244 245 246
                List<Db_ScanData> db_scandatas;
                if (request.Id <= 0)
                    db_scandatas = dbModel.TbScanData.Find(
                        $"ORDER BY {nameof(Db_ScanData.ID)} DESC" +
                        $" LIMIT {request.Mix} OFFSET {-request.Id}");
                else
                    db_scandatas = dbModel.TbScanData.Find(
                        $"WHERE {nameof(Db_ScanData.ID)} <= {request.Id}" +
                        $" ORDER BY ID DESC LIMIT {request.Mix}");

                if (db_scandatas.Count() == 0)
                    return;

247
                var lc_scanDatas = Lc_AutoMapperProfile.Mapper.Map<List<Db_ScanData>, List<Lc_ScanData>>(db_scandatas);
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
                var lc_scanData = lc_scanDatas.First();
                if (lc_scanDatas.Count() > 1)
                {
                    //求均值
                    lc_scanData.Thicks = GetMixScanData(lc_scanDatas, 0, lc_scanDatas.Count());
                }

                reponse.scanData = lc_scanData;

                //找profile
                var db_profiles = dbModel.TbProfile.Find(
                    $"WHERE {nameof(Db_Profile.StartTime)}<={lc_scanData.EndTime.ToStringOfSQLiteFieldType()}" +
                    $" AND {nameof(Db_Profile.EndTime)}>={lc_scanData.EndTime.ToStringOfSQLiteFieldType()}" +
                    $" ORDER BY {nameof(Db_Profile.ID)} DESC");
                if (db_profiles.Count() > 0)
                {
                    reponse.profile = db_profiles.First();
                }

267 268
            });

269
            asyncDelegate(asyncContext, reponse);
270 271 272 273 274 275
        }

        /// <summary>
        /// 获取纵向趋势图
        /// </summary>
        /// <param name="request"></param>
潘栩锋's avatar
潘栩锋 committed
276 277 278
        /// <param name="asyncDelegate"></param>
        /// <param name="asyncContext"></param>
        public async void GetTrend(Pack_GetTrendRequest request, AsyncCBHandler asyncDelegate, object asyncContext)
279 280 281 282
        {
            //TODO 需要异步
            Pack_GetTrendReponse reponse = new Pack_GetTrendReponse();
            reponse.Request = request;
283

284 285
            if (request.Count > 400)//数量限制,避免死机
                request.Count = 400;
286 287 288 289 290 291 292 293
            else if (request.Count < 1)
                request.Count = 1;

            if (request.Mix > 10)//数量限制,避免死机
                request.Mix = 10;
            else if (request.Mix < 1)
                request.Mix = 1;

潘栩锋's avatar
潘栩锋 committed
294 295
            if (request.Interval < 1)//避免 /0
                request.Interval = 1;
296 297


潘栩锋's avatar
潘栩锋 committed
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
                await Task.Factory.StartNew(() =>
                {
                    List<Db_ScanData> db_scandatas=null;
                    if (!request.IsSearchByTime)
                    {
                        if (request.Id <= 0)
                            db_scandatas = dbModel.TbScanData.Find(
                                $"WHERE {nameof(Db_ScanData.ID)} % {request.Interval} = 0" +
                                $" ORDER BY {nameof(Db_ScanData.ID)} DESC" +
                                $" LIMIT {request.Mix + request.Count - 1} OFFSET {-request.Id}");
                        else
                            db_scandatas = dbModel.TbScanData.Find(
                                $"WHERE ({nameof(Db_ScanData.ID)} <= {request.Id})" +
                                $" AND ({nameof(Db_ScanData.ID)} % {request.Interval} = 0)" +
                                $" ORDER BY {nameof(Db_ScanData.ID)} DESC" +
                                $" LIMIT {request.Mix + request.Count - 1}");
                    }
                    else 
                    {
                        db_scandatas = dbModel.TbScanData.Find(
                                $"WHERE ({nameof(Db_ScanData.Time)} <= {request.Time.ToStringOfSQLiteFieldType()})" +
                                $" AND ({nameof(Db_ScanData.ID)} % {request.Interval} = 0)" +
                                $" ORDER BY {nameof(Db_ScanData.ID)} DESC" +
                                $" LIMIT {request.Mix + request.Count - 1}");
                    }


                    if (db_scandatas.Count() == 0)
                        return;
327 328

                //从尾向前排的!!!!
329
                var lc_scanDatas = Lc_AutoMapperProfile.Mapper.Map<List<Db_ScanData>, List<Lc_ScanData>>(db_scandatas);
330

潘栩锋's avatar
潘栩锋 committed
331
                    reponse.Values = ToTrend(lc_scanDatas, request.Count, request.Mix);
332

潘栩锋's avatar
潘栩锋 committed
333 334
                    var lc_scanData = lc_scanDatas.First();
                    reponse.ScanDataId = lc_scanData.ID;
335

潘栩锋's avatar
潘栩锋 committed
336 337 338 339

                });
            
            asyncDelegate(asyncContext, reponse);
340 341
        }

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
        double[] GetMixScanData(List<Lc_ScanData> lc_scanDatas, int offset, int mix)
        {

            var lc_scanData = lc_scanDatas[offset];
            //求均值
            double[] thks = new double[lc_scanData.Thicks.Count()];
            int cnt = 0;
            for (int j = offset; j < offset + mix && j < lc_scanDatas.Count(); j++)
            {
                int index = j;
                if (lc_scanDatas[index].Thicks.Count() != thks.Count())
                {
                    //结束
                    break;
                }

                for (int i = 0; i < thks.Count(); i++)
                {
                    thks[i] += lc_scanDatas[index].Thicks[i];
                }
                cnt++;
            }
            for (int i = 0; i < thks.Count(); i++)
            {
                thks[i] /= cnt;
            }

            return thks;
        }
        List<TrendValue> ToTrend(List<Lc_ScanData> lc_scanDatas, int count, int mix)
        {

            if (mix == 1)
            {
                return lc_scanDatas.Select(sd =>
                {
                    double avg = sd.Thicks.AverageNoNull();
                    double sigma = sd.Thicks.Sigma();
                    return new TrendValue()
                    {
                        Sigma = sigma,
                        Value = avg,
                        Time = sd.Time
                    };
                }).ToList();
            }

            List<TrendValue> trendValues = new List<TrendValue>();

            for (int i = 0; i < lc_scanDatas.Count() && i < count; i++)
            {
                //求均值
                double[] thks = GetMixScanData(lc_scanDatas, i, mix);
                double avg = thks.AverageNoNull();
                double sigma = thks.Sigma();

                trendValues.Add(new TrendValue()
                {
                    Sigma = sigma,
                    Value = avg,
                    Time = lc_scanDatas[i].Time
                });
            }
            return trendValues;
        }
407 408 409 410 411
        /// <summary>
        /// 完成
        /// </summary>
        public void Finish()
        {
潘栩锋's avatar
潘栩锋 committed
412
            shareDb.FinishProfile();
413 414 415 416
        }

    }
}