自学如何训练/调教一个私人ChatGPT - 知乎

mikel阅读(848)

来源: 自学如何训练/调教一个私人ChatGPT – 知乎

每周更新一丢丢~欢迎大佬来指正

训练步骤

训练一个个人化的GPT模型大概可以分为以下几个步骤:

  1. 数据收集:收集与个人领域相关的数据,这些数据应该足够多且多样化。数据集应该是和你的应用场景相关的,例如针对特定的领域或者任务。
  2. 数据清理和预处理:将数据进行清理,去除噪声和冗余,统一数据格式,进行标记和编码等预处理。
  3. 模型选择:选择一个基础的GPT模型,可以选择已经公开的预训练模型,也可以选择自己训练的模型(如果你有大量的计算资源和时间,同时学习过TensorFlow或PyTorch等深度学习框架)。
  4. 微调模型:将收集到的个人数据和已经训练好的GPT模型进行微调,让模型更好地适应个人领域。
  5. 模型测试和优化:通过测试来评估模型的性能,并进行优化,提高模型的准确性和效率。
  6. 部署:将训练好的模型部署到生产环境中,供用户使用。

可以用的预训练模型

目前已经公开的预训练模型有很多,其中比较常用的包括:

  • GPT-2
  • GPT-3
  • BERT
  • RoBERTa
  • T5
  • XLNet

这些模型都具有一定的训练难度,但可以根据具体需求和场景选择适合的模型。其中

  • GPT-2是比较经典的模型之一,训练难度相对较小,但是效果也不错。
  • GPT-3则是当前最为先进的预训练模型之一,拥有极高的自然语言处理能力,但是训练难度较大,需要较高的计算资源和数据量。
  • BERT和RoBERTa则主要应用于文本分类、问答等任务,效果也比较不错。
  • T5则可以用于各种NLP任务的生成式模型,可以生成文本、代码等。
  • XLNet是一种比较新的预训练模型,在许多NLP任务上都表现出色,尤其是在涉及长序列、多文档或多轮对话的任务中。例如,XLNet在阅读理解、文本分类、序列标注和生成任务等方面表现出色。此外,XLNet还可以在多语言和跨语言任务中应用,因为它可以处理多种语言之间的语言交叉性。

电脑小白可不可以训练?

没问题!

但需要先学习一些基础的编程和机器学习知识,以便更好地理解和使用GPT-2预训练模型。

训练GPT-2预训练模型必须的编程知识主要包括以下几个方面:
1. Python编程语言:GPT-2是使用Python编写的,因此需要掌握Python编程语言基础知识,如变量、函数、数据类型、流程控制等。
2. 深度学习框架:训练GPT-2需要使用深度学习框架,如TensorFlow、PyTorch等。需要掌握框架的基本概念、模型构建、模型训练和模型调优等。
3. 自然语言处理:GPT-2是基于自然语言处理技术的深度学习模型,需要掌握自然语言处理基础知识,如文本处理、分词、词向量、语言模型等。
4. 计算机硬件和操作系统:GPT-2训练需要大量计算资源,需要了解计算机硬件配置和操作系统的基础知识,如CPU、GPU、内存、磁盘、Linux操作系统等。
5. 数据处理和存储:训练GPT-2需要处理大量的数据,需要掌握数据处理和存储的基本知识,如数据清洗、数据抽取、数据存储等。
6. 数学基础:深度学习是一种数学模型,需要掌握一些数学基础知识,如线性代数、微积分、概率论等。

关于如何使用GPT-2预训练模型,以下是一些基本的步骤:

  1. 下载预训练模型:可以从Hugging Face等网站下载预训练模型。
  2. 安装必要的库:需要安装Python、PyTorch等库来加载模型。
  3. 加载模型:使用Python代码加载预训练模型。
  4. 输入数据:将要生成文本的前缀输入到模型中。
  5. 生成文本:使用模型生成新的文本。

编程小白如何起步

如果你是零基础,建议你先学习一些基础编程知识,例如 Python 编程语言、命令行操作、基本的数据结构和算法等等。可以通过一些在线课程、教材或者学习网站来学习这些知识。

对于训练 GPT-2 预训练模型,你需要学习深度学习的基本概念和技术,包括神经网络、反向传播算法、优化器、损失函数等等。同时,你还需要了解自然语言处理领域的相关知识,例如文本预处理、语言模型等等。

一些经验丰富的数据科学家或者研究人员会建议你先从预训练模型的 fine-tuning 开始,这个过程不需要你自己训练一个完整的预训练模型,而是使用已经训练好的模型来完成一个特定的任务,例如文本分类或者生成文本等等。在这个过程中,你可以了解到如何调整模型参数、如何构建输入数据和输出数据等等技术细节。这也是一个更加容易入门的方法。

笔记本电脑可以训练吗?

可以的,尽管性能不会那么好,但够用了。

个人笔记本电脑可以尝试:

  1. 使用小型的语言模型来微调
  2. 使用预训练的模型,如GPT-2或BERT,并将其微调到特定任务中。在微调模型之前,还需要准备好相应的数据集,并决定如何设置模型的超参数。为了获得更好的微调效果,建议使用一些技巧,如数据增强和模型融合。

预训练模型的内存大小会因不同的模型规模而有所不同。以GPT-2模型为例,它的规模包括117M、345M、774M、1558M、3450M等不同大小的模型。其中,117M的模型需要约0.5GB的内存,而3450M的模型需要约17GB的内存。

电脑系统有影响吗?

使用哪种操作系统并不会直接影响使用GPT-2等预训练模型的能力。预训练模型可以在Windows和macOS上运行,但是在选择操作系统时,可能需要考虑以下因素:

  1. 设备性能:无论选择哪种操作系统,电脑都需要具备足够的处理能力和存储空间来运行预训练模型。
  2. 软件支持:在使用预训练模型时,需要安装Python、TensorFlow或PyTorch等软件。这些软件都可以在Windows和macOS上运行,但是可能需要查看它们在不同操作系统上的安装和配置方式。
  3. 开发环境:如果打算进行模型微调和训练,可能需要选择一个操作系统来搭建开发环境。例如,如果打算使用Docker容器运行模型,需要选择支持Docker的操作系统。

总之,选择操作系统主要取决于个人的需求和偏好,不会直接影响使用预训练模型的能力。

无需GPU无需网络“本地部署chatGPT”(更新中文模型)_Pangaroo的博客-CSDN博客

mikel阅读(733)

来源: 无需GPU无需网络“本地部署chatGPT”(更新中文模型)_Pangaroo的博客-CSDN博客

想当初图像生成从DELL到stable diffusion再到苹果的移动部署过了两三年吧
聊天bot才发展几个月就可以边缘部署了,如果苹果更新silicon,npu和运存翻倍,争取apple watch也能本地内置,最快ios18 mac、ipad、iPhone能内置吧
又是一个平民百姓都高兴的开源项目,chatGPT这种级别的模型甚至能部署到树莓派上运行,然后在操作的过程中也遇到一些问题,这篇就是记录步数的这个过程。
最近github那边更新了,我踩坑遇到的问题已经不痛用了,但我暂时又没时间研究这个,干脆好人做到底,把未更新的代码贴在下面。
已经为最新版的github更新了(2023.4.7),可以放心食用,不用下载下面的老代码链接了。

链接: https://pan.baidu.com/s/1J9FBxSDhmBcqAnHx3rGhEQ 提取码: q5xv
–来自百度网盘超级会员v6的分享
然后配合下面的模型百度云链接,大家应该就可以自己搭建语言模型了。

大佬的网址:https://github.com/ggerganov/llama.cpp

下载及生成
打开命令行输入下面的指令

git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make

#对于Windows和CMake,使用下面的方法构建:
cd <path_to_llama_folder>
mkdir build
cd build
cmake ..
cmake –build . –config Release
1
2
3
4
5
6
7
8
9
10

模型下载
我觉得模型下载是最麻烦的,还好有别人给了

git clone https://huggingface.co/nyanko7/LLaMA-7B
1
好吧我直接给百度云
链接: https://pan.baidu.com/s/1ZC2SCG9X8jZ-GysavQl29Q 提取码: 4ret
–来自百度网盘超级会员v6的分享

 

然后安装python依赖,然后转换模型到FP16格式。然后第一个小bug会出现。

python3 -m pip install torch numpy sentencepiece

# convert the 7B model to ggml FP16 format
python3 convert-pth-to-ggml.py models/7B/ 1
1
2
3
4

他会报找不到文件。

打开convert-pth-to-ggml.py文件,修改”/tokenizer.model”的路径,再运行python3 convert-pth-to-gaml.py ./models/7B 1,我顺便名字也改了。

文件找到了,然后出现第二个bug。。。。。

我一开始找不出问题,后来对比原网址和7B文件夹里的文件,才发现文件大小根本都不一样,我说几十个G的东西怎么git这么。
打开网站下图这个网址,点红色框的那两个下载。替换掉7B文件夹里的那两个文件。

 

将模型再转换成4位格式

# quantize the model to 4-bits
./quantize ./models/7B/ggml-model-f16.bin ./models/7B/ggml-model-q4_0.bin 2
1
2

推理
# run the inference
./main -m ./models/7B/ggml-model-q4_0.bin -n 128
1
2

想和chatGPT一样对话的话用下面这个指令,-n 控制回复生成的最大长度, –color是区分ai和人类的颜色,-i 作为参数在交互模式下运行, -r 是一种反向提示,-f 是一整段提示, –repeat_penalty 控制生成回复中对重复文本的惩罚力度,–temp 温度系数,值越低回复的随机性越小,反之越大。
更新了之后速度快了很多。

./main -m ./models/7B/ggml-model-q4_0.bin -n 256 –repeat_penalty 1.0 –color -i -r “User:” -f prompts/chat-with-bob.txt
1
让我们打开prompts/chat-with-bob.txt来看一下。

我们可以看到这相当于给了ai模型一个场景话题,然后你和ai之间就可以接着这个话题聊天。

我英文名叫zale,然后我把这个机器人叫作kangaroo,这样的身份和他聊天,你可以按自己的喜欢自己修改下面的代码。

./main -m ./models/7B/ggml-model-q4_0.bin -n 256 –repeat_penalty 1.0 –color -i -r “Zale:” \
1
写一个txt文件

“Transcript of a dialog, where the Zale interacts with an Assistant named Kangaroo. Kangaroo is helpful, kind, honest, good at writing, and never fails to answer the Zale’s requests immediately and with precision.

Zale: Hello, Kangaroo.
Kangaroo: Hello. How may I help you today?
Zale: Please tell me the largest city in Europe.
Kangaroo: Sure. The largest city in Europe is Moscow, the capital of Russia.
Zale:”

1
2
3
4
5
6
7
8

有点呆呆的,不过也算边缘部署的巨大进步了!
一个蛮有意思的发现,明明看得懂中文却跟我说不懂中文。。。。。

分享一段有意思的对话

中文部署
哈工大的github
https://github.com/ymcui/Chinese-LLaMA-Alpaca

git clone https://github.com/ymcui/Chinese-LLaMA-Alpaca.git
1
下载中文模型,但这不是llama.cpp要输入的模型,官方的说明是llama的中文补丁模型,需要和原版的llama/alpaca模型合并才能使用。

安装依赖

pip install git+https://github.com/huggingface/transformers
pip install sentencepiece
pip install peft
1
2
3
为了方便起见,我把llama原文件也放到了这里

还有一些注意事项

查看sha256,每个平台查看方式略微不同,可以上网搜一下如何查看sha256

整理一下llama原文件的路径

我是将transformers下载到conda里了,路径有点长。你就是找到你的convert_llama_weights_to_hf.py文件的路径就好。

python /Users/kangaroo/miniconda3/envs/pytorch/lib/python3.10/site-packages/transformers/models/llama/convert_llama_weights_to_hf.py \
–input_dir ./llama_7b \
–model_size 7B \
–output_dir ./llama_hf
1
2
3
4

合并模型

python scripts/merge_llama_with_chinese_lora.py \
–base_model ./llama_hf \
–lora_model ./chinese_llama_lora_7b \
–output_dir ./cn_llama
1
2
3
4

再把这个文件夹复制到llama.cpp/models 中

回到llama.cpp里重新量化

python convert-pth-to-ggml.py models/cn_llama/ 1

./quantize ./models/cn_llama/ggml-model-f16.bin ./models/cn_llama/ggml-model-q4_0.bin 2
1
2
3
有点话痨,我直接掐掉了,之后再看看

./main -m ./models/cn_llama/ggml-model-q4_0.bin -n 48 –repeat_penalty 1.0 –color -i -r “Zale:” -f prompts/chat-with-zale.txt
1

./main -m models/cn_llama/ggml-model-q4_0.bin –color -f ./prompts/alpaca.txt -ins -c 2048 –temp 0.2 -n 256 –repeat_penalty 1.3
1

————————————————
版权声明:本文为CSDN博主「Pangaroo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45569617/article/details/129553293

JavaScript 对象与 JSON 对象的相互转换_js json转换_latency_cheng的博客-CSDN博客

mikel阅读(435)

来源: JavaScript 对象与 JSON 对象的相互转换_js json转换_latency_cheng的博客-CSDN博客

一、全局JSON对象
ES5定义了全局对象JSON,对解析JSON的行为制定了规范。
JSON对象有两个方法:stringify() 和 parse()。

二、JavaScript 对象序列化为 JSON对象
JSON.stringify( js对象 [, 过滤器] [, 选项])
二三参数可选,js对象中的函数和原型成员将被忽略,值为undefined的属性也被跳过。
默认情况下,返回的JSON不包含任何空格字符和缩进。
var book = {
title: “Professional JavaScript”,
authors: [“Nicholas C. Zakas”],
edition: 3,
year: 2011
};

var jsonText = JSON.stringify(book);

过滤器为数组:JSON.stingify() 的结果只包含数组中列出的属性。
var book = {
title: “Professional JavaScript”,
authors: [“Nicholas C. Zakas”],
edition: 3,
year: 2011
};

var jsonText = JSON.stringify(book, [“title”, “edition”]);
jsonText的值为 {“title”: “Professional JavaScript”, “edition”: 3}

过滤器为函数:函数接收两个参数,键名和值(key, value)。函数体中根据键名处理对应的值。
var book = {
title: “Professional JavaScript”,
authors: [“Nicholas C. Zakas”],
edition: 3,
year: 2011
};

var jsonText = JSON.stringify(book, function(key, value){
switch(key){
case “authors”:
return value.join(“,”)
case “year”:
return 5000;
case “edition”:
return undefined;
default:
return value;
}
});
序列化后的 jsonText 值为:{“title”: “Professional JavaScript”, “authors”: “Nicholas C. Zakas”, “year”: 5000}

第三个参数用于控制结果的缩进:
参数为数值 —– 表示缩进的空格数。
var book = {
title: “Professional JavaScript”,
authors: [“Nicholas C. Zakas”],
edition: 3,
year: 2011
};

var jsonText = JSON.stringify(book, null, 4);
jsonText 中的字符串:
{
“title”: “Professional JavaScript”,
“authors”: [
“Nicholas C. Zakas”
],
“edition”: 3,
“year”: 2011
}

参数为字符串 —– 表示使用该字符串进行缩进。
var book = {
title: “Professional JavaScript”,
authors: [“Nicholas C. Zakas”],
edition: 3,
year: 2011
};

var jsonText = JSON.stringify(book, null, ” – -“);
jsonText 中的字符串:
{
–“title”: “Professional JavaScript”,
–“authors”: [
—-“Nicholas C. Zakas”
–],
–“edition”: 3,
–“year”: 2011
}

(还可以为对象定义 toJSON() 方法,实现对其进行自定义序列化的需求。)

三、JSON对象解析为 JavaScript 对象
JSON.parse(json对象 [, 还原函数])
还原参数接收两个参数,键和值。如果返回undefined,则表示从结果中删除相应的键;如果返回其他值,则将该值插入到结果中。
var book = {
title: “Professional JavaScript”,
authors: [“Nicholas C. Zakas”],
edition: 3,
year: 2011,
releaseDate: new Date(2011, 11, 1)
};

var jsonText = JSON.stringify(book);
var bookCopy = JSON.parse(jsonText, function(key, value){
if (key == “releaseDate”){
return new Date(value);
} else {
return value;
}
});
————————————————
版权声明:本文为CSDN博主「latency_cheng」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/latency_cheng/article/details/73468205

SQLServer数据库中常用的3种分页查询方法

mikel阅读(606)

SQLServer中,常用的分页查询有以下几种:

  1. 使用OFFSET-FETCH语句:该语句从指定偏移量开始返回指定行数的结果集。

例如:

SELECT *

FROM table_name

ORDER BY column_name

OFFSET 10 ROWS

FETCH NEXT 5 ROWS ONLY;

这将从第11行开始返回5行结果集。

注意:这种方法对SQLServer版本有要求,需要SQLServer2012以后的版本才支持

2、使用ROW_NUMBER()函数:该函数为结果集中的每一行分配一个行号,然后可以根据行号进行分页。

例如:

WITH CTE AS (

  SELECT *, ROW_NUMBER() OVER (ORDER BY column_name) AS RowNum

  FROM table_name

)

SELECT *

FROM CTE

WHERE RowNum BETWEEN 11 AND 15; 这将返回第11行到第15行之间的结果集。

3、使用TOP语句和子查询:该方法可以通过子查询返回指定行数的结果集,然后使用TOP语句从子查询中选择前N行。

例如:

SELECT TOP 5 *

FROM (

  SELECT *, ROW_NUMBER() OVER (ORDER BY column_name) AS RowNum

  FROM table_name

) AS subquery

WHERE RowNum > 10;

这将返回第11行到第15行之间的结果集。

需要注意的是,在处理大量数据时,分页查询可能会影响性能。因此,可以考虑使用其他技术来优化查询。例如,可以使用索引或缓存数据以提高性能。

另外,还可以使用存储过程或视图来实现分页查询。存储过程是一组预定义的SQL语句,可以在需要时执行。视图是一种虚拟表,可以从一个或多个表中检索数据。以下是使用存储过程和视图实现分页查询的示例:

使用存储过程:该方法可以将分页查询逻辑封装在存储过程中,然后可以轻松地调用该存储过程以进行分页查询。例如:

CREATE PROCEDURE GetPageResults

  @PageNumber INT,

  @PageSize INT

AS

BEGIN

  SELECT *

  FROM table_name

  ORDER BY column_name

  OFFSET (@PageNumber – 1) * @PageSize ROWS

  FETCH NEXT @PageSize ROWS  ONLY;

END; 

 然后可以使用以下语句调用存储过程:

EXEC GetPageResults @PageNumber = 2, @PageSize = 5;

这将返回第6行到第10行之间的结果集。

使用视图:该方法可以创建一个虚拟表来存储所有数据,然后可以使用分页查询从该视图中检索数据。例如:

CREATE VIEW vw_table_name AS

SELECT *, ROW_NUMBER() OVER (ORDER BY column_name) AS RowNum

FROM table_name;

然后可以使用以下语句进行分页查询:

SELECT *

FROM vw_table_name

WHERE RowNum BETWEEN 11 AND 15;

这将返回第11行到第15行之间的结果集。

需要注意的是,在使用存储过程或视图时,需要考虑安全性和性能。

存储过程可以提高查询性能并减少SQL注入攻击的风险,但需要更多的开发和管理工作。视图可以提供简单的查询和安全性,但可能会影响性能。决定使用哪种方法取决于具体情况,需要根据实际需要进行权衡。

最后,需要注意的是,以上分页查询示例可能需要根据具体情况进行修改。例如,需要根据实际列名和表名来替换相应的名称。同时需要根据具体需求调整分页查询的参数,如每页显示的行数、需要显示的页码等。

此外,还需要注意以下几个问题:

数据库引擎版本:不同版本的SQL Server可能支持不同的分页查询语法和特性。因此,在编写分页查询语句时,需要考虑数据库引擎的版本。

查询复杂度:如果查询涉及多个表、多个条件或计算密集型操作,可能需要采用优化技术来提高查询性能。例如,可以使用索引、查询优化器或缓存数据等技术。

数据库结构:数据库结构对查询性能和分页查询的实现方式也有很大影响。例如,如果表中没有主键或排序字段,则可能需要采用其他技术来实现分页查询。

数据库访问权限:在实际应用中,需要根据不同的用户角色和权限来限制对数据库的访问和查询。因此,在编写分页查询语句时,需要考虑用户权限和安全性问题。

并发访问:在高并发环境下,多个用户同时访问数据库可能会导致性能问题。因此,在编写分页查询语句时,需要考虑并发访问的情况,并采用适当的技术来避免或减少性能问题。

综上所述,SQL Server提供了多种分页查询语法和技术,开发人员可以根据具体情况选择适当的方法来实现分页查询。同时,需要考虑数据库

引擎版本、查询复杂度、数据库结构、数据库访问权限和并发访问等因素,以确保查询性能和安全性。

ChatGPT 本地部署及搭建_孟郎郎的博客-CSDN博客

mikel阅读(1144)

来源: (1条消息) ChatGPT 本地部署及搭建_孟郎郎的博客-CSDN博客

这篇简要说下清华开源项目 ChatGLM 本地部署的详细教程。清华开源项目 ChatGLM-6B 已发布开源版本,这一项目可以直接部署在本地计算机上做测试,无需联网即可体验与 AI 聊天的乐趣。

项目地址:GitHub – THUDM/ChatGLM-6B: ChatGLM-6B:开源双语对话语言模型 | An Open Bilingual Dialogue Language Model

官网介绍:

ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型,基于 General Language Model (GLM) 架构,具有 62 亿参数。结合模型量化技术,用户可以在消费级的显卡上进行本地部署(INT4 量化级别下最低只需 6GB 显存)。 ChatGLM-6B 使用了和 ChatGPT 相似的技术,针对中文问答和对话进行了优化。经过约 1T 标识符的中英双语训练,辅以监督微调、反馈自助、人类反馈强化学习等技术的加持,62 亿参数的 ChatGLM-6B 已经能生成相当符合人类偏好的回答,更多信息请参考我们的博客。

为了方便下游开发者针对自己的应用场景定制模型,我们同时实现了基于 P-Tuning v2 的高效参数微调方法 (使用指南) ,INT4 量化级别下最低只需 7GB 显存即可启动微调。

不过,由于 ChatGLM-6B 的规模较小,目前已知其具有相当多的局限性,如事实性/数学逻辑错误,可能生成有害/有偏见内容,较弱的上下文能力,自我认知混乱,以及对英文指示生成与中文指示完全矛盾的内容。请大家在使用前了解这些问题,以免产生误解。更大的基于 1300 亿参数 GLM-130B 的 ChatGLM 正在内测开发中。

第一步,本地安装 Python
这一步暂略,可以自行下载安装 Python 环境。

Python 下载地址:Download Python | Python.org

注意:安装 >9 以上版本,建议安装 10。

第二步,下载项目程序包
地址见上面的项目地址,直接下载下来并解压。我这里解压到 E:\chatGPT\ 下。

 

第三步,下载模型包 chatglm
下载地址:https://huggingface.co/THUDM/chatglm-6b/tree/main

官网介绍:

ChatGLM-6B 是一个开源的、支持中英双语问答的对话语言模型,基于 General Language Model (GLM) 架构,具有 62 亿参数。结合模型量化技术,用户可以在消费级的显卡上进行本地部署(INT4 量化级别下最低只需 6GB 显存)。ChatGLM-6B 使用了和 ChatGLM 相同的技术,针对中文问答和对话进行了优化。经过约 1T 标识符的中英双语训练,辅以监督微调、反馈自助、人类反馈强化学习等技术的加持,62 亿参数的 ChatGLM-6B 已经能生成相当符合人类偏好的回答。

注意:下载后放到第二步程序包下,自行创建目录 chatglm-6b,如下:

 

第四步,下载依赖包
Window + R 快捷键打开运行窗口,输入 cmd 打开控制台命令行,进入到程序目录下。

 

分别执行如下两条命令:

pip install -r requirements.txt

pip install gradio

注意:如果执行有报错,请查阅文章末尾的错误处理。

 

等待依赖包下载成功,结果如下:

 

第五步,运行网页版 demo
执行如下命令,运行网页版本的 demo,如下:

python web_demo.py

程序会运行一个 Web Server,并输出地址。在浏览器中打开输出的地址即可使用。最新版 Demo 实现了打字机效果,速度体验大大提升。注意,由于国内 Gradio 的网络访问较为缓慢,启用 demo.queue().launch(share=True, inbrowser=True) 时所有网络会经过 Gradio 服务器转发,导致打字机体验大幅下降,现在默认启动方式已经改为 share=False,如有需要公网访问的需求,可以重新修改为 share=True 启动。

执行结果如下:

 

注意:如果执行提示信息和上图对不上,请查阅文章末尾的错误处理。

第七步,测试网页版程序
浏览器打开地址 并访问,输入问题,可以看到 ChatGLM 会给予回复。

 

Very Good!查看电脑性能,感觉 CPU 和内存都要爆掉了 ^ ^

 

 

第八步,运行命令行 Demo
执行如下命令,运行命令行版本的 demo,如下:

python cli_demo.py

程序会在命令行中进行交互式的对话,在命令行中输入指示并回车即可生成回复,输入 clear 可以清空对话历史,输入 stop 终止程序。

 

错误一:下载依赖包超时
E:\chatGPT\ChatGLM-6B-main>pip install -r requirements.txt
Collecting protobuf<3.20.1,>=3.19.5
Downloading protobuf-3.20.0-cp310-cp310-win_amd64.whl (903 kB)
—————————————- 903.8/903.8 kB 4.0 kB/s eta 0:00:00
Collecting transformers==4.27.1
Downloading transformers-4.27.1-py3-none-any.whl (6.7 MB)
———– —————————- 2.0/6.7 MB 5.4 kB/s eta 0:14:29
ERROR: Exception:
Traceback (most recent call last):
File “D:\Python\Python310\lib\site-packages\pip\_vendor\urllib3\response.py”, line 438, in _error_catcher
yield
File “D:\Python\Python310\lib\site-packages\pip\_vendor\urllib3\response.py”, line 561, in read
data = self._fp_read(amt) if not fp_closed else b””
File “D:\Python\Python310\lib\site-packages\pip\_vendor\urllib3\response.py”, line 527, in _fp_read
return self._fp.read(amt) if amt is not None else self._fp.read()
File “D:\Python\Python310\lib\site-packages\pip\_vendor\cachecontrol\filewrapper.py”, line 90, in read
data = self.__fp.read(amt)
File “D:\Python\Python310\lib\http\client.py”, line 465, in read
s = self.fp.read(amt)
File “D:\Python\Python310\lib\socket.py”, line 705, in readinto
return self._sock.recv_into(b)
File “D:\Python\Python310\lib\ssl.py”, line 1274, in recv_into
return self.read(nbytes, buffer)
File “D:\Python\Python310\lib\ssl.py”, line 1130, in read
return self._sslobj.read(len, buffer)
TimeoutError: The read operation timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “D:\Python\Python310\lib\site-packages\pip\_internal\cli\base_command.py”, line 160, in exc_logging_wrapper
status = run_func(*args)
File “D:\Python\Python310\lib\site-packages\pip\_internal\cli\req_command.py”, line 247, in wrapper
return func(self, options, args)
File “D:\Python\Python310\lib\site-packages\pip\_internal\commands\install.py”, line 419, in run
requirement_set = resolver.resolve(
File “D:\Python\Python310\lib\site-packages\pip\_internal\resolution\resolvelib\resolver.py”, line 92, in resolve
result = self._result = resolver.resolve(
File “D:\Python\Python310\lib\site-packages\pip\_vendor\resolvelib\resolvers.py”, line 481, in resolve
state = resolution.resolve(requirements, max_rounds=max_rounds)
File “D:\Python\Python310\lib\site-packages\pip\_vendor\resolvelib\resolvers.py”, line 348, in resolve
self._add_to_criteria(self.state.criteria, r, parent=None)
File “D:\Python\Python310\lib\site-packages\pip\_vendor\resolvelib\resolvers.py”, line 172, in _add_to_criteria
if not criterion.candidates:
File “D:\Python\Python310\lib\site-packages\pip\_vendor\resolvelib\structs.py”, line 151, in __bool__
return bool(self._sequence)
File “D:\Python\Python310\lib\site-packages\pip\_internal\resolution\resolvelib\found_candidates.py”, line 155, in __bool__
return any(self)
File “D:\Python\Python310\lib\site-packages\pip\_internal\resolution\resolvelib\found_candidates.py”, line 143, in <genexpr>
return (c for c in iterator if id(c) not in self._incompatible_ids)
File “D:\Python\Python310\lib\site-packages\pip\_internal\resolution\resolvelib\found_candidates.py”, line 47, in _iter_built
candidate = func()
File “D:\Python\Python310\lib\site-packages\pip\_internal\resolution\resolvelib\factory.py”, line 206, in _make_candidate_from_link
self._link_candidate_cache[link] = LinkCandidate(
File “D:\Python\Python310\lib\site-packages\pip\_internal\resolution\resolvelib\candidates.py”, line 297, in __init__
super().__init__(
File “D:\Python\Python310\lib\site-packages\pip\_internal\resolution\resolvelib\candidates.py”, line 162, in __init__
self.dist = self._prepare()
File “D:\Python\Python310\lib\site-packages\pip\_internal\resolution\resolvelib\candidates.py”, line 231, in _prepare
dist = self._prepare_distribution()
File “D:\Python\Python310\lib\site-packages\pip\_internal\resolution\resolvelib\candidates.py”, line 308, in _prepare_distribution
return preparer.prepare_linked_requirement(self._ireq, parallel_builds=True)
File “D:\Python\Python310\lib\site-packages\pip\_internal\operations\prepare.py”, line 491, in prepare_linked_requirement
return self._prepare_linked_requirement(req, parallel_builds)
File “D:\Python\Python310\lib\site-packages\pip\_internal\operations\prepare.py”, line 536, in _prepare_linked_requirement
local_file = unpack_url(
File “D:\Python\Python310\lib\site-packages\pip\_internal\operations\prepare.py”, line 166, in unpack_url
file = get_http_url(
File “D:\Python\Python310\lib\site-packages\pip\_internal\operations\prepare.py”, line 107, in get_http_url
from_path, content_type = download(link, temp_dir.path)
File “D:\Python\Python310\lib\site-packages\pip\_internal\network\download.py”, line 147, in __call__
for chunk in chunks:
File “D:\Python\Python310\lib\site-packages\pip\_internal\cli\progress_bars.py”, line 53, in _rich_progress_bar
for chunk in iterable:
File “D:\Python\Python310\lib\site-packages\pip\_internal\network\utils.py”, line 63, in response_chunks
for chunk in response.raw.stream(
File “D:\Python\Python310\lib\site-packages\pip\_vendor\urllib3\response.py”, line 622, in stream
data = self.read(amt=amt, decode_content=decode_content)
File “D:\Python\Python310\lib\site-packages\pip\_vendor\urllib3\response.py”, line 560, in read
with self._error_catcher():
File “D:\Python\Python310\lib\contextlib.py”, line 153, in __exit__
self.gen.throw(typ, value, traceback)
File “D:\Python\Python310\lib\site-packages\pip\_vendor\urllib3\response.py”, line 443, in _error_catcher
raise ReadTimeoutError(self._pool, None, “Read timed out.”)
pip._vendor.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host=’files.pythonhosted.org’, port=443): Read timed out.

E:\chatGPT\ChatGLM-6B-main>

可以看到错误信息提示超时,应该是网络问题,可以尝试在命令中加上超时时间设置的参数,命令修改后如下:

pip –default-timeout=1688 install -r requirements.txt

问题二:又一次实时下载模型包

当运行程序时,如果提示信息中看到又一次下载模型包,而没有使用第三步提前准备的模型包时,需要把模型包复制到程序运行时的缓存目录中,缓存路径可能如下:

C:\Users\用户目录\.cache\huggingface\hub\models–THUDM–chatglm-6b\snapshots\fb23542cfe773f89b72a6ff58c3a57895b664a23

模型包拷贝到该目录后再次运行程序即可。

Good Luck!
————————————————
版权声明:本文为CSDN博主「孟郎郎」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tzhuwb/article/details/129910616

 

轻量高效ORM之Dapper篇 - 知乎

mikel阅读(1102)

来源: 轻量高效ORM之Dapper篇 – 知乎

介绍

dapper是一个简单的对象关系映射框架(ORM—-Object Relation Mapping),它几乎与原始的ADO.NET 数据操作读取一样快(反正我ado.net已经忘完了╥__╥,以前用的最多是linq to SQL和ef,不需要写SQL语句,使用linq操作数据源),它负责数据库与编程语言之间的映射。

与EF的优劣

EF——-重量级ORM的代表

优点:

  • 面向对象式操作数据库。
  • 完全摆脱SQL 语句,不用关心SQL如何写,可移植性强。
  • 支持code first,开发人员可以完成且无需关心数据库,代码先行,极大节省开发成本。
  • 结合LINQ,开发效率高。
  • 跨数据库,易配置。
  • 与VS结合较好。

缺点:

  • 比较复杂,学习曲线复杂(官方文档丰富且杂)。
  • 不适合做统计查询(因为统计查询需要执行查询效率高)。
  • 对于多表查询或一些复杂的查询实现较为困难和复杂。
  • 自动生成的SQL语句复杂,效率低。
  • EF的Context上下文不是线程安全的(知识有限,不懂)。
  • 包和插件较为冗余(对于中小型项目来说),性能一般。

Dapper——–轻量级ORM的代表

优点:

  • 开源,轻巧(轻量级),编译后文件简单且小巧。
  • 支持主流数据库,MSSQL,MySQL,Oracle。
  • 执行效率高。
  • 学习较为方便

缺点:

  • 半自动ORM,需要开发人员自己写实体类┭┮﹏┭┮(可以借助实体类生成工具生成)。
  • 开发时间成本高,LINQ支持较弱。
  • 维护成本高,不支持Code first,开发人员除了要维护数据库中的表,还需要维护代码表中的映射对象。

Dapper安装

Nuget包安装管理器搜索,安装最新版本即可。

Dapper方法

Dapper使用以下几个方法扩展了我们的IDbConnection接口

  • Execute
  • Query
  • QueryFirst
  • QueryFirstOrDefault
  • QuerySingle
  • QuerySingleOrDefault
  • QueryMultiple

Execute

可执行存储过程、增、删、改等操作。

此处以插入为例

MySqlConnection实现了DbConnection接口,当数据库发生改变时,可进行更改。

插入(单、多),更新(单、多),删除(单,多)均使用此方法

Query

Dapper Contrib插件

它是额外的插件,在dapper的基础上进一步封装了些许操作,使开发更为方便。

安装包之后,即可使用。

数据注释

ExplicitKey和Computed这两个属性后面遇到再阐述

基本方法

今日总结,皆为初步学习,有很多方法没有涉及到,具体后期在实践中总结。

Dapper.Common基于Dapper的开源LINQ超轻量扩展 - 腾讯云开发者社区-腾讯云

mikel阅读(549)

来源: Dapper.Common基于Dapper的开源LINQ超轻量扩展 – 腾讯云开发者社区-腾讯云

Dapper.Common是基于Dapper的LINQ实现,支持.net core,遵循Linq语法规则、链式调用、配置简单、上手快,支持MySQL,SQLServer(目前只实现了这两个数据库,实现其他数据库也很轻松),支持单表,多表,自定义函数等功能。源码及其简单,直白,解析Lambda只有300行左右代码。严格区分C#函数和数据库函数,你可以在表达式中调用C#函数(不推荐,推荐将计算结果保存到变量,在写入lambda表达式),性能损失在表达式编译:常量>变量>函数。损失多少可以通过ExpressionUtil.BuildExpression()来测试,几万次耗时百毫秒级别。

开源地址:https://github.com/1448376744/Dapper.Common

Nuget:Install-Package Dapper.Common -Version 1.5.0

测试

映射

public class User
  {
       /// <summary>
       /// 如果表名与字段名一致,可以不用Column进行注解,主键采用类型的第一个属性【不推荐】
       /// name:用于映射字段名和数据库字段不一致【完全可以用T4一键生成我GitHub有现成的】
       /// key:
       ///     目前实现了Primary的定义,设置为Primary的字段update实体时,默认采用该字段为更新条件
       /// isIdentity:
       ///     设置未true时在Insert时不会向该字段设置任何值
       /// isColumn:
       ///     标识该字段是否在数据库存在,用于扩展User而不在sql中生成该字段
       /// </summary>
       [Column(name: "id", key: ColumnKey.Primary, isIdentity: true, isColumn: true)]
       public int? Id { get; set; }
       [Column(name:"nick_name")]
       public string NickName { get; set; }
       [Column(name: "create_time")]
       public DateTime? CreateTime { get; set; }
  }

配置

//在App启动时执行一次即可
SessionFactory.AddDataSource(new DataSource()
{
    Name = "mysql",
    Source = () => new SqlConnection("connectionString"),
    SourceType = DataSourceType.SQLSERVER,
    UseProxy = true//使用Session的静态代理实现,记录日志,执行耗时,线上环境建议关闭代理
});

//获取数据库上下文
using (var session = SessionFactory.GetSession("msql"))
{
    //linq to sql
}

使用

1.Insert

var entity = new User()
{
    CreateTime=DateTime.Now,
    NickName="dapper",
};
//绝大部分接口可以设置condition已决定是否执行,支持批量更新
session.From<User>().Insert(entity,condition:1>2);
//查看日志,如果出现异常,应该在catch里,查看session.Loggers
var loggers = session.Loggers;

2.Update

var entity = new User()
{
  Id=2,
  NickName="李四"
};
//更新所有字段(where id=2),支持批量,显然除NickName之外将被更新成null
session.From<User>().Update(entity);

//更新部分字段
session.From<User>()
   .Set(a => a.NickName, "李四", condition: true)//condition为true时更新该字段
   .Set(a => a.Balance, a => a.Balance + 100)//余额在原来基础增加100
   .Where(a => a.Id.In(1,2,3))//将id为1,2,3的记录进行更新
   .Update();

3.Delete

//删除id>5||nick_name like '%da%'
 session.From<User>()
    .Where(a=>a.Id>5||a.NickName.Like("da"))
    .Delete();

4.Single

//查询全部字段
  var user1 = session.From<User>()
      .Where(a=>a.Id==2)
      .Single();

  //查询部分字段
  var user2 = session.From<User>()
     .Where(a => a.Id == 2)
     .Single(s=>new
     {
         s.Id,
         s.NickName
     });

5.Select

//查询:where id in(1,2,3)
 var list = session.From<User>()
        .Where(a => a.Id.In("1,2,3".Split(',')))
        .Select();

6.Where

//构建动态查询,condition: true执行,通过condition选择分支,多个where之间用 and 连接
 var list = session.From<User>()
        .Where(a => a.Id.In(1, 2, 3), condition: true)
        .Where(a => a.NickName.Like("da"), condition: false)
        .Where(a => a.Id > 2 || (a.NickName.Like("da") && a.Balance > 50))
        .Where("select * from user_bill where user_bill.user_id=user.id")//同样可以当作字符串拼接工具
        .Select();

7.Function

/// <summary>
 /// 自定义函数
 /// </summary>
 public static class MySqlFun
 {
     //这里使用泛型并不是必须的,只用函数名在数据库存在即可,泛型为了指定返回数据类型
     [Function]//Dapper.Common严格区分C#函数和数据库函数,一定要用该特性标识数据库函数
     public static T COUNT<T>(T column)
     {
         return default(T);
     }
     [Function]
     public static T MAX<T>(T column)
     {
         return default(T);
     }
     [Function]
     public static T DISTINCT<T>(T column)
     {
         return default(T);
     }
   [Function]
   public static T DATE<T>(T column)
     {
     return default(T);
   }
  }

8.GroupBy

var list = session.From<Order>()
     .GroupBy(a => a.UserId)//多个条件可以new一个匿名对象,也可以并联多个group
     .Having(a => MySqlFun.COUNT(MySqlFun.DISTINCT(a.UserId)) > 10)//count(distinct(user_id))>10
     .Select(s => new
     {
         s.UserId,
         OrderCount = MySqlFun.COUNT(1L),//这里应该返回long int,
         MaxFee = MySqlFun.MAX(s.TotalFee)
     });

9.Join

var list = session.From<Order, User>()
     .Join((a, b) => a.UserId == b.Id, JoinType.Inner)
     .GroupBy((a, b) => a.UserId)
     .Having((a, b) => MySqlFun.COUNT(MySqlFun.DISTINCT(a.UserId)) > 10)//count(distinct(user_id))>10
     .Select((a, b) => new
     {
         a.UserId,
         b.NickName,
         OrderCount = MySqlFun.COUNT(1L),//这里应该返回long int,
         MaxFee = MySqlFun.MAX(a.TotalFee)
     });

10.SubQuery

var list = session.From<Order>()
    .GroupBy(a  => a.UserId)
    .Having(a => MySqlFun.COUNT(MySqlFun.DISTINCT(a.UserId)) > 10)
    .Select(a => new
    {
        a.UserId,
        UserName=Convert.ToString("select nick_name from user where user.id=order.user_id"),//如果这个子查询返回的是int:Convert.ToInt32(sql)
        OrderCount = MySqlFun.COUNT(1L),//这里应该返回long int【这就是为什么定义成泛型函数】,
        MaxFee = MySqlFun.MAX(a.TotalFee)
    });

11.Page

//分页应该写在Where,Having,Group之后(如果有)
var list = session.From<User>()
        .Where(a=>a.NickName != null)
        .Page(1,10,out long total)
        .Select();

12.Take

var list = session.From<User>()
        .Take(5)
        .Select();

13.Skip

//从数据库索引为1的位置(跳过1之前的记录),获取10
var list = session.From<User>()
    .Skip(1,10)
    .Select();

14.Sum

var list= session.From<User>()
     .Sum(s=>s.Balance*s.Id);

15.Exists

//内部采用exist子查询判断满足where条件的记录是否存在
var flag = seesion.From<User>()
    .Where(a=>a.Id > 10)
    .Exists();

16.OrderBy

var list1 = session.From<User>()
    .Order(a=>a.Id)
    .Select();

var list2 = session.From<User>()
    .GroupBy(a => MysqlFun.DATE(a.CreateTime))
    .OrderByDescending(a => MysqlFun.DATE(a.CreateTime))
    .Select(s=>new 
    {
         Date=MysqlFun.DATE(s.CreateTime),
         Count = MysqlFun.Count(1L)
    });

17.Filter

var user =new User ()
{
  Id = 12
  Balance = 50,
  NickName = "张三",
  CreateTime = Datetime.Now
};
//Filter会在Insert,Update,Select,过滤掉不想要的字段
//这将不会更新余额及创建时间
var row = session.From<User>()
    .Filter(f=>new 
    {
          f.CreateTime,
          f.Balance,
    })
    .Update(user);

18.Transaction

//获取数据库上下文
  ISession session = null;
  try
  {
    session=SessionFactory.GetSession();
      //开启事务
      session.Open(true);
      //sql
      //提交事务
      session.Commit();
  }
  catch (Exception)
  {
      session?.Rollback();
      throw;
  }
  finally
  {
      session?.Close();
  }

原文地址:https://cnblogs.com/chaeyeon/p/11028480.html

c# Dapper,添加,修改,删除,查询,事务,存储过程,含数据库(从入门到高级)_橙-极纪元的博客-CSDN博客

mikel阅读(821)

来源: c# Dapper,添加,修改,删除,查询,事务,存储过程,含数据库(从入门到高级)_橙-极纪元的博客-CSDN博客

目录

前言

介绍

重点提示

安装

使用NuGet安装

准备工作

数据库SQL (含存储过程)

模型类

Type.cs

Product.cs

数据库访问层

引入关键库

创建数据库连接

添加 3个方法

1.新增一条数据,不带事务

2.新增一条数据,且,返回自增ID;不带事务

3.新增多条数据,不带事务

修改 2个方法

1.修改一条数据,不带事务

2.修改多条数据,不带事务

删除 2个方法

1.删除一条数据,不带事务

2.删除多条数据,不带事务

查询/Join查询/函数查询/查询In操作/多语句查询/验证类型名是否存在 7个方法

1.查询一条数据

2.普通查询-列表

3.Join查询-列表

4.函数查询 和,平均值,最大值,最小值

5.查询In操作

6.多语句查询

7.验证类型名是否存在

事务 3个方法

1.事务第一种用法;添加一条分类的同时新增一条产品数据

2.事务第二种用法;添加一条分类的同时新增一条产品数据

3.新增(添加)多条数据,带事务

执行存储过程 3个方法

1.查询产品表,根据类型ID 查询出所有产品,且返回产品数量

SQL

2.插入新产品的存储过程,产品名存在就不插入

SQL

3.获取产品表和产品类型表中的所有数据

sql

 

前言
介绍
C# Dapper高级编程;
添加方法3个,

修改方法2个,

删除方法2个,

查询方法7个(含Join),

事务方法3个,

存储过程方法3个

重点提示
一、ORM框架执行效率排序EF 7 8 Dapper执行效率 1 2

二、传参

传参有三种方式
第一种:model模型传参 如:User user=new User(); user.name=”小明”
第二种:匿名类型传参 如:var user = new {name=”小明”};
第三种:DynamicParameters 传参 如下:
DynamicParameters paras = new DynamicParameters();
paras.Add(“@name”, “小明”);//输入参数

三、

只有在BeginTransaction(事务)时要求连接是打开的conn.Open()。
而在不使用事务的时候,简单的增删改查可以不用这一句dbConnection.Open()(即conn.Open());
因为Dapper的大部分方法中有dbConnection.Open(),所以不需要每次都打开连接,程序会自己处理。

安装
使用NuGet安装
项目》引用》右键》管理NuGet程序包》左侧出现界面》浏览》输入“Dapper”》选中》左侧有个“安装”》点击安装

在解决方案管理器中点击项目,查看引用,如果有Dapper,说明安装成功。

 

准备工作
数据库sql (含存储过程)
USE [master]
GO
/****** Object: Database [DBTase] Script Date: 2020/11/20 10:22:57 ******/
CREATE DATABASE [DBTase]
CONTAINMENT = NONE
ON PRIMARY
( NAME = N’DBTase’, FILENAME = N’C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLServer\MSSQL\DATA\DBTase.mdf’ , SIZE = 5120KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
LOG ON
( NAME = N’DBTase_log’, FILENAME = N’C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLServer\MSSQL\DATA\DBTase_log.ldf’ , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO
ALTER DATABASE [DBTase] SET COMPATIBILITY_LEVEL = 110
GO
IF (1 = FULLTEXTSERVICEPROPERTY(‘IsFullTextInstalled’))
begin
EXEC [DBTase].[dbo].[sp_fulltext_database] @action = ‘enable’
end
GO
ALTER DATABASE [DBTase] SET ANSI_NULL_DEFAULT OFF
GO
ALTER DATABASE [DBTase] SET ANSI_NULLS OFF
GO
ALTER DATABASE [DBTase] SET ANSI_PADDING OFF
GO
ALTER DATABASE [DBTase] SET ANSI_WARNINGS OFF
GO
ALTER DATABASE [DBTase] SET ARITHABORT OFF
GO
ALTER DATABASE [DBTase] SET AUTO_CLOSE OFF
GO
ALTER DATABASE [DBTase] SET AUTO_CREATE_STATISTICS ON
GO
ALTER DATABASE [DBTase] SET AUTO_SHRINK OFF
GO
ALTER DATABASE [DBTase] SET AUTO_UPDATE_STATISTICS ON
GO
ALTER DATABASE [DBTase] SET CURSOR_CLOSE_ON_COMMIT OFF
GO
ALTER DATABASE [DBTase] SET CURSOR_DEFAULT GLOBAL
GO
ALTER DATABASE [DBTase] SET CONCAT_NULL_YIELDS_NULL OFF
GO
ALTER DATABASE [DBTase] SET NUMERIC_ROUNDABORT OFF
GO
ALTER DATABASE [DBTase] SET QUOTED_IDENTIFIER OFF
GO
ALTER DATABASE [DBTase] SET RECURSIVE_TRIGGERS OFF
GO
ALTER DATABASE [DBTase] SET DISABLE_BROKER
GO
ALTER DATABASE [DBTase] SET AUTO_UPDATE_STATISTICS_ASYNC OFF
GO
ALTER DATABASE [DBTase] SET DATE_CORRELATION_OPTIMIZATION OFF
GO
ALTER DATABASE [DBTase] SET TRUSTWORTHY OFF
GO
ALTER DATABASE [DBTase] SET ALLOW_SNAPSHOT_ISOLATION OFF
GO
ALTER DATABASE [DBTase] SET PARAMETERIZATION SIMPLE
GO
ALTER DATABASE [DBTase] SET READ_COMMITTED_SNAPSHOT OFF
GO
ALTER DATABASE [DBTase] SET HONOR_BROKER_PRIORITY OFF
GO
ALTER DATABASE [DBTase] SET RECOVERY FULL
GO
ALTER DATABASE [DBTase] SET MULTI_USER
GO
ALTER DATABASE [DBTase] SET PAGE_VERIFY CHECKSUM
GO
ALTER DATABASE [DBTase] SET DB_CHAINING OFF
GO
ALTER DATABASE [DBTase] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF )
GO
ALTER DATABASE [DBTase] SET TARGET_RECOVERY_TIME = 0 SECONDS
GO
EXEC sys.sp_db_vardecimal_storage_format N’DBTase’, N’ON’
GO
USE [DBTase]
GO
/****** Object: StoredProcedure [dbo].[cp_petowner] Script Date: 2020/11/20 10:22:57 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[cp_petowner]
AS
select * from product

GO
/****** Object: StoredProcedure [dbo].[cp_petowner_VarCharValue] Script Date: 2020/11/20 10:22:57 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
–2.创建一个带参数的存储过程
CREATE PROCEDURE [dbo].[cp_petowner_VarCharValue]
@ownername varchar(50)
AS
DECLARE @ownername2 varchar(50)
set @ownername2=’小米手机’
select *,@ownername as ownername from product where name=@ownername2

GO
/****** Object: StoredProcedure [dbo].[PROC_Product] Script Date: 2020/11/20 10:22:57 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
–【存储过程】查询产品表,根据类型ID 查询出所有产品,且返回产品数量
create proc [dbo].[PROC_Product]
@typeID int,
@count int out
as
begin

select @count=COUNT(ID) from Product where TypeID=@typeID;

select * from Product where TypeID=@typeID;
end

GO
/****** Object: StoredProcedure [dbo].[PROC_Product_insert] Script Date: 2020/11/20 10:22:57 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
–【存储过程】插入新产品的存储过程,产品名存在就不插入
create proc [dbo].[PROC_Product_insert]
@name nvarchar(50),
@typeID int ,
@count int out
as
begin
declare @c int;
select @c=COUNT(ID) from Product where Name=@name;
if(@c!=0)
set @count =0;
else
begin
insert into Product(name, typeID) values(@name,@typeID);
set @count=1;
end
end

GO
/****** Object: StoredProcedure [dbo].[PROC_TypeAndProduct] Script Date: 2020/11/20 10:22:57 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
–【存储过程】获取产品表和产品类型表中的所有数据
create procedure [dbo].[PROC_TypeAndProduct]
as
begin
select TypeID,TypeName from [Type];
select ID,TypeID,Name from Product;
end
GO
/****** Object: Table [dbo].[Product] Script Date: 2020/11/20 10:22:57 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Product](
[ID] [int] IDENTITY(1,1) NOT NULL,
[TypeID] [int] NULL,
[Name] [nvarchar](50) NULL,
CONSTRAINT [PK_Product] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object: Table [dbo].[Type] Script Date: 2020/11/20 10:22:57 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Type](
[TypeID] [int] IDENTITY(1,1) NOT NULL,
[TypeName] [nvarchar](50) NULL,
CONSTRAINT [PK_Type] PRIMARY KEY CLUSTERED
(
[TypeID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET IDENTITY_INSERT [dbo].[Product] ON

INSERT [dbo].[Product] ([ID], [TypeID], [Name]) VALUES (1, 1, N’苹果手机’)
INSERT [dbo].[Product] ([ID], [TypeID], [Name]) VALUES (3, 1, N’三星手机’)
INSERT [dbo].[Product] ([ID], [TypeID], [Name]) VALUES (4, 1, N’华为手机’)
INSERT [dbo].[Product] ([ID], [TypeID], [Name]) VALUES (5, 1, N’小米手机’)
INSERT [dbo].[Product] ([ID], [TypeID], [Name]) VALUES (7, 2, N’苹果电脑’)
INSERT [dbo].[Product] ([ID], [TypeID], [Name]) VALUES (8, 2, N’戴尔电脑’)
INSERT [dbo].[Product] ([ID], [TypeID], [Name]) VALUES (9, 3, N’小米手环’)
INSERT [dbo].[Product] ([ID], [TypeID], [Name]) VALUES (10, 3, N’华为手环’)
SET IDENTITY_INSERT [dbo].[Product] OFF
SET IDENTITY_INSERT [dbo].[Type] ON

INSERT [dbo].[Type] ([TypeID], [TypeName]) VALUES (1, N’手机’)
INSERT [dbo].[Type] ([TypeID], [TypeName]) VALUES (2, N’电脑’)
INSERT [dbo].[Type] ([TypeID], [TypeName]) VALUES (3, N’手表’)
SET IDENTITY_INSERT [dbo].[Type] OFF
ALTER TABLE [dbo].[Product] WITH CHECK ADD CONSTRAINT [FK_product_Type] FOREIGN KEY([TypeID])
REFERENCES [dbo].[Type] ([TypeID])
GO
ALTER TABLE [dbo].[Product] CHECK CONSTRAINT [FK_product_Type]
GO
USE [master]
GO
ALTER DATABASE [DBTase] SET READ_WRITE
GO
模型类
Type.cs
/// <summary>
/// 产品类型
/// </summary>
public class Type
{

/// <summary>
/// TypeID
/// </summary>
private int _typeid;
public int TypeID
{
get { return _typeid; }
set { _typeid = value; }
}
/// <summary>
/// TypeName
/// </summary>
private string _typename;
public string TypeName
{
get { return _typename; }
set { _typename = value; }
}

}
Product.cs
/// <summary>
/// 产品
/// </summary>
public class Product
{

/// <summary>
/// ID
/// </summary>
private int _id;
public int ID
{
get { return _id; }
set { _id = value; }
}
/// <summary>
/// TypeID
/// </summary>
private int _typeid;
public int TypeID
{
get { return _typeid; }
set { _typeid = value; }
}
/// <summary>
/// Name
/// </summary>
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}

public Type ProductType { get; set; }//做联表查询

}
数据库访问层
引入关键库
using System;
using System.Collections.Generic;
using System.Linq;
using Dapper;
using System.Data;
using System.Data.SqlClient;
创建数据库连接
private static string connStr = “server=.;uid=sa;pwd=sa;database=DBTase”;

添加 3个方法

1.新增一条数据,不带事务
/// <summary>
/// 新增一条数据,不带事务
/// </summary>
public static void Add()
{
string sql = @”insert into Type(TypeName) values(@TypeName)”;

Type productType = new Type()
{
TypeName = “测试类型2020-11-19”
};

using (SqlConnection conn = new SqlConnection(connStr))
{
int result = conn.Execute(sql, productType);
if (result > 0)
{
Console.WriteLine(“新增一条数据成功!”);
}
}
}
2.新增一条数据,且,返回自增ID;不带事务
/// <summary>
/// 新增一条数据,且,返回自增ID;不带事务
/// </summary>
public static void AddGetID()
{
/*
在高并发的环境中 可能得到的@@identity会不是你想要的结果
你在新增,别人也可能也在新增 。你获取的时候就是 获取到最后插入的那条记录的ID.
所以 我们要修改一下
SELECT @@identity
修改为
SELECT SCOPE_IDENTITY();
*/
string sql = @”insert into Type(TypeName) values(@TypeName);SELECT SCOPE_IDENTITY();”;

Type productType = new Type()
{
TypeName = “新增一条数据,且,返回自增ID;不带事务”
};

using (SqlConnection conn = new SqlConnection(connStr))
{
//获取新加的ID
int id = Convert.ToInt32(conn.ExecuteScalar(sql, productType));
if (id > 0)
{
Console.WriteLine(“新增一条数据,且,返回自增ID;不带事务”);
Console.WriteLine($”新增ID为:{id}”);
}
}
}
3.新增多条数据,不带事务
/// <summary>
/// 新增多条数据,不带事务
/// </summary>
public static void AddList()
{
string sql = @”insert into Type(TypeName) values(@TypeName)”;

List<Type> productTypeList = new List<Type>
{
new Type(){ TypeName = “1测试类型2020-11-19”},
new Type(){ TypeName = “2测试类型2020-11-19”},
new Type(){ TypeName = “3测试类型2020-11-19”},
new Type(){ TypeName = “4测试类型2020-11-19”},
new Type(){ TypeName = “5测试类型2020-11-19”},
new Type(){ TypeName = “6测试类型2020-11-19”}
};

using (SqlConnection conn = new SqlConnection(connStr))
{
int result = conn.Execute(sql, productTypeList);
if (result > 0)
{
Console.WriteLine(“新增多条数据,不带事务–添加成功!”);
}
}
}

 

修改 2个方法

1.修改一条数据,不带事务
/// <summary>
/// 修改一条数据,不带事务
/// </summary>
public static void Update()
{
string sql = @”update Type set TypeName=@TypeName where TypeID=@TypeID”;
Type productType = new Type()
{
TypeID = 5,
TypeName = “Update测试类型2020-11-19”
};
using (SqlConnection conn = new SqlConnection(connStr))
{
int result = conn.Execute(sql, productType);
if (result > 0)
{
Console.WriteLine(“修改一条数据成功!”);
}
}
}
2.修改多条数据,不带事务
/// <summary>
/// 修改多条数据,不带事务
/// </summary>
public static void UpdateList()
{
string sql = @”update Type set TypeName=@TypeName where TypeID=@TypeID”;
List<Type> productTypeList = new List<Type>
{
new Type(){ TypeID=6, TypeName = “1Update测试类型2020-11-19”},
new Type(){ TypeID=7, TypeName = “2Update测试类型2020-11-19”},
new Type(){ TypeID=8, TypeName = “3Update测试类型2020-11-19”},
new Type(){ TypeID=9, TypeName = “4Update测试类型2020-11-19”},
new Type(){ TypeID=10,TypeName = “5Update测试类型2020-11-19”},
new Type(){ TypeID=11,TypeName = “6Update测试类型2020-11-19”}
};
using (SqlConnection conn = new SqlConnection(connStr))
{
int result = conn.Execute(sql, productTypeList);
if (result > 0)
{
Console.WriteLine(“修改多条数据成功!”);
}
}
}

 

删除 2个方法
1.删除一条数据,不带事务
/// <summary>
/// 删除一条数据,不带事务
/// </summary>
public static void Delete()
{
string sql = @”delete Type where TypeID=@TypeID”;
Type productType = new Type();
productType.TypeID = 11;

using (SqlConnection conn = new SqlConnection(connStr))
{
//添加、删除、修改 Execute 存储过程
//update
int result = conn.Execute(sql, productType);
if (result > 0)
{
Console.WriteLine(“删除一条数据成功!”);
}
}
}

2.删除多条数据,不带事务
/// <summary>
/// 删除多条数据,不带事务
/// </summary>
public static void DeleteList()
{
string sql = @”delete Type where TypeID=@TypeID”;

List<Type> productTypeList = new List<Type>
{
new Type(){ TypeID=9},
new Type(){ TypeID=10}
};

using (SqlConnection conn = new SqlConnection(connStr))
{
//添加、删除、修改 Execute 存储过程
//update
int result = conn.Execute(sql, productTypeList);
if (result > 0)
{
Console.WriteLine(“删除多条数据成功!”);
}
}
}

 

查询/Join查询/函数查询/查询In操作/多语句查询/验证类型名是否存在 7个方法
1.查询一条数据
/// <summary>
/// 查询一条数据
/// </summary>
public static void GetModel()
{
Console.WriteLine(“******查询一条数据******”);

string sql = @”select * from Type where TypeID=@TypeID”;
Type productType = new Type();
productType.TypeID = 6;

using (SqlConnection conn = new SqlConnection(connStr))
{
Type _type = conn.Query<Type>(sql, productType).Single();
Console.WriteLine($”[ID:{_type.TypeID}]Name:{_type.TypeName}”);
}
}
2.普通查询-列表
/// <summary>
/// 普通查询-列表
/// ProductSelect产品查询
/// </summary>
public static void ProductSelect()
{
Console.WriteLine(“******普通查询-列表******”);
string sql = “select * from product”;

using (SqlConnection conn = new SqlConnection(connStr))
{
List<Product> productsList = conn.Query<Product>(sql).ToList();

Console.WriteLine(“//ProductSelect查询//”);
foreach (var item in productsList)
{
Console.WriteLine($”ID:{item.ID}\nName:{item.Name}”);
}
}

}
3.Join查询-列表
/// <summary>
/// Join查询-列表
/// ProductJoinTypeSelect产品带产品类型名称查询
/// </summary>
public static void ProductJoinTypeSelect()
{
Console.WriteLine(“******Join查询-列表******”);

string sql = @”select * from product p
left join type t
on (p.TypeID=t.TypeID)”;

using (SqlConnection conn = new SqlConnection(connStr))
{
var productsList = conn.Query<Product, Type, Product>
(sql, (product, type) =>
{
product.ProductType = type;//关联表
return product;
}, splitOn: “typeid”//建立关系的字段
).ToList();

Console.WriteLine(“//ProductJoinTypeSelect查询//”);
foreach (var item in productsList)
{
Console.WriteLine($”ID:{item.ID}\nName:{item.Name}\nTypeName:{item.ProductType.TypeName}”);
}
}

}

4.函数查询 和,平均值,最大值,最小值
/// <summary>
/// 函数查询 和,平均值,最大值,最小值
/// </summary>
public static void GetFunction()
{
Console.WriteLine(“******函数查询,和,平均值,最大值,最小值******”);

string sql = @”select * from Type”;//ORM框架执行效率排序EF 7 8 Dapper执行效率 1 2
using (SqlConnection conn = new SqlConnection(connStr))
{
List<Type> productTypeList = conn.Query<Type>(sql).ToList();
int count = productTypeList.Count();//获取记录条数
Console.WriteLine($”记录条数:{count}”);
var sum = productTypeList.Sum(p => p.TypeID);
var avg = productTypeList.Average(p => p.TypeID);
var max = productTypeList.Max(p => p.TypeID);
var min = productTypeList.Min(p => p.TypeID);
Console.WriteLine($”和 Sum:{sum}”);
Console.WriteLine($”平均值 Average:{avg}”);
Console.WriteLine($”最大值 Max:{max}”);
Console.WriteLine($”最小值 Min:{min}”);

foreach (Type t in productTypeList)
{
Console.WriteLine($”{t.TypeID}-{t.TypeName}”);
}
}
}
5.查询In操作
/// <summary>
/// 查询In操作
/// </summary>
public static void GetIn()
{
Console.WriteLine(“******查询In操作******”);

string sql = “select * from product where ID in @ids”;

int[] ids = {1,2,3,4,5};

using (SqlConnection conn = new SqlConnection(connStr))
{
List<Product> productsList = conn.Query<Product>(sql,new { ids= ids }).ToList();

foreach (var item in productsList)
{
Console.WriteLine($”ID:{item.ID}\nName:{item.Name}”);
}
}
}
6.多语句查询
/// <summary>
/// 多语句查询
/// </summary>
public static void GetMultiple()
{
Console.WriteLine(“******多语句查询******”);

string sql = “SELECT TypeID, TypeName FROM [Type];SELECT ID, TypeID, Name FROM Product”;

using (SqlConnection conn = new SqlConnection(connStr))
{
Dapper.SqlMapper.GridReader multiReader = conn.QueryMultiple(sql);

//注意:由于首先查出是Type,其次是Product,那么你在执行下面代码的时候顺序必须和sql语句顺序一致
IEnumerable<Type> typeList = multiReader.Read<Type>();
IEnumerable<Product> productList = multiReader.Read<Product>();

Console.WriteLine(“//多语句查询-类型信息”);
foreach (var item in typeList)
{
Console.WriteLine($”ID:{item.TypeID}\nName:{item.TypeName}”);
}

Console.WriteLine(“//多语句查询-产品信息”);
foreach (var item in productList)
{
Console.WriteLine($”ID:{item.ID}\nName:{item.Name}”);
}
}
}
7.验证类型名是否存在
/// <summary>
/// 验证类型名是否存在
/// </summary>
/// <param name=”name”>类型名</param>
/// <returns></returns>
public static bool Check(string name)
{
string sql = “select count(TypeName) from Type where TypeName=@TypeName”;
using (SqlConnection conn = new SqlConnection(connStr))
{
var number = conn.QueryFirst<int>(sql, new { TypeName = name });

if (number > 0)
{
return true;
}
return false;
}
}
事务 3个方法
1.事务第一种用法;添加一条分类的同时新增一条产品数据
/// <summary>
/// 事务第一种用法;添加一条分类的同时新增一条产品数据
/// </summary>
public static void ExecuteTranscationOne()
{

/*
在高并发的环境中 可能得到的@@identity会不是你想要的结果
你在新增,别人也可能也在新增 。你获取的时候就是 获取到最后插入的那条记录的ID.
所以 我们要修改一下
SELECT @@identity
修改为
SELECT SCOPE_IDENTITY();
*/
string TypeSql = @”insert into Type(TypeName) values(@TypeName);
SELECT SCOPE_IDENTITY();”;

string ProduxtSql = @”insert into Product(TypeID,Name)
values(@TypeID,@Name)”;

Type type = new Type()
{
TypeName = “新的分类1”
};
Product product = new Product()
{
TypeID = 0,
Name = “新的产品1”
};
using (SqlConnection conn = new SqlConnection(connStr))//打开数据库方式交给框架执行
{
SqlTransaction trans = null;
try
{
conn.Open();//手动打开数据库链接//在dapper中使用事务,需要手动打开连接
//程序事务,建立在某个连接对象上
//开始事务
trans = conn.BeginTransaction();//连接对象开启事务
int typeID = Convert.ToInt32(conn.ExecuteScalar(TypeSql, type, trans));
product.TypeID = typeID;
int result2 = conn.Execute(ProduxtSql, product, trans);
//提交事务(持久化数据)
trans.Commit();
if (result2 > 0)
Console.WriteLine(“事务1:添加一条数据成功”);
else
Console.WriteLine(“事务1:添加一条数据【失败】”);
}
catch (Exception ex)
{
//事务回滚
trans.Rollback();
Console.WriteLine(ex.Message);
}
}
}
2.事务第二种用法;添加一条分类的同时新增一条产品数据
/// <summary>
/// 事务第二种用法;添加一条分类的同时新增一条产品数据
/// </summary>
public static void ExecuteTranscationTwo()
{

/*
在高并发的环境中 可能得到的@@identity会不是你想要的结果
你在新增,别人也可能也在新增 。你获取的时候就是 获取到最后插入的那条记录的ID.
所以 我们要修改一下
SELECT @@identity
修改为
SELECT SCOPE_IDENTITY();
*/
string TypeSql = @”insert into Type(TypeName) values(@TypeName);
SELECT SCOPE_IDENTITY();”;

string ProduxtSql = @”insert into Product(TypeID,Name)
values(@TypeID,@Name)”;

Type type = new Type()
{
TypeName = “新的分类:事务2”
};
Product product = new Product()
{
TypeID = 0,
Name = “新的产品:事务2”
};
using (SqlConnection conn = new SqlConnection(connStr))//打开数据库方式交给框架执行
{
conn.Open();//在dapper中使用事务,需要手动打开连接

// 连接对象开启事务
//开始事务
using (SqlTransaction trans = conn.BeginTransaction())
{
try
{
//获取新加类型ID
int typeID = Convert.ToInt32(conn.ExecuteScalar(TypeSql, type, trans));
//把新的类型ID 给产品
product.TypeID = typeID;
int result2 = conn.Execute(ProduxtSql, product, trans);
//提交事务(持久化数据)
trans.Commit();

if (result2 > 0)
Console.WriteLine(“事务2:添加一条数据成功”);
else
Console.WriteLine(“事务2:添加一条数据【失败】”);
}
catch (Exception ex)
{
//事务回滚
trans.Rollback();
Console.WriteLine(ex.Message);
}
}
}
}
3.新增(添加)多条数据,带事务
/// <summary>
/// 新增多条数据,带事务
/// </summary>
public static void ExecAddList()
{
string sql = @”insert into Type(TypeID,TypeName) values(@TypeID,@TypeName)”;

List<Type> productTypeList = new List<Type>
{
new Type(){ TypeID=1, TypeName = “Exec1测试类型2020-11-20”},
new Type(){ TypeName = “Exec2测试类型2020-11-20”},
new Type(){ TypeName = “Exec3测试类型2020-11-20”},
new Type(){ TypeName = “Exec4测试类型2020-11-20”},
new Type(){ TypeName = “Exec5测试类型2020-11-20”},
new Type(){ TypeName = “Exec6测试类型2020-11-20″}
};

using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();//在dapper中使用事务,需要手动打开连接
// 连接对象开启事务
//开始事务
using (SqlTransaction trans = conn.BeginTransaction())
{
try
{
int result = conn.Execute(sql, productTypeList, trans);
//提交事务(持久化数据)
trans.Commit();
if (result > 0)
{
Console.WriteLine($”新增多条数据,带事务–添加{result}条成功!”);
}
}
catch (Exception ex)
{
//事务回滚
trans.Rollback();
Console.WriteLine(ex.Message);
}
}
}
}

 

执行存储过程 3个方法
1.查询产品表,根据类型ID 查询出所有产品,且返回产品数量
/// <summary>
/// 查询产品表,根据类型ID 查询出所有产品,且返回产品数量
/// </summary>
public static void PROC_Product_CountAndList()
{

using (SqlConnection conn = new SqlConnection(connStr))//打开数据库方式交给框架执行
{
//参数
DynamicParameters paras = new DynamicParameters();
paras.Add(“@typeID”, 1);//输入参数
paras.Add(“@count”, 0, DbType.Int32, ParameterDirection.Output);//输出参数

List<Product> productList = conn.Query<Product>(“PROC_Product”, paras, commandType: CommandType.StoredProcedure).ToList();//sql 存储过程

int count = paras.Get<int>(“@count”);//获取输出参数

Console.WriteLine($”共计:{count}”);
foreach (Product product in productList)
{
Console.WriteLine($”ID:{product.ID} – Name:{product.Name} – TypeID:{product.TypeID}”);
}
}
}
sql
–【存储过程】查询产品表,根据类型ID 查询出所有产品,且返回产品数量
create proc PROC_Product
@typeID int,
@count int out
as
begin

select @count=COUNT(ID) from Product where TypeID=@typeID;

select * from Product where TypeID=@typeID;
end
GO

–查询
DECLARE @count int
EXEC PROC_Product 1,@count OUTPUT
select @count
2.插入新产品的存储过程,产品名存在就不插入
/// <summary>
/// 插入新产品的存储过程,产品名存在就不插入
/// 参考:https://www.cnblogs.com/wyy1234/p/9078859.html
/// </summary>
public static void PROC_Product_insert()
{
using (SqlConnection conn = new SqlConnection(connStr))//打开数据库方式交给框架执行
{
//参数
DynamicParameters paras = new DynamicParameters();
paras.Add(“@name”, “苹果3”);//输入参数
paras.Add(“@typeID”, 1);//输入参数
paras.Add(“@count”, 0, DbType.Int32, ParameterDirection.Output);//输出参数

var result = conn.Query<Product>(“PROC_Product_insert”, paras, commandType: CommandType.StoredProcedure).ToList();//sql 存储过程

int count = paras.Get<int>(“@count”);//获取输出参数

Console.WriteLine($”插入:{count}条”);

}
}
sql
GO
–【存储过程】插入新产品的存储过程,产品名存在就不插入
create proc PROC_Product_insert
@name nvarchar(50),
@typeID int ,
@count int out
as
begin
declare @c int;
select @c=COUNT(ID) from Product where Name=@name;
if(@c!=0)
set @count =0;
else
begin
insert into Product(name, typeID) values(@name,@typeID);
set @count=1;
end
end
GO

–查询
DECLARE @count int
EXEC PROC_Product_insert “苹果手机2”,1,@count OUTPUT
select @count
3.获取产品表和产品类型表中的所有数据
/// <summary>
/// 获取产品表和产品类型表中的所有数据
/// 参考:https://www.cnblogs.com/wyy1234/p/9078859.html
/// </summary>
public static void PROC_TypeAndProduct()
{
using (SqlConnection conn = new SqlConnection(connStr))//打开数据库方式交给框架执行
{

//获取多个结果集
Dapper.SqlMapper.GridReader res = conn.QueryMultiple(“PROC_TypeAndProduct”, commandType: CommandType.StoredProcedure);

//注意:如果存储过程首先查出是Type,其次是Product,那么你在执行下面代码的时候顺序必须和存储过程查询顺序一致
//read方法获取Type和Product
IEnumerable<Type> typeList = res.Read<Type>();
IEnumerable<Product> productList = res.Read<Product>();
}
}
sql
GO
–【存储过程】获取产品表和产品类型表中的所有数据
create procedure PROC_TypeAndProduct
as
begin
select TypeID,TypeName from [Type];
select ID,TypeID,Name from Product;
end

–查询
EXEC PROC_TypeAndProduct

————————————————
版权声明:本文为CSDN博主「橙-极纪元」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cplvfx/article/details/109849118

Dapper 分页,万能公共分页,使用sql高效率分页_橙-极纪元的博客-CSDN博客

mikel阅读(568)

来源: Dapper 分页,万能公共分页,使用sql高效率分页_橙-极纪元的博客-CSDN博客

用户表实体类 UserInfoModel
public class UserInfoModel
{
public int Id{set;get;}
public int ClassId{set;get;}
public string Name{set;get;}
public int sex{set;get;}

}
分页模型

/*分页计算
当前显示数据=每页行数x(当前页数-1)
skip()跳过多少条,take()查询多少条
list.Skip(page.pageSize * (page.pageIndex – 1)).Take(page.pageSize).AsQueryable().ToList();
*/

/// <summary>
/// 分页信息
/// </summary>
public class PageInfo
{

/// <summary>
/// 每页行数(每页数据量):默认每页10条
/// </summary>
public int pageSize { get; set; } = 10;

/// <summary>
/// 当前页:默认第1页
/// </summary>
public int pageIndex { get; set; } = 1;

/// <summary>
/// 总记录数:默认0条
/// </summary>
public int count { get; set; } = 0;

/// <summary>
/// 总页数
/// </summary>
public int pageCount
{
get
{
if (count > 0)
{
return count % this.pageSize == 0 ? count / this.pageSize : count / this.pageSize + 1;
}
else
{
return 0;
}
}
}
}
数据库基类
using Dapper;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace User.Dal
{
public class BaseDapper
{
/// <summary>
/// 数据库连接字符串
/// </summary>
protected static string connStr = System.Configuration.ConfigurationManager.ConnectionStrings[“DbContext”].ConnectionString;

/// <summary>
/// 公共分页
/// </summary>
/// <typeparam name=”T”>返回类型</typeparam>
/// <param name=”model”>SQL条件</param>
/// <param name=”total”>结果集总数</param>
/// <param name=”param”>参数</param>
/// <returns></returns>
public static IEnumerable<T> GetPageList<T>(SQLSelectPageModel model,out int total,object param = null)
{
#region 分页算法
int skip = 1;//从第几条开始
int take = model.pageIndex * model.pageSize;//到第几条结束
if (model.pageIndex > 0)
{
skip = ((model.pageIndex – 1) * model.pageSize)+1;
}
#endregion

StringBuilder sqlStr = new StringBuilder();
sqlStr.Append($”SELECT COUNT(1) FROM {model.tableName} where {model.where};”);
sqlStr.Append($@”SELECT {model.files}FROM
(SELECT ROW_NUMBER() OVER(ORDER BY {model.orderby}) AS RowNum,{model.files} FROM {model.tableName} WHERE {model.where}) AS result
WHERE RowNum >= {skip} AND RowNum <= {take} ORDER BY {model.orderby}”);

using (SqlConnection conn = new SqlConnection(connStr))
{
//获取多个结果集
Dapper.SqlMapper.GridReader res = conn.QueryMultiple(sqlStr.ToString(), param: param, commandType: CommandType.Text);

//注意:如果存储过程首先查出是Type,其次是Product,那么你在执行下面代码的时候顺序必须和存储过程查询顺序一致
//read方法获取Type和Product
total = res.ReadFirst<int>();
IEnumerable<T> list = res.Read<T>();
return list;

//total = reader.ReadFirst<int>();
//return reader.Read<T>();
}
}
}
/// <summary>
/// sql 分页模型
/// </summary>
public class SQLSelectPageModel
{
/// <summary>
/// 查询的“列”
/// </summary>
public string files { set; get; }
/// <summary>
/// 表名 (可以跟join)
/// </summary>
public string tableName { set; get; }
/// <summary>
/// 条件
/// </summary>
public string where { set; get; }
/// <summary>
/// 排序 条件
/// </summary>
public string orderby { set; get; }
/// <summary>
/// 当前页
/// </summary>
public int pageIndex { set; get; }
/// <summary>
/// 当前页显示条数
/// </summary>
public int pageSize { set; get; }
}
}
子类调用
方式一 【推荐】
public class UserInfoDAL
{
/// <summary>
/// 根据分类ID获取信息列表
/// </summary>
/// <param name=”ClassId”>分类ID</param>
/// <param name=”sex”>性别 0 全部,1男,2女</param>
/// <param name=”pageInfo”>分页信息</param>
/// <returns></returns>
public static List<UserInfoModel> GetBaseInfoList(UserInfoModel UModel, PageInfo pageInfo)
{
List<UserInfoModel> result = new List<UserInfoModel>();
try
{
//1.SQL参数
SQLSelectPageModel sQLSelectPage = new SQLSelectPageModel() {
files=”*”,
tableName= “UserInfo”,
where= “ClassId=@ClassId”,
orderby= “Id desc”,
pageIndex= pageInfo.pageIndex,
pageSize= pageInfo.pageSize
};

//2.拼装条件 和参数
StringBuilder whereSB = new StringBuilder();

if (UModel.sex == 1 || UModel.sex == 2)
{
whereSB.Append(” and sex = @sex “);
}

sQLSelectPage.where = sQLSelectPage.where + whereSB.ToString();

//3.调用 基类 公共分页
var res = GetPageList<UserInfoModel>(sQLSelectPage, out int totalCount, UModel).ToList();

pageInfo.count = totalCount;

return res;
}
catch (Exception e)
{
return result;
}

}
}
方式二
public class UserInfoDAL
{
/// <summary>
/// 根据分类ID获取信息列表
/// </summary>
/// <param name=”ClassId”>分类ID</param>
/// <param name=”sex”>性别 0 全部,1男,2女</param>
/// <param name=”pageInfo”>分页信息</param>
/// <returns></returns>
public static List<UserInfoModel> GetBaseInfoList(int ClassId, int sex, PageInfo pageInfo)
{
List<UserInfoModel> result = new List<UserInfoModel>();
try
{
//1.SQL参数
SQLSelectPageModel sQLSelectPage = new SQLSelectPageModel() {
files=”*”,
tableName= “UserInfo”,
where= “ClassId=@ClassId”,
orderby= “Id desc”,
pageIndex= pageInfo.pageIndex,
pageSize= pageInfo.pageSize
};

//2.拼装条件 和参数
var param = new object();
if (sex == 1 || sex == 2)
{
sQLSelectPage.where = sQLSelectPage.where + ” and sex = @sex”;
param = new { ClassId = ClassId, sex = sex };
}
else
{
param = new {ClassId = ClassId};
}

//3.调用 基类 公共分页
var res = GetPageList<UserInfoModel>(sQLSelectPage, out int totalCount, param).ToList();

pageInfo.count = totalCount;

return res;
}
catch (Exception e)
{

}

return result;
}

}

————————————————
版权声明:本文为CSDN博主「橙-极纪元」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cplvfx/article/details/120204281

基于Dapper的分页实现,支持筛选,排序,结果集总数,多表查询,非存储过程 - JIN Weijie - 博客园

mikel阅读(562)

来源: 基于Dapper的分页实现,支持筛选,排序,结果集总数,多表查询,非存储过程 – JIN Weijie – 博客园

简介

之前事先搜索了下博客园上关于Dapper分页的实现,有是有,但要么是基于存储过程,要么支持分页,而不支持排序,或者搜索条件不是那么容易维护。

代码

首先先上代码: https://github.com/jinweijie/Dapper.PagingSample

方法定义

以下是我的一个分页的实现,虽然不是泛型(因为考虑到where条件以及SQL语句的搭配),但是应该可以算是比较通用的了,方法定义如下:

public Tuple<IEnumerable<Log>, int> Find(LogSearchCriteria criteria
            , int pageIndex
            , int pageSize
            , string[] asc
            , string[] desc);

以上函数定义是一个查询Log的示例,返回结果中,Tuple的第一个值是结果集,第二个值是总行数(例如,总共有100条记录,每页10条,当前第一页,那么第一个值是10条记录,第二个值是100)

在示例项目中,我用两种方法实现了分页:

1. 第一种是基于2此查询,第一次得到总数,第二次查询得到结果集。

2. 第二种是基于1此查询,用了SQLServer 的Offest/Fetch,所以只支持SQL Server 2012+,所以大家根据自己用的SQL Server版本选择不同的实现,这里当然是第二种实现效率更高一点。

运行示例

1. 将Github的Repo下载或者Clone到本地以后,到Database目录下,解压缩Database.7z

2. Attach到Sql Server上。默认我使用Sql Server LocalDB,连接字符串是 Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=DapperPagingSample;integrated security=True;   如果你用的不是LocalDB,请酌情修改App.Config的连接字符串。

3. Ctrl+F5运行程序,示例项目里,我用了一个简单的WinForm程序,但应该可以比较好的演示分页效果。

多表支持

增加了示例,支持多表查询,例如有两个Log表,Level表,Log的LevelId字段引用Level的Id字段,通过以下的查询,可以实现多表查询的分页,排序,过滤:

首先是通过两次查询的示例(基本支持所有版本Sql Server):

复制代码
 1 public Tuple<IEnumerable<Log>, int> Find(LogSearchCriteria criteria
 2             , int pageIndex
 3             , int pageSize
 4             , string[] asc
 5             , string[] desc)
 6         {
 7             using (IDbConnection connection = base.OpenConnection())
 8             {
 9                 const string countQuery = @"SELECT COUNT(1)
10                                             FROM      [Log] l
11                                             INNER JOIN [Level] lv ON l.LevelId = lv.Id
12                                             /**where**/";
13 
14                 const string selectQuery = @"  SELECT  *
15                             FROM    ( SELECT    ROW_NUMBER() OVER ( /**orderby**/ ) AS RowNum, l.*, lv.Name as [Level]
16                                       FROM      [Log] l
17                                       INNER JOIN [Level] lv ON l.LevelId = lv.Id
18                                       /**where**/
19                                     ) AS RowConstrainedResult
20                             WHERE   RowNum >= (@PageIndex * @PageSize + 1 )
21                                 AND RowNum <= (@PageIndex + 1) * @PageSize
22                             ORDER BY RowNum";
23 
24                 SqlBuilder builder = new SqlBuilder();
25 
26                 var count = builder.AddTemplate(countQuery);
27                 var selector = builder.AddTemplate(selectQuery, new { PageIndex = pageIndex, PageSize = pageSize });
28 
29                 if (!string.IsNullOrEmpty(criteria.Level))
30                     builder.Where("lv.Name= @Level", new { Level = criteria.Level });
31 
32                 if (!string.IsNullOrEmpty(criteria.Message))
33                 {
34                     var msg = "%" + criteria.Message + "%";
35                     builder.Where("l.Message Like @Message", new { Message = msg });
36                 }
37 
38                 foreach (var a in asc)
39                 {
40                     if(!string.IsNullOrWhiteSpace(a))
41                         builder.OrderBy(a);
42                 }
43 
44                 foreach (var d in desc)
45                 {
46                     if (!string.IsNullOrWhiteSpace(d))
47                         builder.OrderBy(d + " desc");
48                 }
49 
50                 var totalCount = connection.Query<int>(count.RawSql, count.Parameters).Single();
51                 var rows = connection.Query<Log>(selector.RawSql, selector.Parameters);
52 
53                 return new Tuple<IEnumerable<Log>, int>(rows, totalCount);
54             }
55         }
复制代码

第二个示例是通过Offset/Fetch查询(支持Sql Server 2012+)

复制代码
 1 public Tuple<IEnumerable<Log>, int> FindWithOffsetFetch(LogSearchCriteria criteria
 2                                                 , int pageIndex
 3                                                 , int pageSize
 4                                                 , string[] asc
 5                                                 , string[] desc)
 6         {
 7             using (IDbConnection connection = base.OpenConnection())
 8             {
 9                
10                 const string selectQuery = @" ;WITH _data AS (
11                                             SELECT l.*, lv.Name AS [Level]
12                                             FROM      [Log] l
13                                             INNER JOIN [Level] lv ON l.LevelId = lv.Id
14                                             /**where**/
15                                         ),
16                                             _count AS (
17                                                 SELECT COUNT(1) AS TotalCount FROM _data
18                                         )
19                                         SELECT * FROM _data CROSS APPLY _count /**orderby**/ OFFSET @PageIndex * @PageSize ROWS FETCH NEXT @PageSize ROWS ONLY";
20 
21                 SqlBuilder builder = new SqlBuilder();
22                 
23                 var selector = builder.AddTemplate(selectQuery, new { PageIndex = pageIndex, PageSize = pageSize });
24 
25                 if (!string.IsNullOrEmpty(criteria.Level))
26                     builder.Where("lv.Name = @Level", new { Level = criteria.Level });
27 
28                 if (!string.IsNullOrEmpty(criteria.Message))
29                 {
30                     var msg = "%" + criteria.Message + "%";
31                     builder.Where("l.Message Like @Message", new { Message = msg });
32                 }
33                 
34                 foreach (var a in asc)
35                 {
36                     if (!string.IsNullOrWhiteSpace(a))
37                         builder.OrderBy(a);
38                 }
39 
40                 foreach (var d in desc)
41                 {
42                     if (!string.IsNullOrWhiteSpace(d))
43                         builder.OrderBy(d + " desc");
44                 }
45                 
46                 var rows = connection.Query<Log>(selector.RawSql, selector.Parameters).ToList();
47 
48                 if(rows.Count == 0)
49                     return new Tuple<IEnumerable<Log>, int>(rows, 0);
50                 
51 
52                 return new Tuple<IEnumerable<Log>, int>(rows, rows[0].TotalCount);
53                 
54             }
55         }
复制代码

 

谢谢

希望对大家有帮助:)

最后,我更新了本篇随便,增加了内容,希望不要再被撤下了(上次撤下说是因为篇幅太短。。。),因为个人觉得这个对大家应该还是会有用的。