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 ...
随机推荐
- 运行monitor提示需要安装旧JAVA SE 6运行环境
MAC系统下运行monitor命令 ➜ tools git:(master) ✗ monitor 提示如下: 若要打开Eclipse.app,您需要Java SE 6 runtime,您想现在安装一个 ...
- [GO]给导入包起别名
package main import io "fmt" //引用fmt这个包时,名字重命名为io import _ "os" //引用os这个包,但是不调用, ...
- css总结13:CSS 伪类(Pseudo-classes)
1 伪类作用:CSS伪类是用来添加一些选择器的特殊效果. 2 常用示例: 2.1anchor伪类:代码: 正常语法: a{color:#FF0000;}/* 文字颜色 */ 伪类语法: a:l ...
- 打造一套UI与后台并重.net通用权限管理系统
一.前言 从进行到软件开发这个行业现在已经有几年了,在整理出这个套开发框架之前自己做了不少重复造轮子的事.每次有新的项目总是要耗费不少时间在UI.权限和系统通用模块上面,自己累得要死,老板还骂没效率. ...
- python 测试报告发送邮件
使用过程成出现的如下错误 smtplib.SMTPDataError: (554, 'DT:SPM 126 smtp5错误解决办法 1.自动化测试中,调用邮件模块自动发送邮件时,运行脚本报错: s ...
- P1001
原创 问题描述: 当两个比较大的整数相乘时,可能会出现数据溢出的情形.为避免溢出,可以采用字符串的方法来实现两个大数之间的乘法. 具体来说,首先以字符串的形式输入两个整数,每个整数的长度不会超过8位, ...
- C语言编程基础
主流C语言编译器介绍 关于GNU规范的语法扩展 用C语言构建一个可执行程序的流程 宏定义(无参宏定义和带参宏定义),C语言宏定义详解 条件编译,C语言条件编译详解 原码.反码.补码及位操作符,C语言位 ...
- StackOverflow: 你没见过的七个最好的Java答案
StackOverflow发展到目前,已经成为了全球开发者的金矿.它能够帮助我们找到在各个领域遇到的问题的最有用的解决方案,同时我们也会从中学习到很多新的东西.这篇文章是在我们审阅了StackOver ...
- resultType和resultMap的区别
1.resultType和resultMap的区别 1>resultType 返回的结果类型 2>resultMap 描述如何将结果集映射到Java对象 2.resultMap节点 1&g ...
- postgreSQL PL/SQL编程学习笔记(五)——触发器(Triggers)
Trigger Procedures PL/pgSQL can be used to define trigger procedures on data changes or database eve ...