using SQLite.CodeFirst; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Common; using System.Data.Entity; using System.Data.Entity.Core.Common; using System.Data.Entity.Core.Common.CommandTrees; using System.Data.Entity.Core.Metadata.Edm; using System.Data.Entity.Infrastructure; using System.Data.Entity.Infrastructure.Interception; using System.Data.Entity.ModelConfiguration.Conventions; using System.Data.Entity.Validation; using System.Data.SQLite; using System.Data.SQLite.EF6; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; using XdCxRhDW.Entity; namespace XdCxRhDW.Repostory { class DbTableColumnInfo { public string name { get; set; } public string type { get; set; } public int notnull { get; set; } public int pk { get; set; } } public class DbContextBase : DbContext { public DbContextBase(string nameOrConnectionString) : base(nameOrConnectionString) { } public DbContextBase(DbConnection con, bool contextOwnsConnection) : base(con, contextOwnsConnection) { } /// /// 同步数据库表、字段、索引 /// public void SyncDb() { SyncTable(); SyncTableField(); SyncIndex(); } /// /// 手动创建组合索引(如果不存在) /// public void CreateCombinedIndex(Expression> expr) { var props = ((NewExpression)expr.Body).Members.Select(p => p.Name).OrderBy(p => p).ToList(); if (props.Count < 1) return; var name = string.Join("_", props); var tableName = typeof(TEntityType).GetCustomAttribute()?.Name; if (string.IsNullOrWhiteSpace(tableName)) tableName = typeof(TEntityType).Name; string indexName = $"IX_{tableName}_{name}"; StringBuilder sb = new StringBuilder(); int idx = 0; foreach (var item in props) { if (idx < props.Count - 1) sb.Append($"'{item}',"); else sb.Append($"'{item}'"); idx++; } var columnStr = sb.ToString(); var index = this.Database.SqlQuery($"SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='{tableName}' and name='{indexName}'").FirstOrDefault(); if (index == null) this.Database.ExecuteSqlCommand($"CREATE INDEX '{indexName}' ON {tableName} ({columnStr})"); } /// /// 手动创建组合索引(如果不存在) /// public void CreateCombinedIndex(string tableName, string[] propNames) { if (string.IsNullOrWhiteSpace(tableName)) return; if (propNames == null || propNames.Length == 0) return; var props = propNames.OrderBy(p => p).ToList(); var name = string.Join("_", props); string indexName = $"IX_{tableName}_{name}"; StringBuilder sb = new StringBuilder(); int idx = 0; foreach (var item in props) { if (idx < props.Count - 1) sb.Append($"'{item}',"); else sb.Append($"'{item}'"); idx++; } var columnStr = sb.ToString(); var index = this.Database.SqlQuery($"SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='{tableName}' and name='{indexName}'").FirstOrDefault(); if (index == null) this.Database.ExecuteSqlCommand($"CREATE INDEX '{indexName}' ON {tableName} ({columnStr})"); } void SyncIndex() { var tables = this.Database.SqlQuery("select name from sqlite_master where type='table' and name not like 'sqlite%'").ToList(); var props = this.GetType().GetProperties(); List entityTypes = new List(); foreach (var prop in props) { bool isDbSet = prop.PropertyType.IsGenericType && typeof(DbSet<>) == prop.PropertyType.GetGenericTypeDefinition(); if (isDbSet) { var entityType = prop.PropertyType.GenericTypeArguments[0]; entityTypes.Add(entityType); } } foreach (var table in tables) { var res = this.Database.SqlQuery($"PRAGMA table_info([{table}])").ToList(); var entityType = entityTypes.FirstOrDefault(p => p.Name == table); if (entityType == null) continue; //创建具有Index特性的索引列 var entityProps = entityType.GetProperties().Where(p => p.CanRead && p.Name.ToUpper() != "ID" && p.CanWrite && !p.GetMethod.IsVirtual && p.GetCustomAttribute() != null && p.GetCustomAttribute() == null); foreach (var prop in entityProps) { var index = this.Database.SqlQuery($"SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='{table}' and name='IX_{table}_{prop.Name}'").FirstOrDefault(); if (index == null) { this.Database.ExecuteSqlCommand($"CREATE INDEX 'IX_{table}_{prop.Name}' ON {table} ('{prop.Name}')"); } } //创建类上具有IndexCombined特性的组合索引 var attrs = entityType.GetCustomAttributes(); foreach (var item in attrs) { CreateCombinedIndex(table, item.Names); } } } void SyncTable() { var tables = this.Database.SqlQuery("select name from sqlite_master where type='table' and name not like 'sqlite%'").ToList(); var props = this.GetType().GetProperties(); Dictionary list = new Dictionary(); foreach (var prop in props) { bool isDbSet = prop.PropertyType.IsGenericType && typeof(DbSet<>) == prop.PropertyType.GetGenericTypeDefinition(); if (isDbSet) { var entityType = prop.PropertyType.GenericTypeArguments[0]; var name = entityType.GetCustomAttribute()?.Name; if (name == null) { name = entityType.Name; } list.Add(name, entityType); } } foreach (var item in list) { if (!tables.Contains(item.Key)) { var entityProps = item.Value.GetProperties().Where(p => p.CanRead && p.CanWrite && !p.GetMethod.IsVirtual && p.GetCustomAttribute() == null); item.Value.GetProperties().Where(p => p.CanWrite); StringBuilder sb = new StringBuilder(); sb.Append($"create table {item.Key}(ID integer primary key autoincrement"); foreach (var prop in entityProps) { if (prop.Name.ToLower() == "id") continue; bool isNullable = prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>); string typeStr = ""; var type = prop.PropertyType; if (prop.PropertyType.IsGenericType) { type = prop.PropertyType.GenericTypeArguments[0]; } if (type == typeof(string)) { typeStr = "nvarchar"; } else if (type == typeof(int) || type == typeof(long) || prop.PropertyType.IsEnum) { typeStr = "int"; } else if (type == typeof(double) || type == typeof(float)) { typeStr = "float"; } else if (type == typeof(DateTime)) { typeStr = "datetime"; } sb.Append($",{prop.Name} {typeStr}"); if (!isNullable) { sb.Append(" not null"); } } sb.Append(")"); string createTableSql = sb.ToString(); Database.ExecuteSqlCommand(createTableSql); } } } void SyncTableField() { var tables = this.Database.SqlQuery("select name from sqlite_master where type='table' and name not like 'sqlite%'").ToList(); var props = this.GetType().GetProperties(); List entityTypes = new List(); foreach (var prop in props) { bool isDbSet = prop.PropertyType.IsGenericType && typeof(DbSet<>) == prop.PropertyType.GetGenericTypeDefinition(); if (isDbSet) { var entityType = prop.PropertyType.GenericTypeArguments[0]; entityTypes.Add(entityType); } } foreach (var table in tables) { var res = this.Database.SqlQuery($"PRAGMA table_info([{table}])").ToList(); var entityType = entityTypes.FirstOrDefault(p => p.Name == table); if (entityType == null) continue; var entityProps = entityType.GetProperties().Where(p => p.CanRead && p.CanWrite && !p.GetMethod.IsVirtual && p.GetCustomAttribute() == null); foreach (var prop in entityProps) { var find = res.Find(p => p.name.ToLower() == prop.Name.ToLower()); if (find == null) { string typeStr = ""; var type = prop.PropertyType; if (prop.PropertyType.IsGenericType) { type = prop.PropertyType.GenericTypeArguments[0]; } if (type == typeof(string)) { typeStr = "nvarchar"; } else if (type == typeof(int) || type == typeof(long) || prop.PropertyType.IsEnum) { typeStr = "int"; } else if (type == typeof(double) || type == typeof(float)) { typeStr = "float"; } else if (type == typeof(DateTime)) { typeStr = "datetime"; } bool isNullable = prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>); string updateTableSql; if (isNullable) updateTableSql = $"alter table {table} add column {prop.Name} {typeStr}"; else { if (typeStr == "int" || typeStr == "float") updateTableSql = $"alter table {table} add column {prop.Name} {typeStr} not null default 0"; else if (typeStr == "nvarchar") updateTableSql = $"alter table {table} add column {prop.Name} {typeStr} not null default ''"; else if (typeStr == "datetime") updateTableSql = $"alter table {table} add column {prop.Name} {typeStr} not null default '{DateTime.Now:yyyy-MM-dd HH:mm:ss}'"; else updateTableSql = $"alter table {table} add column {prop.Name} {typeStr}"; } this.Database.ExecuteSqlCommand(updateTableSql); } } } } } public class RHDWLogContext : DbContextBase { public string DbFile; public RHDWLogContext() : base("LogDbCon") //配置使用的连接名 { //|DataDirectory|在mvc等程序中代表了App_Data,在普通程序中代表程序根目录 var dbFile = Database.Connection.ConnectionString.Replace("Data Source=", "").Replace("|DataDirectory|\\", ""); this.DbFile = dbFile; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { this.Database.Log = msg => { }; modelBuilder.Conventions.Remove(); modelBuilder.Configurations.AddFromAssembly(typeof(RHDWLogContext).Assembly);//自动加载Entity-Type var sqliteConnectionInitializer = new SqliteCreateDatabaseIfNotExists(modelBuilder); Database.SetInitializer(sqliteConnectionInitializer); base.OnModelCreating(modelBuilder); } public DbSet LogRes { set; get; } } /// /// 基础表上下文(id为int) /// public class RHDWContext : DbContextBase { public string DbFile; public RHDWContext() : base("DbCon") //配置使用的连接名 { //|DataDirectory|在mvc等程序中代表了App_Data,在普通程序中代表程序根目录 this.DbFile = Database.Connection.ConnectionString.Replace("Data Source=", "").Replace("|DataDirectory|\\", ""); } public Task> SqlQueryAsync(string sql) { return this.Database.SqlQuery(sql).ToListAsync(); } public Task SqlQueryOneAsync(string sql) { return this.Database.SqlQuery(sql).FirstOrDefaultAsync(); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { this.Database.Log = msg => { }; modelBuilder.Conventions.Remove(); modelBuilder.Configurations.AddFromAssembly(typeof(RHDWContext).Assembly);//自动加载Entity-Type var sqliteConnectionInitializer = new SqliteCreateDatabaseIfNotExists(modelBuilder); Database.SetInitializer(sqliteConnectionInitializer); base.OnModelCreating(modelBuilder); } public DbSet XlInfos { set; get; } public DbSet RefCgRes { get; set; } public DbSet TaskInfos { set; get; } public DbSet TaskSigs { set; get; } public DbSet TxInfos { get; set; } public DbSet SatInfos { get; set; } public DbSet CDBSatInfos { get; set; } public DbSet SigInfos { get; set; } public DbSet SigDelays { get; set; } public DbSet TargetInfos { get; set; } public DbSet SysSetings { get; set; } } /// /// 分区表上下文(id为long) /// public class RHDWPartContext : DbContextBase { private string DbFile; public static RHDWPartContext GetContext(string dbFile, bool createDb = false) { if (!File.Exists(dbFile) && !createDb) { return null; } var connectionString = $@"Data Source={dbFile}"; SQLiteConnection con = new SQLiteConnection(connectionString); return new RHDWPartContext(con); } public static RHDWPartContext GetContext(DateTime partTime, bool createDb = false, string prefix = "") { var dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DbPart"); var dayFile = Path.Combine(dir, $@"{partTime.Year}\{prefix}{partTime:MMdd}.db"); if (!File.Exists(dayFile) && !createDb) { return null; } var connectionString = $@"Data Source=|DataDirectory|\DbPart\{partTime.Year}\{prefix}{partTime:MMdd}.db"; SQLiteConnection con = new SQLiteConnection(connectionString); return new RHDWPartContext(con); } private RHDWPartContext(DbConnection con) : base(con, true) { var dbFile = Database.Connection.ConnectionString.Replace("Data Source=", "").Replace("|DataDirectory|\\", ""); this.DbFile = dbFile; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { this.Database.Log = msg => { }; modelBuilder.Conventions.Remove(); modelBuilder.Configurations.AddFromAssembly(typeof(RHDWPartContext).Assembly); var sqliteConnectionInitializer = new SqliteCreateDatabaseIfNotExists(modelBuilder); Database.SetInitializer(sqliteConnectionInitializer); base.OnModelCreating(modelBuilder); } public DbSet StationRes { get; set; } public DbSet CxRes { get; set; } public DbSet CgRes { get; set; } public DbSet CgXgfRes { get; set; } public DbSet PosRes { get; set; } public DbSet CheckRes { get; set; } } public class SqliteConfiguration : DbConfiguration { public SqliteConfiguration() { DbInterception.Add(new SqliteInterceptor());//拦截器 SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance); SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance); SetProviderServices("System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices))); } } }