【学习笔记2 C#/面向对象/WinForm/ADO.NET及五大对象/Oracle数据库及数据交互】

学习日志

C#基础/面向对象/WinForm窗体开发-常用控件的属性、方法、事件/ADO.NET/Oracle数据库

一、软件工程相关知识

1、常用的设计模式

单例模式:在整个上下文中获取对象都是同一个实例对象----spring中的bean中/工具类/线程池 要保持数据库连接、线程池、配置信息等,必须整个程序保持一致,也防止了过多创建对象消耗内存。
工厂模式:(简单工厂模式、工厂方法模式、抽象工厂模式):创建与使用分离,工厂模式的核心思想。例子:创建对象交给 spring 处理。
代理模式:(静态代理、动态代理)
建造者模式:(生成器模式)
适配器模式:将一个接口转换为客户端所期望的接口,从而使两个接口不兼容的类能够协同工作。
装饰模式:现有的对象添加新的功能(不同于继承)
策略模式

2、设计原则(七大设计原则):

单一职责原则: 一类一职责。
接口隔离原则: 大接口拆分成小接口。
依赖倒置原则: 依赖抽象(抽象类或接口-定制规范)—面向接口编程。
里氏替换原则: 子类可以扩展父类的功能,但不能改变父类原有的功能.子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。
开闭原则: 当需求改变时,在不改变原有代码的前提下,通过扩展模块、函数来满足新需求。(使用设计模式的目的就是遵循开闭原则)。
迪米特法则: (最少知道原则)合成复用原则:尽量使用合成/聚合的方式,而不是使用继承。

二、C#基础

1、 .NET

版本.NET5、.NET6、.NET7 .NET平台是.NET Framework和.NET Core 的并轨

2、.cs文件结构

-using …引用命名空间(例using System;)
-namespace …项目的命名空间,大多数时候也是项目本身的名称
-public class class …类名class
-public form1()方法或者叫函数 主函数:Main方法

同一个命名空间中的类可以直接引用,不同命名空间中的类要先引用命名空间

3、C#的基本语法

.NET6新语法namespace的使用–新版namespace可以相当于java中的package

using System;
namespace WindowsFormsApplication1;
class Form1
{

}

C#大小写敏感

–关键字 class static ref out 等
–变量与类型 常用类型:double、char、string、int
–字符串拼接 + show()
–表达式
–分支语句if swich
–循环while for
–数组
–函数与方法 大驼峰、首字母大写、拼接词首字母大写
–参数修饰符out ref params

ref:需要赋初始值,在方法中对参数所做的任何更改都将反映在传入的变量中
out:不用赋初始值,返回值可以有多个——只使用一次方法的调用就能获得多个返回值
params:传递可变的参数。例:int Add(params int[] ints) 这里的ints可变参数数组被传递

二、面向对象基础

1、实例化类

类定义了对象的结构和行为,对象是类的实例。类可以包括字段(成员变量)和方法(成员函数)
里氏转换
1)子类对象可以直接赋值给父类变量
2)子类可以调用父类对象,但是父类只有调用自己
3)父类中如果是子类对象,则可以将父类强制转换为子类

2、抽象类以及抽象类不能被实例化(abstract)

//抽象类shape图形,包含一个抽象方法CalculateArea计算面积
public abstract class Shape
{
  public abstract double CalculateArea();
  //抽象类中普通方法
  public void Display()
  {
    Console.WriteLine("display");
  }
}

//派生类Circle和Rectangle,继承自基类
//圆
public class Circle:Shape
{
  public double Radius{get;set;}
  public Circle(double radius)
  {
    Radius = radius;
  }
  //重写基类抽象方法 CalcualteArea
  public override double CalcualteArea()
  {
    return Math.PI*Radius*Radius;
  }
}

//长方形
public class Rectangle:Shape
{
  public double Width{get;set;}
  public double Height{get;set;}
  public Rectangle(double width, double height)
  {
    Width = width;
    Height = height;
  }
  //重写基类抽象方法CalculateArea
  public override double CalculateArea()
  {
    return Width*Height;
  }
}


class Program
{
  static void main(string[] args)
  {
    //创建对象
    Shape circle = new Circle(5);
    circle.Display();
    //创建对象
    Shape rectangle = new Rectangle(6,4);
    rectangle.Display();
  }
}

3、嵌套类-类里面写类

class Car
{
	private string brand1;
	class Fadongji
	{
		private string brand2;
	}
}
访问嵌套类

Car.Fadongji carF=new Car.Fadongji();

4、接口(interface)

创建基类->创建接口->子类使用接口方法->测试子类
例:不牌子的车

//创建基类
class Car
{
	private string brand;
	public string Brand
	{ 
		get { return brand; } set { brand = value; }
	}
	public Car(string brand) 
	{
		this.brand = brand;
	}
	public void Run()
	{
		Console.WriteLine("{0}品牌的汽车在奔跑", brand);
		Console.ReadKey();
	}
}
//创建接口
internal interface IRun
{
    void Run();
}
class BMWCar:Car
{
	//初始化
	public BMWCar(string brand)
		:base(brand)
	{ }
}

class BatCar: Car,IRun
{
	public BatCar(string brand)
	:base(brand)
	{ }

	public void Run()
	{
		Console.WriteLine("batCarCanRun");
		Console.ReadKey();
	}
}

5、委托-引用类型

委托:(对具有特定参数列表和返回类型的方法的引用) 主要用于事件驱动、回调。委托可以看作是方法的类型安全的函数指针,允许将方法作为参数传递给其他方法,或者将方法赋值给变量,在需要的时候调用这些方法。

1)使用场景:

委托用于将方法作为参数传递给其他方法或变量
-当使用事件设计模式时,事件的订阅和通知
-当封装静态方法可取时
-当调用方不需要访问实现该方法的对象中的其他属性、方法或接口时,通过委托可以实现回调机制,让方法在某些条件下调用另一个方法。
-需要方便的组合
-当类可能需要该方法的多个实现时
-LINQ使用委托作为查询操作的参数,例如Where、Select等方法可以接受委托作为条件或者转换逻辑

2)属性:

-委托类似于 C++ 函数指针,委托会同时封装对象实例和方法
-委托允许将方法作为参数进行传递
-委托可用于定义回调方法
-委托可以链接在一起;例如,可以对一个事件调用多个方法
-方法不必与委托类型完全匹配
-使用 Lambda 表达式可以更简练地编写内联代码块。 Lambda 表达式(在某些上下文中)可编译为委托类型

3)委托和接口的其区别和联系

委托和接口都允许类设计器分离类型声明和实现,任何类或结构都能继承和实现给定的接口。 可以为任何类上的方法创建委托,前提是该方法符合委托的方法签名。 接口引用或委托可由不了解实现该接口或委托方法的类的对象使用。
-委托支持多播,一个委托可以引用多个方法,并按顺序依次调用它们
-接口不支持多播,每个实现接口的类需要独立实现接口方法

委托的使用-单播/多播/使用匿名方法和Lambda表达式
-delegate 关键字
使用 delegate 关键字时生成的代码会映射到调用 Delegate 和 MulticastDelegate 类的成员的方法调用
委托:语法看起来像是声明变量,但实际上是声明类型。可以在类中、直接在命名空间中、甚至是在全局命名空间中定义委托类型。

1>单播委托

//定义一个委托类型为MyDelegate,它可以引用任何具有如下签名的方法:返回类型为void,接受一个string类型参数

public class Program
{
    // 委托MyDelegate:返回类型为void,接受一个string类型参数
    public delegate void MyDelegate(string message);

    static void Main(string[] args)
    {
        // 实例化委托并绑定方法
        MyDelegate handler = new MyDelegate(Method1);

        // 调用委托
        handler("Hello World");
    }

    // 委托引用的方法1
    static void Method1(string message)
    {
        Console.WriteLine("Method1 says: " + message);
    }
}
2>多播委托

多个方法绑定到同一个委托实例上,在调用委托时,依次执行每一个绑定的方法

public class Program
{
    public delegate void MyDelegate(string message);

    static void Main(string[] args)
    {
        MyDelegate handler = Method1;
        handler += Method2; // 添加第二个方法到委托

        // 调用委托,会依次执行 Method1 和 Method2
        handler("Hello World");
    }

    static void Method1(string message)
    {
        Console.WriteLine("Method1 says: " + message);
    }

    static void Method2(string message)
    {
        Console.WriteLine("Method2 says: " + message);
    }
}
3>使用匿名方法和Lambda表达式来定义委托实例
public class Program
{
    public delegate void MyDelegate(string message);

    static void Main(string[] args)
    {
        // 使用匿名方法
        MyDelegate handler1 = delegate (string message)
        {
            Console.WriteLine("Anonymous Method says: " + message);
        };

        // 使用Lambda表达式
        MyDelegate handler2 = (message) =>
        {
            Console.WriteLine("Lambda Expression says: " + message);
        };

        // 调用委托
        handler1("Hello World");
        handler2("Hello World");
    }
}
6、事件-一种特殊的委托,用于实现发布-订阅模式

事件允许一个类在特定条件发生时通知其他类或对象,而无需知道这些对象的具体信息。事件通常声明为类的成员,通过event关键字声明,并且通常与委托类型结合使用。发布-订阅模式:其他对象可以订阅事件,当事件发生时,通知所有已订阅的对象。

public class Publisher
{
    // 定义事件
    public event EventHandler SomethingHappened;

    // 触发事件的方法
    protected virtual void OnSomethingHappened()
    {
        SomethingHappened?.Invoke(this, EventArgs.Empty);
    }

    // 其他方法
    public void DoSomething()
    {
        // 执行某些操作后触发事件
        OnSomethingHappened();
    }
}
7、装箱和拆箱

Object 是.NET 的万物之源,所有类型都继承自 System.Object,这也是装箱和拆箱的基础。装箱就是将值类型转换为引用类型的过程,拆箱就是将引用类型(装箱后对象)转换为值类型的过程。

三、WinForm窗体开发基本知识/常用控件的事件、方法和属性

1>创建窗体: Visual Studio,添加Windows窗体应用程序项目,创建新的WinForm应用程序
2>界面设计: 可视化设计器,在窗体上拖放控件并设置其属性
3>事件驱动模型: WinForm应用程序基于事件驱动,通过响应用户操作(如点击按钮)来执行相应的操作

常用控件的事件、方法和属性:
Lable、Button、ComboBox、ListView、DataGridView、RichTextBox

Label (标签)

属性:
Text:设置或返回标签控件中显示的文本信息
AutoSize:用来获取或设置一个值,该值指示是否自动调整控件的大小以完整显示其内容。取值为 true时,控件将自动调整到刚好能容纳文本时的大小,取值为false时,控件的大小为设计时的大小。默认值为false。
Anchor:可以设定 Top、Bottom、Right、Left 。子控件与父控件的位置关系

Button(按钮)

属性:
Text: 按钮上显示的文本
Enabled: 指示按钮是否可用
事件:
Click: 当按钮被点击时触发的事件
MouseHover, MouseLeave: 鼠标悬停和离开时触发的事件

ComboBox(下拉框)

属性:
Items: 下拉框中的选项列表
DropDownStyle: 下拉框的样式,如DropDown、DropDownList等
SelectedIndex, SelectedItem: 当前选中项的索引和值
事件:
SelectedIndexChanged: 选中项改变时触发的事件
DropDown: 下拉框展开时触发的事件

ListView(列表视图)

属性:
Items: 列表项的集合、Columns: 列头的集合,用于定义列表的列
View: 列表的显示模式,如Details、LargeIcon等
方法:
Add(), Remove(), Clear(): 添加、移除和清空列表项
Sort(): 对列表项进行排序
ItemSelectionChanged: 选择项改变时触发的事件
ColumnClick: 点击列头时触发的事件
事件:ItemSelectionChanged: 选择项改变时触发的事件
ColumnClick: 点击列头时触发的事件

DataGridView(数据网格视图)

属性:
DataSource: 数据源,绑定到DataGridView显示数据
Columns: 列定义,可以手动添加、删除和编辑列
Rows: 行集合,可以手动添加、删除和编辑行
方法:
Refresh(): 刷新DataGridView显示的数据
Update(): 更新数据源中的数据到DataGridView
事件:
CellClick, CellDoubleClick: 单元格点击和双击时触发的事件
CellValidating, CellValidated: 单元格验证前后触发的事件

RichTextBox(可以输入文本、 又可以编辑文本的文字处理控件)

属性:
Rtf:获取或设置RichTextBox控件中的文本,包括所有RTF格式代码。通常用于在RichTextBox控件和其他RTF源之间交换信息
方法:
Redo:重做上次被撤销的操作。例:RichTextBox对象.Redo() 该方法无参数
Find:从RichTextBox控件中查找指定的字符串。例:RichTextBox对象.Find(str)
SaveFile:用来把RichTextBox中的信息保存到指定的文件中。例: RichTextBox对象名.SaveFile(文件名);

四、ADO.NET-用于与数据源进行交互的一组技术和类库

(1)ADO.NET中五个对象

-Connection对象:创建连接对象,数据库与程序之间的连接
-Command对象:创建命令对象,对数据库发出查询,新增,修改,删除的命令
-DataAdapter对象:主要是在数据源和DataSet之间执行数据传输的工作,构造适配器调用结果集。在command对象下达命令后,将取得的数据存放到DataSet对象中
-DataSet对象:可以将从数据库中查询到的信息保存起来,甚至可以将整个数据库显示出来。DataSetCommand 对象取得一些例如主键等的数据表结构,并可以记录数据表间的关联
-DataReader对象:只需要循序的读取数据而不需要其它操作时,可以使用DataReader 对象:DataReader对象只是一次一笔向下循序的读取数据源中的数据,而且这些数据是只读的,并不允许作其它的操作

(2)使用:

使用Connection对象来连接数据库,使用Command 或DataAdapter对象来执行SQL语句,并将执行的结果返回给DataReader或DataAdapte ,然后再使用取得的DataReader或DataAdapter对象操作数据结果

五、数据类型DataSet 和 DataTable

DataSet:
内存中的数据缓存,可以包含一组DataTable、DataRelation和约束。允许在一个单一的数据结构中存储多个表,可以包含关系、约束和其他数据。DataSet可以容纳多个DataTable,这些表可以之间可以有关系。DataSet存储在内存中,可以通过数据适配器(DataAdapter)与数据库进行交互。
使用:

DataSet dataSet = new DataSet();
// 创建并添加表
DataTable table1 = new DataTable("Table1");
dataSet.Tables.Add(table1);
DataTable table2 = new DataTable("Table2");
dataSet.Tables.Add(table2);
// 建立表之间的关系
DataRelation relation = new DataRelation("RelationName", table1.Columns["Column1"], table2.Columns["Column2"]);
dataSet.Relations.Add(relation);

DataTable:
DataTable是DataSet中的一部分,代表内存中的一个表格,类似于数据库中的表。包含了若干行DataRow和列DataColumn,可以通过行和列来存储和操作数据。
使用:

// 创建DataTable并定义列
DataTable dataTable = new DataTable("TableName");
dataTable.Columns.Add("Column1", typeof(int));
dataTable.Columns.Add("Column2", typeof(string));
// 添加行
dataTable.Rows.Add(1, "Value1");
dataTable.Rows.Add(2, "Value2");
// 遍历行和列
foreach (DataRow row in dataTable.Rows)
{
    foreach (DataColumn col in dataTable.Columns)
    {
        Console.WriteLine(row[col]);
    }
}

六、Oracle数据库-数据交互

PL/SQL是Oracle的过程化SQL语言,用于编写存储过程、函数和触发器

using System.Data.OracleClient;
using System.Data;

//窗体上添加按钮Button1
private void Button1_Click(object sender, System.EventArgs e)
{
string ConnectionString="Data Source=sky;user=system;password=manager;";//连接串
OracleConnection conn=new OracleConnection(ConnectionString);//创建一个新连接
try
{
conn.Open();
OracleCommand cmd=conn.CreateCommand();

cmd.CommandText="select * from MyTable";//sql语句
OracleDataReader odr=cmd.ExecuteReader();//创建一个OracleDateReader对象
while(odr.Read())//读取数据,如果odr.Read()返回为false,说明到记录集的尾部了
{
Response.Write(odr.GetOracleString(1).ToString());//输出字段1,字段索引
}
odr.Close();
}
catch(Exception ee)
{
Response.Write(ee.Message); //有错误则输出错误信息
}
finally
{
conn.Close(); //关闭连接
}
}

public void oledboracle_dataset()
{
string ConnectionString="Data Source=mine;user=sys;password=sys;"; //连接串
OracleConnection conn=new OracleConnection(ConnectionString); //创建一个新连接
OracleCommand cmd= new OracleCommand("select * from fjdl.t_rights",conn);//sql语句
DataSet ds = new DataSet();//创建DataSet对象存储
OracleDataAdapter oda=new OracleDataAdapter();//创建OracleDataAdapter对象传递
oda.SelectCommand=cmd;
oda.Fill(ds);
conn.Close();
DataGrid1.DataSource=ds.Tables[0].DefaultView;
DataGrid1.DataBind();
}

1、调用一个带输入、输出参数的存储过程

Oralce中创建存储过程:

create or replace procedure GetRecords(name_out out varchar2,age_in in varchar2) as
begin
select NAME into name_out from test where AGE = age_in;
end;
string connectionString = "Data Source=…….;User ID=…...;Password=.....";
string queryString = "......";
OracleConnection cn = new OracleConnection(connectionString);
OracleCommand cmd = new OracleCommand(queryString,cn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("name_out",OracleType.VarChar,20);
cmd.Parameters["name_out"].Direction = ParameterDirection.Output;
cmd.Parameters.Add("age_in",21);

cn.Open();
cmd.ExecuteNonQuery();
Console.WriteLine("Name is:{0}",cmd.Parameters["name_out"].Value.ToString());
cn.Close();

注意事项:参数名称,必须和存储过程定义中的参数同名

2、调用不返回数据的存储过程----不返回数据的存储过程一般有Delete, Insert, Update

create or replace procedure insertRecord(UserID in varchar2,
UserName in varchar2,
UserAge in varchar2) is
begin
insert into test values (UserID, UserName, UserAge);
end;
string connectionString = "Data Source=…….;User ID=…...;Password=.....";
string queryString = "......";
OracleConnection cn = new OracleConnection(connectionString);
OracleCommand cmd = new OracleCommand(queryString,cn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("UserID","007");
cmd.Parameters.Add("UserName","Dell");
cmd.Parameters.Add("UserAge","40");

cn.Open();
cmd.ExecuteNonQuery();
Console.WriteLine("Record inserted!");
cn.Close();

注意事项:参数名称一定要和存储过程定义中的一致

3、使用DataReader读取返回的结果集

存储过程返回结果集,必须定义一个游标变量作为输出参数

string connectionString = "Data Source=…….;User ID=…...;Password=.....";
string queryString = "......";
OracleConnection cn = new OracleConnection(connectionString);
OracleCommand cmd = new OracleCommand(queryString,cn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("ret_cursor",OracleType.Cursor); 
cmd.Parameters["ret_cursor"].Direction = ParameterDirection.Output;

cn.Open();
OracleDataReader dr = cmd.ExecuteReader();
int i = 1;
while( dr.Read() )
{
Console.WriteLine("Record {0}:",i++);
Console.WriteLine("ID:{0} Name:{1} Age:{2}",
dr.GetOracleNumber(0),
dr.GetOracleString(1),
dr.GetOracleNumber(2));
Console.WriteLine();
}
dr.Close(); //DataReader对象及时关闭
cn.Close(); //DataReader对象未关闭之前不能关闭连接

4、返回的结果集填充DataSet:

利用ADO.NET从Oralce返回DataSet-用DataAdapter接收返回的游标,再用DataAdapter的Fill()方法填充数据集

string connectionString = "Data Source=…….;User ID=…….;Password=......";//连接串
string queryString = ".........";//sql语句,在Oracle中,存储过程可以通过包名和存储过程名来指定
OracleConnection cn = new OracleConnection(connectionString); //创建一个新连接
OracleCommand cmd = new OracleCommand(queryString,cn);
cmd.CommandType = CommandType.StoredProcedure;//将命令类型设置为存储过程,表明要执行的是一个存储过程而不是简单的SQL语句
cmd.Parameters.Add("ret_cursor",OracleType.Cursor);//添加一个名为 ret_cursor 的参数到命令对象中,其类型为 OracleType.Cursor。这种类型的参数通常用于从存储过程中返回结果集
cmd.Parameters["ret_cursor"].Direction = ParameterDirection.Output;//设置参数的方向为输出,表示这个参数是用来接收从存储过程返回的结果集

cn.Open();//打开与Oracle数据库的连接
OracleDataAdapter da = new OracleDataAdapter(cmd);//创建一个 OracleDataAdapter 对象 da,用来执行 OracleCommand 对象 cmd 所指定的查询或存储过程,并将结果填充到 DataSet 中
DataSet ds = new DataSet();//创建一个新的 DataSet 对象 ds,用来存储从数据库中检索的数据
da.Fill(ds,"TestTable");//使用 DataAdapter 执行查询,并将结果填充到 DataSet 中的名为 "TestTable" 的表中
cn.Close();//关闭与Oracle数据库的连接,释放资源

5、DataAdapter更新数据库:

通常用DataAdapter取回DataSet,将会对DataSet进行一些修改,继而更新数据库(如果只是为了获取数据,微软推荐使用DataReader代替DataSet)。然而,通过存储过程更新数据库不能简单地通过DataAdapter的Update()方法进行更新。必须手动为DataAdapter添加InsertCommand, DeleteCommand, UpdateCommand,因为存储过程对这些操作的细节是不知情的,必须人为给出。
Update()方法更新数据库是非常有用的,但是只局限于单个表,对于表连接的情况,还是直接用OracleCommand的ExcuteNonQuery()方法去执行更新操作比较方便

6、Oracle数据库中Package

Oracle数据库中Package(包):是一种数据库对象,允许将一组相关的PL/SQL程序单元(如过程、函数、变量、常量等)封装在一起,形成一个逻辑单元。Oracle中的包=包规范+包体
包规范:定义了包的接口,包括声明的过程、函数、变量、常量等
包体:包体包含实际的PL/SQL代码实现。定义了在包规范中声明的过程、函数的具体实现细节。包体部分对于外部程序单元来说是私有的,只有在授权的情况下可以访问其中的代码

–包头只负责定义,包体则负责具体实现。
–如果包返回多个游标,则DataReader会按照参数集合中添加它们的顺序来访问这些游标,而不是按照它们在过程中出现的顺序来访问。
–可使用DataReader的NextResult()方法前进到下一个游标

例:

包规范(定义了包 TestPackage 的接口部分,公开给其他程序单元使用的部分):
create or replace package TestPackage is
type mycursor is ref cursor; -- 定义游标变量
procedure GetRecords(ret_cursor out mycursor); -- 定义过程,用游标变量作为返回参数
end TestPackage;

包体(包含了实际的 PL/SQL 代码实现):
create or replace package body TestPackage is
/*过程体*/
procedure GetRecords(ret_cursor out mycursor) as
begin
open ret_cursor for select * from test;
end GetRecords;
end TestPackage;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值