public static IReadOnlyList <File> AddFilesToClass(UpdateFilesArgs args)
        {
            Debug.WriteLine("db begin: " + nameof(AddFilesToClass));
            List <File> fs = new List <File>();

            if (args.Files.Any(p => !p.StartsWith(args.Project.RootPath)))
            {
                throw new Exception("文件不在项目目录下");
            }
            int      index            = 0;
            int      count            = args.Files.Count;
            DateTime lastCallbackTime = DateTime.MinValue;

            foreach (var path in args.Files)
            {
                File f           = new File(new FI(path), args.Project);
                File existedFile = db.Files.FirstOrDefault(p => p.Name == f.Name && p.Dir == f.Dir);
                //文件不存在的话,需要首先新增文件
                if (existedFile == null)
                {
                    args.GenerateThumbnailsMethod?.Invoke(f);
                    //if (args.IncludeThumbnails)
                    //{
                    //    FileUtility.TryGenerateThumbnail(f);
                    //}
                    //if (args.IncludeExplorerIcons)
                    //{
                    //    FileUtility.TryGenerateExplorerIcon(f);
                    //}
                    db.Files.Add(f);
                }
                else
                {
                    var existedFileClass = db.FileClasses.FirstOrDefault(p => p.Class == args.Class && p.File == existedFile);
                    //如果文件已存在,就搜索一下是否存在关系,存在关系就不需要继续了
                    if (existedFileClass != null && existedFileClass.Status != FileClassStatus.Disabled)
                    {
                        goto next;
                    }
                    //存在但被禁用
                    if (existedFileClass != null && existedFileClass.Status == FileClassStatus.Disabled)
                    {
                        fs.Add(existedFile);
                        existedFileClass.Status          = FileClassStatus.Auto;
                        db.Entry(existedFileClass).State = EntityState.Modified;
                        goto next;
                    }
                    f = existedFile;
                }
                db.FileClasses.Add(new FileClass(args.Class, f, true));
                fs.Add(f);
next:
                index++;
                if (args.Callback != null && (DateTime.Now - lastCallbackTime).TotalMilliseconds > CallbackUpdateMs)
                {
                    lastCallbackTime = DateTime.Now;
                    if (!args.Callback(index * 1.0 / count, f))
                    {
                        db.SaveChanges();
                        return(null);
                    }
                }
            }
            SaveChanges();
            Debug.WriteLine("db end: " + nameof(AddFilesToClass));

            return(fs.AsReadOnly());
        }
        public static void UpdateFilesOfClasses(UpdateFilesArgs args)
        {
            Debug.WriteLine("db begin: " + nameof(UpdateFilesOfClasses));

            //dbFiles只在需要刷新物理文件时用到,但是因为有两个作用域,所以写在了外层
            HashSet <File> dbFiles = null;//= new HashSet<File>(Queryable.Where(DbUtility.db.Files, (System.Linq.Expressions.Expression<Func<File, bool>>)(p => (bool)(p.Project == args.Project))));

            List <File> files = null;

            if (args.Research)
            {
                dbFiles = new HashSet <File>(db.Files.Where(p => p.ProjectID == args.Project.ID));
                IReadOnlyList <System.IO.FileSystemInfo> diskFiles = FzLib.IO.FileSystem.EnumerateAccessibleFileSystemInfos(args.Project.RootPath);
                if (args.DeleteNonExistentItems)
                {
                    HashSet <string> paths = new HashSet <string>(diskFiles.Select(p => p.FullName));

                    //删除已不存在的文件
                    foreach (var file in dbFiles)
                    {
                        if (!paths.Contains(file.GetAbsolutePath()))
                        {
                            db.Entry(file).State = EntityState.Deleted;
                        }
                    }
                    db.SaveChanges();
                }
                files = diskFiles
                        .OfType <FI>()
                        .Select(p => new File(p, args.Project)).ToList();
            }
            else
            {
                files = db.Files.Where(p => p.ProjectID == args.Project.ID).Include(p => p.Project).ToList();
            }

            //现在数据库中该项目的所有文件应该都存在相对应的物理文件
            int      index            = 0;
            int      count            = files.Count;
            DateTime lastCallbackTime = DateTime.MinValue;
            var      classes          = db.Classes.ToList();

            foreach (var file in files)
            {
                File f = null;// new File(file, args.Project);
                if (args.Research)
                {
                    //先判断一下数据库中是否已存在该文件
                    if (!dbFiles.Contains(file))
                    {
                        f = file;
                        db.Files.Add(f);
                    }
                    else
                    {
                        //如果数据库中存在该文件,则从HashSet中提取该文件
                        if (!dbFiles.TryGetValue(file, out File newF))
                        {
                            //理论上不会进来
                            Debug.Assert(false);
                        }
                        f = newF;
                    }
                    args.GenerateThumbnailsMethod?.Invoke(f);
                    //if (args.IncludeThumbnails)
                    //{
                    //    FileUtility.TryGenerateThumbnail(f);
                    //}
                    //if (args.IncludeExplorerIcons)
                    //{
                    //    FileUtility.TryGenerateExplorerIcon(f);
                    //}
                }
                else
                {
                    f = file;
                }
                if (args.Reclassify)
                {
                    foreach (var c in classes.Where(p => p.ProjectID == args.Project.ID))
                    {
                        FileClass fc = IncludeAll(db.FileClasses)
                                       .FirstOrDefault(p => p.Class == c && p.File == f);
                        bool isMatched = FileUtility.IsMatched(f.FileInfo, c);
                        if (fc == null && isMatched)
                        {
                            //如果匹配并且不存在,那么新增关系
                            db.Add(new FileClass(c, f, false));
                        }
                        else if (fc != null && !isMatched && fc.Status != FileClassStatus.AddManully)
                        {
                            //如果存在关系但不匹配,那么应该删除已存在的关系
                            //注意,手动删除的关系并不会走到这一步
                            db.Entry(fc).State = EntityState.Deleted;
                        }
                        //其他情况,既不需要增加,也不需要删除
                    }
                }
                index++;
                if (args.Callback != null && (DateTime.Now - lastCallbackTime).TotalMilliseconds > CallbackUpdateMs)
                {
                    lastCallbackTime = DateTime.Now;
                    if (!args.Callback(index * 1.0 / count, f))
                    {
                        db.SaveChanges();
                        return;
                    }
                }
            }

            db.SaveChanges();
            Debug.WriteLine("db end: " + nameof(UpdateFilesOfClasses));
        }