Sqlite CodeFirst的初级实现
示例实体:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics.CodeAnalysis;
using Honeysuckle.Domain.Entities; namespace Chagoi.Pos.Core.Entity.Goods
{
[Table("a2")]
[SuppressMessage("ReSharper", "InconsistentNaming")]
public class GoodsInfo : Entity<int>
{
[Column("c1")]
public string Name { get; set; } /// <summary>
/// 商品条码
/// </summary>
[Column("c2")]
[StringLength()]
[Index]
public string goods_barcode { get; set; } /// <summary>
/// 简称
/// </summary>
[Column("c3")]
[StringLength()]
[Index("fdafd")]
public string goods_short_name { get; set; } [Column("c4")]
[StringLength()]
[Required]
public string hello { get; set; } [Column("c5")]
public DateTime UpdateTime { get; set; }
} }
生成代码:
using Castle.Core.Logging;
using Chagoi.Pos.Core.Entity.Device;
using Chagoi.Pos.Core.Entity.Goods;
using Chagoi.Pos.Core.Entity.Order;
using Chagoi.Pos.Core.Entity.Pay;
using Chagoi.Pos.Core.Entity.Users;
using Honeysuckle.Dependency;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Configuration;
using System.Data;
using System.Data.SQLite;
using System.Diagnostics;
using System.Linq;
using System.Text; namespace Chagoi.Pos.EntityFramework.Seed
{
public static class SeedHelper
{
private static readonly string DbPath;
private static ILogger _logger; static SeedHelper()
{
DbPath = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
} public static void SeedHostDb(IIocResolver iocResolver, ILogger logger)
{
_logger = logger;
SeedHostDb();
} private static void SeedHostDb()
{
var tobeCreateTables = new List<Type>()
{
typeof(IotDevice), typeof(GoodsInfo),
typeof(GoodsCategory),
typeof(GoodsBrand), typeof(AlipayParameter),
typeof(WxpayParameter), typeof(AppUser),
typeof(Order)
}; _logger.Info("#region 开始执行数据库的创建或结构调整"); var stopwatch = new Stopwatch();
stopwatch.Start(); using (var connection = new SQLiteConnection(DbPath))
{
connection.Open(); using (var transaction = connection.BeginTransaction())
{
try
{
foreach (var entity in tobeCreateTables)
{
//表名称,这里使用混淆表明,要求必须输入
var tableAttribute = entity.GetCustomAttributes(typeof(TableAttribute), true).FirstOrDefault();
if (null == tableAttribute)
{
throw new ArgumentNullException(nameof(TableAttribute));
}
var tableName = ((TableAttribute)tableAttribute).Name; //填充数据库中标的原始结构
var tableStructureCommandText = $"PRAGMA table_info(\"{tableName}\");";
var sqLiteCommand = new SQLiteCommand(connection) { CommandText = tableStructureCommandText };
var sQLiteDataAdapter = new SQLiteDataAdapter(sqLiteCommand);
var tableStructure = new DataTable(tableName);
sQLiteDataAdapter.Fill(tableStructure); var hasTable = tableStructure.Rows.Count > ;
if (!hasTable)
{
_logger.Info($"表{tableName}不存在,开始执行创建过程..."); //执行创建表的SQL语句
var createTableSql = GenerateCreateTableCommandText(entity, tableName);
sqLiteCommand.CommandText = createTableSql;
_logger.Debug(sqLiteCommand.CommandText);
sqLiteCommand.ExecuteNonQuery();
_logger.Info($"表{tableName}的创建语句已执行.");
}
else
{
_logger.Info($"表{tableName}已经存在,开始执行差异对比过程...");
var updateTableSql = GenerateUpdateTableCommandText(entity, tableStructure);
if (string.IsNullOrEmpty(updateTableSql))
{
_logger.Info($"表{tableName}结构无差异,无需调整.");
continue;
}
sqLiteCommand.CommandText = updateTableSql;
_logger.Debug(sqLiteCommand.CommandText);
var nonQuery = sqLiteCommand.ExecuteNonQuery();
_logger.Info($"表{tableName}的调整语句已执行,返回结果:{nonQuery}");
}
} transaction.Commit();
}
catch (Exception ex)
{
_logger.Error("执行数据库的创建或结构调整过程发生异常",ex);
transaction.Rollback();
}
} connection.Dispose();
} stopwatch.Stop(); var elapsedMilliseconds = stopwatch.ElapsedMilliseconds; _logger.Info($"#endregion 执行数据库的创建或结构调整过程完毕,耗时{elapsedMilliseconds}毫秒");
} /// <summary>
/// 生成创建表的sql命令,包含索引的创建
/// </summary>
/// <param name="entityType">实体类型</param>
/// <param name="tableName">表的名称</param>
/// <returns></returns>
private static string GenerateCreateTableCommandText(Type entityType, string tableName)
{
var properties = entityType.GetProperties(); //索引创建语句,根据实体的Index特性来生成
var createTableIndexCommandTexts = new List<string>(); var createTableCommandText = $"CREATE TABLE \"{tableName}\" (";
foreach (var property in properties)
{
//列名,优先取特性名称
var columnName = GetColumnName(property); //是否可空
var notNull = IsNotNull(property); //字段类型
var dbType = GetDbType(property); createTableCommandText += $"\"{columnName}\" {dbType} {notNull},"; //处理索引
var indexAttributeObj = property.GetCustomAttributes(typeof(IndexAttribute), true).FirstOrDefault();
if (null != indexAttributeObj)
{
var indexAttribute = ((IndexAttribute)indexAttributeObj); //是否是唯一索引
var unique = indexAttribute.IsUnique ? "UNIQUE" : ""; //索引名称
var indexName = string.IsNullOrEmpty(indexAttribute.Name) ? $"Index_{columnName}" : indexAttribute.Name; //创建索引的语句
var indexSql = $"CREATE {unique} INDEX \"{indexName}\" ON \"{tableName}\"(\"{columnName}\" ASC); ";
createTableIndexCommandTexts.Add(indexSql);
}
}
createTableCommandText += "PRIMARY KEY (\"Id\" ASC)";
createTableCommandText += ");"; var allCommandText = new StringBuilder(createTableCommandText);
foreach (var createTableIndexCommandText in createTableIndexCommandTexts)
{
allCommandText.Append(createTableIndexCommandText);
}
return allCommandText.ToString();
} /// <summary>
/// 生成更新表的sql命令,只支持新增列
/// 不支持添加索引列,不支持删除列
/// 新增的列必须允许为空
/// </summary>
/// <param name="entityType">实体类型</param>
/// <param name="dataTable">数据中的表结构</param>
/// <returns></returns>
private static string GenerateUpdateTableCommandText(Type entityType, DataTable dataTable)
{
var properties = entityType.GetProperties();
var alreadyCreatedColumnNames = dataTable.AsEnumerable().Select(t => t.Field<string>("name").ToString()).ToArray(); var addColumnCommandTexts = new List<string>();
foreach (var property in properties)
{
var colName = GetColumnName(property);
var alreadyCreated = alreadyCreatedColumnNames.Any(m => m == colName);
if (!alreadyCreated)
{ var dbType = GetDbType(property);
var addColumnCommandText = $"ALTER TABLE \"{dataTable.TableName}\" ADD COLUMN \"{colName}\" {dbType} NULL;";
addColumnCommandTexts.Add(addColumnCommandText);
}
} var allCommandText = new StringBuilder();
foreach (var addColumnCommand in addColumnCommandTexts)
{
allCommandText.Append(addColumnCommand);
}
return allCommandText.ToString();
} #region 基础函数 /// <summary>
/// 获取数据类型
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
private static string GetDbType(System.Reflection.PropertyInfo property)
{
string dbType;
if (property.PropertyType.FullName != null)
{
var propertyTypeFullName = property.PropertyType.FullName.ToUpper();
switch (propertyTypeFullName)
{
case "SYSTEM.BOOLEAN":
dbType = "BOOLEAN";
break;
case "SYSTEM.INT32":
case "SYSTEM.INT64":
dbType = "INTEGER";
break;
case "SYSTEM.STRING":
//是否标记了最大长度
var stringLengthAttributeObj = property.GetCustomAttributes(typeof(StringLengthAttribute), true).FirstOrDefault();
if (stringLengthAttributeObj != null)
{
var length = ((StringLengthAttribute)stringLengthAttributeObj).MaximumLength;
dbType = $"VARCHAR({length})";
}
else
{
dbType = "TEXT";
}
break;
case "SYSTEM.DATETIME":
dbType = "DATETIME";
break;
default:
throw new ArgumentOutOfRangeException(nameof(propertyTypeFullName));
}
}
else
{
throw new ArgumentNullException(nameof(property.PropertyType.FullName));
} return dbType;
} /// <summary>
/// 字段是否可用
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
private static string IsNotNull(System.Reflection.PropertyInfo property)
{
var hasRequiredAttribute = property.GetCustomAttributes(typeof(RequiredAttribute), true).Length > ;
var notNull = hasRequiredAttribute ? "NOT NULL" : "";
if (property.Name.ToUpper() == "ID") //ID始终不能为空
{
notNull = "NOT NULL";
} return notNull;
} /// <summary>
/// 获取列名
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
private static string GetColumnName(System.Reflection.PropertyInfo property)
{
var columnName = property.Name;
var columnAttributeObj = property.GetCustomAttributes(typeof(ColumnAttribute), true).FirstOrDefault();
if (null != columnAttributeObj)
{
columnName = ((ColumnAttribute)columnAttributeObj).Name;
} return columnName;
} #endregion
}
}
Sqlite CodeFirst的初级实现的更多相关文章
- EntityFramework系列:SQLite.CodeFirst自动生成数据库
http://www.cnblogs.com/easygame/p/4447457.html 在Code First模式下使用SQLite一直存在不能自动生成数据库的问题,使用SQL Server C ...
- C#/.NET VS2017+ EF+SQLite.CodeFirst——真正实现CodeFirst
本文所介绍的是真正的EF+CodeFirst,不需要提前建表,由代码自动生成! 进行前需要准备的: 1.下载Sqlite Experthttp://www.sqliteexpert.com/downl ...
- SQLite 的 CodeFirst 模式
目录 问题描述 解决方案 安装依赖包 修改程序配置 App.config 创建模型对象 Person.cs 创建数据上下文 PersonDbContext.cs 主程序调用 Program.cs 注意 ...
- EntityFramework SQLite
安装完sqlite的nuget包后,还要设置App.config文件才能正常使用 1. 在<providers>节点添加一条提供器配置 <provider invariantNam ...
- 通过EntityFramework操作sqlite(DbFirst)
记录一下通过 EntityFramework6 来操作sqlite过程 环境: visual studio 2017 .net 4.5 Console Application(项目类型) sqlite ...
- visual studio 2013 下ef6 CodeFirst 使用SQL Lite 数据库
今天系统的来记录一下再vs2013下,使用ef6 codefirst功能,来操作SQL lite数据库 本来我以为sqlite数据库用的这么多,ef6肯定支持,结果,使用过程中很多坑,现在我把具体的配 ...
- EntityFramework系列:SQLite的CodeFrist和RowVersion
没什么好说的,能支持DropCreateDatabaseIfModelChanges和RowVersion的Sqlite谁都想要.EntityFramework7正在添加对Sqlite的支持,虽然EF ...
- EF6 Code First 系列 (四):SQLite的DropCreateDatabaseIfModelChanges和乐观并发控制
没什么好说的,能支持DropCreateDatabaseIfModelChanges和RowVersion的Sqlite谁都想要.EntityFramework7正在添加对Sqlite的支持,虽然EF ...
- 【C#】使用EF访问Sqlite数据库
原文:[C#]使用EF访问Sqlite数据库 1. 先上Nuget下载对应的包 如图,搜索System.Data.SQLite下载安装即可,下载完之后带上依赖一共有这么几个: EntityFramew ...
随机推荐
- poj 1611 The Suspects(第一道并查集)
题意: 有N个学生,编号为0-n-1,现在0号学生感染了非典,凡是和0在一个社团的人就会感染, 并且这些人如果还参加了别的社团,他所在的社团照样全部感染,社团个数为m,求感染的人数. 输入: n代表人 ...
- SQL聚集索引和非聚集索引的区别
其实对于非专业的数据库操作人员来讲,例如软件开发人员,在很大程度上都搞不清楚数据库索引的一些基本知识,有些是知其一不知其二,或者是知其然不知其所以然.造成这种情况的主要原因我觉的是行业原因,有很多公司 ...
- 【转】android中layout_weight的理解
android Layout_weight的理解 SDK中的解释: Indicates how much of the extra space in the LinearLayout will be ...
- C# 接口(3)
这么半天说了如何使用,实现接口.相信也都发现了接口和抽象类很多相似的地方. 但是! 这两个根本就是不一样的. 抽象类 : ...
- B - N皇后问题
原文链接 一天课下,张老板研究起了国际象棋,渴望完美的他更改了棋盘的大小,在N*N的方格棋盘放置了N个皇后,希望它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的 ...
- bzoj1070【SCOI2007】修车(费用流)
题目描述 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待 ...
- docker构建mysql容器及Navicat 远程连接
1. MySQL部署 1.1拉取MySQL镜像 docker pull mysql 查看镜像 docker images 1.2创建MySQL容器 首先建立所需要的 文件夹: docker run - ...
- CodeForces - 233A Perfect Permutation
A. Perfect Permutation time limit per test: 2 seconds memory limit per test: 256 megabytes input: st ...
- 数据结构54:平衡二叉树(AVL树)
上一节介绍如何使用二叉排序树实现动态查找表,本节介绍另外一种实现方式——平衡二叉树. 平衡二叉树,又称为 AVL 树.实际上就是遵循以下两个特点的二叉树: 每棵子树中的左子树和右子树的深度差不能超过 ...
- CodeCraft-19 and Codeforces Round #537 (Div. 2) C. Creative Snap 分治
Thanos wants to destroy the avengers base, but he needs to destroy the avengers along with their bas ...