Thứ Hai, 7 tháng 9, 2015
Thứ Sáu, 4 tháng 9, 2015
BÁO CÁO BÀI TẬP LỚN: ĐỒ HỌA MÁY TÍNH
Đề Tài: Viết Chương Trình Mô Phỏng Bắn Pháo Hoa
GV: Trần Xuân Thanh
I. Thành Viên Trong Nhóm
Nhóm 8 (bài 8)
1. Lương Kim Lượng
2. Lê Hữu Đoàn
3. Hoàng Văn Sơn
4. Lê Xuân Linh
5. Lại Văn Dũng
II. Tóm Tăt Lý Thuyết Và Thuật Toán Liên Quan
1. Tóm tắt lý thuyết
Pháo hoa hay pháo bông là loại pháo sử dụng thuốc phóng, thuốc nổ và các phụ gia đặc biệt tạo nên quang cảnh hoành tráng màu sắc của ánh sáng đa dạng hình khối phong phú, sinh động nhằm quy tụ cộng đồng trong những sinh hoạt văn hóa có tính tập thể như khai mạc, bế mạc ngày lễ tết, giao thừa, lễ hội chào mừng quốc khánh, đại hội thể thao các cấp. Là loại pháo lễ hội có lịch sử lâu đời, pháo hoa rất thịnh hành trong dân gian các nước phương Đông đặc biệt là Trung Hoa từ thời cổ đại. Tuy nhiên, hiện nay pháo hoa đã trở nên phổ biến toàn cầu và được sản xuất chủ yếu tại các nhà máy công nghiệp.
Trong bài viết này, chúng tôi sẽ mô phỏng kỹ thuật bắn pháo hoa, bằng ngôn ngữ lập trình C++ trong môi trường đồ họa (graphics)
Bài viết và chương trình có thể chưa hoàn thiện rất mong sự góp ý và tư vấn nhiệt tình từ phía thầy cô và các bạn.
Các hàm Sử Dụng
a) Hàm delay
Mục đích sử dụng : tạo độ trễ cho chương trình
Sử dụng thư viện : dos.h
Tham số bên trong hàm delay() là một con số (ngừng trong 1/1000 giây) ví dụ delay(1000) = 1s
Cách sử dụng
+ Cung cấp giá trị cho đối số n (có tham số trong lời gọi hàm)
delay(5000); //Đối số n=5000
+ Sử dụng giá trị mặc định của đối số (Không có hàm số trong lời gọi)
delay(); //Đối số n=1000
b) Hàm random() - Tạo 1 giá trị ngẫu nhiên bất kỳ
Để tạo ra một số ngẫu nhiên, chúng ta sử dụng hàm random(), Hàm này trả về cho chúng ta kết quả là một giá trị nguyên có giá trị từ 0 đến RANDOM_MAX
Với RANDOM_MAX là một hằng số được định nghĩa trong thư viện <stdlib>.
c) Một số hàm sẵn có trong thư viện đồ họa
putpixel(int x,int y,int c) vẽ 1 điểm trên màn hình với tọa độ x,y và màu c
bar3d(int x1,int y1,int x2,int y2,int deth,int top) vẽ 1 hình hộp 3D với tọa độ x1y1,x2y2 với depth là chiều sâu,top=0(hộp k có nắp)
setfillstyle(int b,int c) xác định mẫu tô màu với b là mẫu và c là màu vẽ (mẫu vẽ nằm trong dải từ 1 đến 12 với 1 là nét tô đậm
và 12 là nét vẽ do người dùng tự định nghĩa.
floodfill(int x,int y,int c) hàm tô màu với tọa độ xy và c là màu biên
hàm text trong chế độ đồ họa
settextstyle(int <phông chữ>,int <hướng chữ>,int <cỡ chữ>)
outtextxy(int x,int y,char *s) viết chữ với tọa độ xy và xâu s
2. Thuật Toán
Một số thuật toán vẽ đồ họa (tham khảo cuốn tài liệu Kỹ Thuật Đồ Họa - 2006 Học Viện Công Nghệ Bưu Chính Viễn Thông Hà Nội).
Thuật toán vẽ đường thẳng DDA (Digital Differential Analizer)
Thuật toán sinh đường tròn Midpoint và Bresenham
Các giải thuật tô màu...
hình ảnh chương trình khi chạy
► Video giới thiệu, cài đặt và chạy thử chương trình
<iframe width="560" height="315" src="https://www.youtube.com/embed/UEuEClFXkBY?rel=0&showinfo=0" frameborder="0" allowfullscreen></iframe>
II. Cài Đặt Mã Nguồn
#include <conio.h>
#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#include <graphics.h>
#include <dos.h>
#include <math.h>
#define round(a) int(a+0.5)
void InitGraph()
{
int gd=DETECT,gm,error;
initgraph(&gd,&gm,"../bgi");
error=graphresult();
if (error!=grOk)
{ printf("Loi do hoa %s",grapherrormsg(error));
printf("An phim bat ky de thoat");
getch(); exit(1);
}
}
void dda(int x1, int y1, int x2, int y2, int c)
{
float x=x1,y=y1,m;
if (x1!=x2)
{ m=float(y2-y1)/(x2-x1);
putpixel(x,round(y),c);
if ( m>-1 && m<1)
{ if (x1<x2)
for (x=x1; x<=x2; x++)
y+=m,putpixel(x,round(y),c);
if (x1>x2)
for (x=x1; x>=x2; x--)
y-=m,putpixel(x,round(y),c);
}
if (m<=-1 || m>=1)
{ if (y1<y2)
for (y=y1; y<=y2; y++)
x+=1/m,putpixel(round(x),y,c);
if (y1>y2)
for (y=y1; y>=y2; y--)
x-=1/m,putpixel(round(x),y,c);
}
}
else
for (int i=y1; i<=y2; i++) putpixel(x1,i,c);
}
void toquet1(int xmin,int ymin, int xmax, int ymax, int c) // dung cho hcn
{
for (int i=ymin+1; i<ymax; i++)
dda(xmin,i,xmax,i,c);
}
void toquet2(int xt,int yt,int r,int c) // dung cho hinh tron
{
int xmin=xt-r,ymin=yt-r,xmax=xt+r,ymax=yt+r,i,j;
for (i=xmin; i<=xmax; i++)
for (j=ymin; j<=ymax; j++)
if (((i-xt)*(i-xt)+(j-yt)*(j-yt))<=r*r)
putpixel(i,j,c);
}
void totrai(int x, int y, int mauto, int maubien);
void tophai(int x, int y, int mauto, int maubien);
void totren(int x, int y, int mauto, int maubien);
void toduoi(int x, int y, int mauto, int maubien);
void totrai(int x, int y, int mauto, int maubien)
{
int maudiem;
maudiem=getpixel(x,y);
if ((maudiem!=mauto)&&(maudiem!=maubien))
{ putpixel(x,y,mauto);
totrai(x-1,y,mauto,maubien);
totren(x,y-1,mauto,maubien);
toduoi(x,y+1,mauto,maubien);
}
}
void tophai(int x, int y, int mauto, int maubien)
{
int maudiem;
maudiem=getpixel(x,y);
if ((maudiem!=mauto)&&(maudiem!=maubien))
{ putpixel(x,y,mauto);
tophai(x+1,y,mauto,maubien);
totren(x,y-1,mauto,maubien);
toduoi(x,y+1,mauto,maubien);
}
}
void totren(int x, int y, int mauto, int maubien)
{
int maudiem;
maudiem=getpixel(x,y);
if ((maudiem!=mauto)&&(maudiem!=maubien))
{ putpixel(x,y,mauto);
totrai(x-1,y,mauto,maubien);
tophai(x+1,y,mauto,maubien);
totren(x,y-1,mauto,maubien);
}
}
void toduoi(int x, int y, int mauto, int maubien)
{
int maudiem;
maudiem=getpixel(x,y);
if ((maudiem!=mauto)&&(maudiem!=maubien))
{ putpixel(x,y,mauto);
totrai(x-1,y,mauto,maubien);
tophai(x+1,y,mauto,maubien);
toduoi(x,y+1,mauto,maubien);
}
}
void tomau(int x, int y, int mauto, int maubien) //(x,y) toa do tam
{
int maudiem;
maudiem=getpixel(x,y);
if ((maudiem!=mauto)&&(maudiem!=maubien))
{ putpixel(x,y,mauto);
totrai(x-1,y,mauto,maubien);
tophai(x+1,y,mauto,maubien);
totren(x,y-1,mauto,maubien);
toduoi(x,y+1,mauto,maubien);
}
}
void put8pixel(int x,int y,int xt,int yt, int color) // (xt,yt) toa do tam
{
putpixel(x+xt,y+yt,color); putpixel(y+xt,x+yt,color);
putpixel(x+xt,-y+yt,color); putpixel(y+xt,-x+yt,color);
putpixel(-x+xt,y+yt,color); putpixel(-y+xt,x+yt,color);
putpixel(-x+xt,-y+yt,color); putpixel(-y+xt,-x+yt,color);
}
void put30pixel(int a,int b,int xt, int yt,int c)
{ int i;
float x[30],y[30],grad=(12*3.14)/180;
x[0]=a; y[0]=b;
for(i=1; i<30; i++)
{ x[i]=x[0]*cos(i*grad)-y[0]*sin(i*grad)+yt*sin(i*grad)+xt*(1-cos(i*grad));
y[i]=x[0]*sin(i*grad)+y[0]*cos(i*grad)+yt*(1-cos(i*grad))-xt*sin(i*grad);
}
for (i=0; i<30; i++) putpixel(round(x[i]),round(y[i]),c);
}
void put8ht(int x, int y, int xt, int yt, int c)
{
toquet2(x+xt,y+yt,2,c); toquet2(y+xt,x+yt,2,c);
toquet2(x+xt,-y+yt,2,c); toquet2(y+xt,-x+yt,2,c);
toquet2(-x+xt,y+yt,2,c); toquet2(-y+xt,x+yt,2,c);
toquet2(-x+xt,-y+yt,2,c); toquet2(-y+xt,-x+yt,2,c);
}
//************************************************************************
void hcn(int x1, int y1, int x2, int y2,int c)
{
dda(x1,y1,x2,y1,c); dda(x1,y2,x2,y2,c);
dda(x1,y1,x1,y2,c); dda(x2,y1,x2,y2,c);
}
void hinhtron1(int xt, int yt, int r,int color) //(xt,yt) toa do tam
{
int x=0,y=r,p=3-2*r;
put8pixel(x,y,xt,yt,color);
while (x<=y)
{ if (p<0) p+=4*x+6;
else p+=4*(x-y)+10,y--;
x++;
put8pixel(x,y,xt,yt,color);
}
}
void hinhtron2(int xt, int yt, int r,int c) //(xt,yt) toa do tam
{
int x=0,y=r,p=3-2*r;
put8ht(x,y,xt,yt,c);
while (x<=y)
{ if (p<0) p+=4*x+6;
else p+=4*(x-y)+10,y--;
x++;
if (x%8==0) put8ht(x,y,xt,yt,c);
else put8ht(x,y,xt,yt,0);
}
}
//*****************************************************************************************
void bonghoa(int xt, int yt,int r,int c)
{
float x[5],y[5],grad=(72*3.14)/180;
x[0]=xt; y[0]=yt-2*r;
for (int i=1; i<5; i++)
{ x[i]=x[0]*cos(i*grad)-y[0]*sin(i*grad)+yt*sin(i*grad)+xt*(1-cos(i*grad));
y[i]=x[0]*sin(i*grad)+y[0]*cos(i*grad)+yt*(1-cos(i*grad))-xt*sin(i*grad);
}
hinhtron1(round(x[0]),round(y[0]),2*r,c); toquet2(round(x[0]),round(y[0]),2*r,c);
hinhtron1(round(x[1]),round(y[1]),2*r,c); toquet2(round(x[1]),round(y[1]),2*r,c);
hinhtron1(round(x[2]),round(y[2]),2*r,c); toquet2(round(x[2]),round(y[2]),2*r,c);
hinhtron1(round(x[3]),round(y[3]),2*r,c); toquet2(round(x[3]),round(y[3]),2*r,c);
hinhtron1(round(x[4]),round(y[4]),2*r,c); toquet2(round(x[4]),round(y[4]),2*r,c);
hinhtron1(xt,yt,r,14); toquet2(xt,yt,r,14);
}
void ngoisao(int xt, int yt, int r)
{
float x[5],y[5],grad=(72*3.14)/180;
x[0]=xt; y[0]=yt-2*r;
for (int i=1; i<5; i++)
{ x[i]=x[0]*cos(i*grad)-y[0]*sin(i*grad)+yt*sin(i*grad)+xt*(1-cos(i*grad));
y[i]=x[0]*sin(i*grad)+y[0]*cos(i*grad)+yt*(1-cos(i*grad))-xt*sin(i*grad);
}
dda(round(x[0]),round(y[0]),round(x[2]),round(y[2]),15);
dda(round(x[0]),round(y[0]),round(x[3]),round(y[3]),15);
dda(round(x[1]),round(y[1]),round(x[3]),round(y[3]),15);
dda(round(x[1]),round(y[1]),round(x[4]),round(y[4]),15);
dda(round(x[2]),round(y[2]),round(x[4]),round(y[4]),15);
tomau(xt,yt,14,15); tomau(xt-r/2,yt+r,14,15);
tomau(xt,yt-r,14,15); tomau(xt+4*r/5,yt+r,14,15);
tomau(xt-r,round((yt+y[1])/2),14,15); tomau(xt+r,round((yt+y[4])/2),14,15);
}
void cay(int xt, int yt,int r)
{
toquet2(xt,yt,r,10);
toquet1(xt-r/4,yt,xt+r/4,yt+4*r,6);
toquet2(xt-r,yt,r,10);
toquet2(xt+r,yt,r,10);
toquet2(xt,yt-r,r,10);
}
void chauhoa(int xt, int yt, int r, int c)
{
int i,j,k;
arc(xt,yt,180,360,r);
dda(xt-r,yt,xt+r,yt,c);
hcn(xt-r/2,yt,xt+r/2,yt+2*r,c);
toquet1(xt-r/2,yt,xt+r/2,yt+2*r,c);
for(i=xt-r; i<=xt+r; i++)
for(j=yt; j<=yt+r; j++)
if (((i-xt)*(i-xt)+(j-yt)*(j-yt))<=r*r) putpixel(i,j,c);
randomize(); k=1;
while (k<=30)
{ i=random(2*r)+xt-r;
j=random(r)+yt-r;
bonghoa(i,j,1,random(13)+1);
k++;
}
}
void moon(int xt, int yt, int r)
{
toquet2(xt,yt,r,14);
toquet2(xt+r/2,yt,r,0);
}
void phongnen()
{
int i;
hcn(0,415,getmaxx(),500,4); toquet1(0,415,getmaxx(),500,8);//to mau san truong
bar3d(200,300,440,450,30,1); toquet1(200,300,440,450,7);//khung ngoi nha 3D
hcn(200,300,440,450,WHITE);
setfillstyle(9,4);
floodfill(450,430,WHITE);//To mau canh ben
setfillstyle(1,12);
floodfill(430,290,WHITE);// to mau noc nha
setcolor(RED);
settextstyle(3,0,1);settextjustify(0,0); outtextxy(210,375,"Truong Dai Hoc Thanh Do");
//ve va to cua so
for(i=0;i<4;i++)
{
hcn(215+i*60,320,250+i*60,350,WHITE);
toquet1(215+i*60,320,250+i*60,350,BLACK);
}
//cua chinh
hcn(295,390,345,450,WHITE);setfillstyle(1,BLACK);
floodfill(320,400,WHITE);
setcolor(WHITE);
// duong vien
hcn(200,380,440,389,WHITE);
toquet1(200,380,440,389,3);
//bac thang
hcn(280,465,360,470,0); toquet1(280,465,360,470,7);
hcn(285,460,355,465,0); toquet1(285,460,355,465,7);
hcn(290,455,350,460,0); toquet1(290,455,350,460,7);
hcn(295,450,345,455,0); toquet1(295,450,345,455,7);
toquet1(295,465,345,470,4); toquet1(300,460,340,465,4);
toquet1(305,455,335,460,4); toquet1(310,450,330,455,4);
//tuong dai 2ben
for(i=0;i<5;i++)
{ hcn(440+i*20,443-i*7,640,450-i*7,0); toquet1(440+i*20,443-i*7,640,450-i*7,7);
hcn(200-i*20,443-i*7,0,450-i*7,0); toquet1(200-i*20,443-i*7,0,450-i*7,7);
}
//cot co, ngoi sao,chau hoa va cay
hcn(210,460,250,480,0);setfillstyle(5,YELLOW);floodfill(215,470,0); //toquet1(210,460,250,480,7);
hcn(210,460,250,480,6);
toquet1(228,280,232,460,15); toquet2(230,279,2,15);
toquet1(232,280,272,310,4); ngoisao(252,295,5);
cay(50,370,30); cay(150,400,20);
cay(590,370,30); cay(490,400,20);
moon(30,30,20);
for (i=0; i<4; i++)
{ chauhoa(460+i*40,450,15,15);
chauhoa(180-i*40,450,15,15);
}
}
//SET PHAO HOA
//Set tia phao
void tiaphao(int xt, int yt,int c)
{
toquet2(xt,yt,2,c); dda(xt,yt,xt,yt+10,c);
dda(xt,yt+10,xt-2,yt,c); dda(xt,yt+10,xt+2,yt,c);
randomize();
for(int i=0;i<5;i++) putpixel(xt,yt+10+2*i,c);
}
//Set hieu ung phao no
void phaono(int xt,int yt)
{
int i,j;
for(i=yt;i>=yt-80;i--)
{ put30pixel(xt,i,xt,yt,14); delay(20); }
toquet2(xt,yt,85,0);
for (i=0; i<10; i++)
{ int k=random(14)+1;
if (i%2==0)
for (j=0;j<10;j++) hinhtron2(xt,yt,j*8,k);
else
for (j=0;j<10;j++) hinhtron2(xt,yt,j*8,0);
delay(100);
}
}
//Loai phao hoa tron
void phaohoa()
{
int i,j,xt,yt,chon;
chon=random(5)+1;
switch(chon)
{ case 1:
{ xt=random(108)+1;
yt=random(110)+130;
for(i=289; i>=yt+2; i--)
{ tiaphao(xt,i,14);delay(10);tiaphao(xt,i,0);}
phaono(xt,yt);
break;
}
case 2:
{ xt=random(107)+109;
yt=random(25)+110;
for(i=340; i>=yt+2; i--)
{ tiaphao(xt,i,14);delay(10);tiaphao(xt,i,0);}
phaono(xt,yt);
break;
}
case 3:
{ xt=random(170)+227;
yt=random(25)+110;
for(i=255; i>=yt+2; i--)
{ tiaphao(xt,i,14);delay(10);tiaphao(xt,i,0);}
phaono(xt,yt);
break;
}
case 4:
{ xt=random(128)+401;
yt=random(25)+110;
for(i=240; i>=yt+2; i--)
{ tiaphao(xt,i,14);delay(10);tiaphao(xt,i,0);}
phaono(xt,yt);
break;
}
case 5:
{ xt=random(108)+530;
yt=random(110)+110;
for(i=289; i>=yt+2; i--)
{ tiaphao(xt,i,14);delay(10);tiaphao(xt,i,0);}
phaono(xt,yt);
break;
}
}
}
//Goi phao hoa
void banphaohoa()
{
int i,j,yt;
randomize();
for (i=0;i<10;i++) phaohoa();
yt=random(25)+130;
for (i=255; i>=yt+2; i--)
{ tiaphao(160,i,14); tiaphao(320,i,14);
tiaphao(480,i,14);
delay(10);
tiaphao(160,i,0); tiaphao(320,i,0);
tiaphao(480,i,0);
}
for(i=yt;i>=yt-80;i--)
{ put30pixel(160,i,160,yt,14);
put30pixel(320,i,320,yt,14);
put30pixel(480,i,480,yt,14);
delay(20);
}
toquet1(0,48,640,255,0);
for (i=0; i<6; i++)
{ int k=random(14)+1;
if (i%2==0)
for (j=0;j<10;j++)
{ hinhtron2(160,yt,j*8,k); hinhtron2(320,yt,j*8,k);
hinhtron2(480,yt,j*8,k);
}
else
for (j=0;j<10;j++)
{ hinhtron2(160,yt,j*8,0); hinhtron2(320,yt,j*8,0);
hinhtron2(480,yt,j*8,0);
}
delay(100);
}
//*********************************
yt=random(25)+130;
for (i=255; i>=yt+2; i--)
{ tiaphao(80,i,14); tiaphao(240,i,14);
tiaphao(400,i,14); tiaphao(560,i,14);
delay(10);
tiaphao(80,i,0); tiaphao(240,i,0);
tiaphao(400,i,0); tiaphao(560,i,0);
}
for(i=yt;i>=yt-80;i--)
{ put30pixel(80,i,80,yt,14);
put30pixel(240,i,240,yt,14);
put30pixel(400,i,400,yt,14);
put30pixel(560,i,560,yt,14);
delay(20);
}
toquet1(0,48,640,255,0);
for (i=0; i<16; i++)
{ int k=random(14)+1;
if (i%2==0)
for (j=0;j<10;j++)
{ hinhtron2(80,yt,j*8,k); hinhtron2(240,yt,j*8,k);
hinhtron2(400,yt,j*8,k); hinhtron2(560,yt,j*8,k);
}
else
for (j=0;j<10;j++)
{ hinhtron2(80,yt,j*8,0); hinhtron2(240,yt,j*8,0);
hinhtron2(400,yt,j*8,0); hinhtron2(560,yt,j*8,0);
}
delay(100);
}
//*****************************
yt=170;
for (i=255; i>=yt+2; i--)
{ tiaphao(80,i,14); tiaphao(240,i,14);
tiaphao(400,i,14); tiaphao(560,i,14);
tiaphao(160,i-40,14); tiaphao(320,i-40,14);
tiaphao(480,i-40,14);
delay(10);
tiaphao(80,i,0); tiaphao(240,i,0);
tiaphao(400,i,0); tiaphao(560,i,0);
tiaphao(160,i-40,0); tiaphao(320,i-40,0);
tiaphao(480,i-40,0);
}
for(i=yt;i>=yt-80;i--)
{ put30pixel(80,i,80,yt,14);
put30pixel(240,i,240,yt,14);
put30pixel(400,i,400,yt,14);
put30pixel(560,i,560,yt,14);
put30pixel(160,i-40,160,yt-40,14);
put30pixel(320,i-40,320,yt-40,14);
put30pixel(480,i-40,480,yt-40,14);
delay(20);
}
toquet1(0,48,640,255,0);
for (i=0; i<10; i++)
{
if (i%2==0)
for (j=0;j<10;j++)
{ hinhtron2(80,yt,j*8,random(14)+1); hinhtron2(240,yt,j*8,random(14)+1);
hinhtron2(400,yt,j*8,random(14)+1); hinhtron2(560,yt,j*8,random(14)+1);
hinhtron2(160,yt-40,j*8,random(14)+1); hinhtron2(320,yt-40,j*8,random(14)+1);
hinhtron2(480,yt-40,j*8,random(14)+1);
}
else
for (j=0;j<10;j++)
{ hinhtron2(80,yt,j*8,0); hinhtron2(240,yt,j*8,0);
hinhtron2(400,yt,j*8,0); hinhtron2(560,yt,j*8,0);
hinhtron2(160,yt-40,j*8,0); hinhtron2(320,yt-40,j*8,0);
hinhtron2(480,yt-40,j*8,0);
}
delay(100);cleardevice();
}
}
void main()
{
InitGraph();
phongnen();
banphaohoa();
getch();
closegraph();
}
III. Đánh Giá Và Kết Luận
Việc sử dụng kỹ thuật đồ họa C++ giúp ta mô phỏng khá tốt kỹ thuật bắn pháo hoa. Ngày nay, với sự phát triển nhanh chóng của công nghệ, việc mô phỏng có thể thực hiện tốt với đồ họa đẹp mắt và trơn tru hơn thì chúng ta có thể sử dụng thư viện đồ họa với thư viện và kỹ xảo 3D như OPENGL hay DIRECTX của hãng Microsoft kết hợp với lập trình C++.
Bài báo cáo đến đây là kết thúc, cảm ơn các thành viên đã cố gắng trong thời gian qua, cảm ơn quý thầy cô và các bạn đã đón đọc bài viết.
Chủ Nhật, 30 tháng 8, 2015
Thứ Ba, 25 tháng 8, 2015
//lớp vé tàu
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace vetau
{
abstract public class vetau
{
protected string tenve;
protected string loaive;
protected string ngayph;
protected double giave;
public string TENVE
{
get {
return tenve;
}
set
{
tenve = value;
}
}
public string LOAIVE
{
get
{
return loaive;
}
set
{
loaive = value;
}
}
public string NGAYPH
{
get
{
return ngayph;
}
set
{
ngayph = value;
}
}
public double GIAVE
{
get
{
return giave;
}
set
{
giave = value;
}
}
public vetau(string ten,string loai,string ngay,double gia)
{
this.tenve = ten;
this.loaive = loai;
this.ngayph = ngay;
this.giave = gia;
}
abstract public double tinhtoan();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace vetau
{
abstract public class vetau
{
protected string tenve;
protected string loaive;
protected string ngayph;
protected double giave;
public string TENVE
{
get {
return tenve;
}
set
{
tenve = value;
}
}
public string LOAIVE
{
get
{
return loaive;
}
set
{
loaive = value;
}
}
public string NGAYPH
{
get
{
return ngayph;
}
set
{
ngayph = value;
}
}
public double GIAVE
{
get
{
return giave;
}
set
{
giave = value;
}
}
public vetau(string ten,string loai,string ngay,double gia)
{
this.tenve = ten;
this.loaive = loai;
this.ngayph = ngay;
this.giave = gia;
}
abstract public double tinhtoan();
}
}
//lớp vé cứng kế thừa vé tàu
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace vetau
{
class VeCung:vetau
{
private int soluong;
public int SOLUONG
{
get
{
return soluong;
}
set
{
soluong = value;
}
}
public VeCung(string ten,string loai,string ngay,double gia,int sol):base(ten,loai,ngay,gia)
{
this.soluong = sol;
}
public override double tinhtoan()
{
if(soluong<=50)giave-=giave*0.02;
else giave-=giave*0.05;
return giave;
}
}
}
//lớp vé mềm kế thừa lớp vé
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace vetau
{
class VeMem:vetau
{
private string loaighe;
public string LOAIGHE
{
get { return loaighe; }
set { loaighe = value; }
}
public VeMem(string ten,string loai,string ngay,double gia,string loaighe):base(ten,loai,ngay,gia)
{
this.loaighe = loaighe;
}
public override double tinhtoan()
{
if(loaighe=="1")giave-=giave*0.02;
else giave-=giave*0.04;
return giave;
}
}
}
//form main
code view
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace vetau
{
public partial class Form1 : Form
{
private bool kt()
{
txtSoLuong.Enabled = true;
txtLoai.Enabled =false;
return true;
}
public Form1()
{
InitializeComponent();
}
VeMem vm = null;
VeCung vc = null;
string tenv;
string loaiv;
string ngaypv;
int solv;
double giav;
string loaighev;
public string LOAIGHEV
{
get
{
return loaighev ;
}
}
public string TENV
{
get
{
return tenv;
}
}
public int SOLCV
{
get
{
return solv;
}
}
public string LOAIV
{
get
{
return loaiv ;
}
}
string NGAYPHV
{
get
{
return ngaypv ;
}
}
public double GIAV
{
get
{
return
giav ;
}
}
private void Form1_Load(object sender, EventArgs e)
{
txtTenVe.Focus();
}
private void btnSaVe_Click(object sender, EventArgs e)
{
btnIn.Enabled = true;
try
{
if (txtTenVe.Text == "")
MessageBox.Show("Không Được Để Trống", "Thông Báo", MessageBoxButtons.OK, MessageBoxIcon.Information);
string ten = txtTenVe.Text.Trim();
if (txtLoaiVe.Text == "")
MessageBox.Show("Không Được Để Trống", "Thông Báo", MessageBoxButtons.OK, MessageBoxIcon.Information);
string loai = txtLoaiVe.Text.Trim();
string ngay = dpicNgayph.Value.ToShortDateString();
if (txtGia.Text ==null)
MessageBox.Show("Không Được Để Trống", "Thông Báo", MessageBoxButtons.OK, MessageBoxIcon.Information);
double gia = double.Parse(txtGia.Text.Trim());
int soluong = int.Parse(txtSoLuong.Text.Trim());
string loaighe = txtLoai.Text.ToString();
if(rdVeCung.Checked==true)
{
vc = new VeCung(ten, loai, ngay, gia, soluong);
giav = vc.tinhtoan();
tenv = vc.TENVE;
solv = vc.SOLUONG;
loaiv=vc.LOAIVE;
ngaypv=vc.NGAYPH;
}
if(rdVeMem.Checked==true)
{
vm = new VeMem(ten, loai, ngay, gia, loaighe);
giav = vm.tinhtoan();
tenv = vm.TENVE;
loaiv = vm.LOAIVE;
ngaypv = vm.NGAYPH;
loaighev = vm.LOAIGHE;
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void btnIn_Click(object sender, EventArgs e)
{
if (txtSoLuong.Text == null)
MessageBox.Show("Không Được Để Trống", "Thông Báo", MessageBoxButtons.OK, MessageBoxIcon.Information);
if (txtLoai.Text == null)
MessageBox.Show("Không Được Để Trống", "Thông Báo", MessageBoxButtons.OK, MessageBoxIcon.Information);
if(rdVeCung.Checked==true)
{
VeC vec = new VeC();
vec.TENVC = TENV;
vec.LOAIC = LOAIV;
vec.NGAYPHC = NGAYPHV;
vec.GIAVC =GIAV;
vec.SOLC = SOLCV;
vec.Show();
}
if(rdVeMem.Checked==true)
{
VeM vem = new VeM();
vem.TENVM = TENV;
vem.LOAIM = LOAIV;
vem.NGAYPHM = NGAYPHV;
vem.GIAVM = GIAV;
vem.LOAIGM
= LOAIGHEV;
vem.Show();
}
}
private void rdVeCung_CheckedChanged(object sender, EventArgs e)
{
if (rdVeCung.Checked == true) txtSoLuong.Enabled = true;
}
private void rdVeMem_CheckedChanged(object sender, EventArgs e)
{
if (rdVeMem.Checked == true) txtLoai.Enabled = true;
}
private void txtGia_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar < 48 || e.KeyChar > 58)
MessageBox.Show("Bạn không Được nhập chữ", "Thông Báo", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
//code form ve cung
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace vetau
{
public partial class VeC : Form
{
string tenvC;
string loaiC;
string ngaypC;
int solC;
double giaC;
public string TENVC
{
set
{
tenvC = value;
}
}
public int SOLC
{
set
{
solC = value;
}
}
public string LOAIC
{
set
{
loaiC = value;
}
}
public string NGAYPHC
{
set
{
ngaypC = value;
}
}
public double GIAVC
{
set
{
giaC = value;
}
}
public VeC()
{
InitializeComponent();
}
private void VeC_Load(object sender, EventArgs e)
{
lblTeVeCung.Text += tenvC;
lblLoaVeCung.Text += loaiC;
lblNamphCung.Text += ngaypC;
lblSolCung.Text += solC;
lblGiaVeCung.Text =lblGiaVeCung.Text+ giaC+"VND";
}
}
}
//code form ve mem
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace vetau
{
public partial class VeC : Form
{
string tenvC;
string loaiC;
string ngaypC;
int solC;
double giaC;
public string TENVC
{
set
{
tenvC = value;
}
}
public int SOLC
{
set
{
solC = value;
}
}
public string LOAIC
{
set
{
loaiC = value;
}
}
public string NGAYPHC
{
set
{
ngaypC = value;
}
}
public double GIAVC
{
set
{
giaC = value;
}
}
public VeC()
{
InitializeComponent();
}
private void VeC_Load(object sender, EventArgs e)
{
lblTeVeCung.Text += tenvC;
lblLoaVeCung.Text += loaiC;
lblNamphCung.Text += ngaypC;
lblSolCung.Text += solC;
lblGiaVeCung.Text =lblGiaVeCung.Text+ giaC+"VND";
}
}
}
Thứ Năm, 2 tháng 7, 2015
Làm việc với DataSet & DataAdapter
Ở bài trước bạn đã biết cách xử lý và hiện kết quả ra màn hình dùng Data Reader. Chú ý rằng : nếu chỉ muốn xem thông tin thì dùng Data Reader.
Bài này hướng dẫn sử dụng DataSet để xử lý kết quả kết hợp với DataAdapter. Không giống với DataReader, tạo ra các đối tượng dùng interface System.DataIDataReader, thì DataSet là một thành phần đặc trưng của ADO.NET được sử dụng bởi tất cả các nhà cung cấp dữ liệu (data provider). Dataset có thể hoàn toàn độc lập và sử dụng khi kết nối hoặc ngắt kết nối khỏi nguồn. Mục đích cơ bản của DataSet là cung cấp xử lý xem xét dữ liệu lưu trữ trong một ‘memory cache’. Nếu như một DataSet không kết nối tới cơ sở dữ liệu thì làm sao mà xử lý dữ liệu và save lại vào database ? Đây là lí do mà DataAdapter ra đời. Hãy nghĩ DataAdapter chính là một chiếc cầu nối giữa DataSet và Data Source. Nếu không có một DataAdapter nào thì DataSet không thể truy cập bất cứ DataSource nào. DataAdapter đảm bào việc kết nối và truyền thông tin cho DataSet. Tìm hiểu về ObjectModel Đầu tiên thì mình đưa ra một số so sánh giữa DataSet và DataReader nhé, để các bạn tránh hay hỏi nhiều về việc : Lúc nào thì xài DataSet và lúc nào thì xài DataReader, giống và khác nhau như thế nào ? So sánh DataSet và DataReader Nếu bạn đơn giản chi muốn lấy dữ liệu và trình bày nó ra thôi thì dùng DataReader. Đặc biệt trường hợp mà bạn đọc với một số lượng lớn dữ liệu, ví như là vòng lặp tới hàng triệu dòng kết quả dữ liệu, bạn muốn tốc độ đọc nhanh và trình bày nhanh thì DataReader được sử dụng cho mục đích này, NHANH và TIỆN LỢI, cho việc ĐỌC dữ liệu. Nếu bạn muốn chỉnh sử dữ liệu rồi update thông tin dữ liệu lại database thì bạn sử dụng DataSet. DataAdapter lấp đầy (fill) dữ liệu vào DataSet bằng cách sử dụng một DataReader, thêm vào đó resource cần được lưu trữ vào để sử dụng khi ngắt kết nối. Vì vậy việc sử dụng DataSet tốn nhiều tài nguyên hơn DataReader rất nhiều, bạn cần cân nhắc ở đây lúc nào sử dụng thành phần nào thì tốt, tránh lạm dụng quá. Nếu như bạn muốn đọc dữ liệu và viết ra dưới dạng XML, hoặc export database schema, viết lại db dưới dạng XML,…. thì nên sử dụng DataReader. Giới thiệu sơ qua về DataSet DataSet trong ADO.NET là một bước phát triển lớn trong việc phát triển ứng dụng cơ sở dữ liệu đa hệ. Khi lấy và chỉnh sửa dữ liệu, duy trì liên tục kết nối tới Data Source trong khi chờ user yêu cầu thì rõ ràng là tốn tài nguyên máy rất nhiều. DataSet giúp ích ở đây rất lớn. Vì DataSet cho phép lưu trữ dữ liệu và chỉnh sửa tại ‘local cache’, hay gọi là offline mode. Có thể xem xét và xử lý thông tin trong khi ngắt kết nối. Sau khi chỉnh sửa và xem xong thì tạo một kết nối và update dữ liệu từ local vào Data Source. Dữ liệu trong DataSet được lưu trữ dưới dạng một Collection các Tables và bạn cần phải xử lý thông qua các lớp DataTable -> DataRow và DataColumn. Bảng dưới đây là kiến trúc DataSet. Giới thiệu về DataAdapter Bạn chỉ cần tưởng tượng rằng : bạn có một cái bể nước (DataSource) , một cái máy bơm (DataAdapter) và một cái thùng đựng nước (DataSet). Thì khi lấy nước dùng cái bơm lấy nước từ bể, kiểm tra và lọc nước sau đó lại dùng cái bơm hút lại về cái bể nước. Đó chính là vai trò của cái bơm và DataAdapter tương tự như vậy. ^_^! Giải thích hơi chuối. Tương quan 3 lớp như thế này : Có 4 cách tạo DataAdapter : [code=C#] // Cách 1 : Đơn giản chỉ khai báo tạo đối tượng Adapter SqlDataAdapter da = new SqlDataAdapter(); // Cách 2 : Thiết lập đối tượng SqlCommand SqlDataAdapter da = new SqlDataAdapter(cmd); // Cách 3 : Thiết lập query và đối tượng SqlConnection SqlDataAdapter da = new SqlDataAdaoter(sql, conn); // Cách 4 : Thiết lập query và mệnh lệnh thực thi SqlDataAdapter da = new SqlDataAdapter(sql, connString); Giới thiệu về DataTable và thành phần kèm Nằm trong lớp : System.Data.DataTable. Có cấu trúc theo cấu trúc của bảng trong cơ sở dữ liệu gồm các hàng và cột nên có 2 thành phần kèm theo là : DataRow và DataColumn DataRow sẽ là tập hợp các cột (record-set) DataColumn là tập hợp các hàng cùng một đặc tính. (Field) Ví dụ :
Visual C# Code:
DataTable dt = new DataTable();
DataColumn col = dt.Columns[“Contact”]; // Cột Contact DataColumn col = dt.Columns[2]; DataRow row = dt.Rows[2]; Vậy là đủ giới thiệu qua. Bây giờ vào vấn đề chính nào. Làm việc với DataSet và DataAdapter Tạo một dataset :
Visual C# Code:
Có nhiều cách xử lý với DataSet như · Sử dụng thông qua Adapter · Đọc từ một tài liệu XML Cách thứ 2 đễ lúc khác nhé. Làm cơ bản trước đã. Thử xử lý dữ liệu bằng một ví dụ :
Visual C# Code:
using System;
using System.Data; using System.Data.SqlClient; namespace MSSQL_Server { class Database { static void Main(string[] args) { // Tạo connection strin string connString = @"Server = .\SQLEXPRESS; Integrated Security = True; Database = Northwind"; // Tạo SQL query string sql = @"SELECT productname, unitprice FROM products WHERE unitprice < 20"; // Tạo connection SqlConnection conn = new SqlConnection(connString); try { // Mỏ kết nối conn.Open(); // Tạo Adapter SqlDataAdapter da = new SqlDataAdapter(sql, conn); // Tạo DataSet DataSet ds = new DataSet(); // Lấp đầy kết quả vào DataSet da.Fill(ds, "products"); // Tạo DataTable thu kết quả từ bảng DataTable dt = ds.Tables["products"]; // In kết quả ra Console foreach (DataRow row in dt.Rows) { foreach (DataColumn col in dt.Columns) Console.WriteLine(row[col]); Console.WriteLine("".PadLeft(20, '=')); } } catch (Exception e) { // Bắt lỗi Console.WriteLine(e.Message); } finally { // Đóng kết nối conn.Close(); } } } } Sau khi đã mở kết nối thì ta tạo một Adapter. Adapter này chứa thông tin về SQL query cần thực thi và một đối tượng kết nối conn, sau đó tạo một DataSet. Lúc này thì DataSet chưa có gì. Sau đó lấp đầy kết quả vào DataSet bằng method ‘Fill’ của Adapter. Từ đó hiểu thêm rằng : Adapter tự động thực thi câu lệnh SQL , thu lấy kết quả và gán hết vào DataSet. Khác với DataReader cần có một đối tượng SqlComnmand đễ xử lý. Nếu khi lấp đầy kết quả vào DataSet mà không gán tên bảng nào thì tự động trong DataSet tên lần lượt từng bảng là ‘TableN’ với bảng đầu tiên là Table, Table1,Table2…TableN. Nếu một query được thực thi lại nhiều lần thì DataSet sẽ cập nhật thông tin từng đó bảng vào trong . Chú ý trong Adapter ở trên nếu thay bằng cách tạo Adapter dưới đây :
Visual C# Code:
DataSet có thể chứa nhiều table vì thế khi xử lý Table nào cần phải gán vào DataTable một tên table cụ thể. Và cuối cùng dùng DataColumn và DataRow để xử lý DataTable đó. Đó là cách extract dữ liệu từ DataSet. Phân loại và Sắp xếp trong DataSet Thử ví dụ dưới đây :
Visual C# Code:
using System;
using System.Data; using System.Data.SqlClient; namespace MSSQL_Server { class Database { static void Main(string[] args) { // Tạo connection strin string connString = @"Server = .\SQLEXPRESS; Integrated Security = True; Database = Northwind"; // Tạo SQL query string sql1 = @"SELECT * FROM customers "; string sql2 = @"SELECT * FROM products WHERE unitprice < 10 "; // Trộn 2 query vào làm 1 string sql = sql1 + sql2; // Tạo connection SqlConnection conn = new SqlConnection(connString); try { // Tạo Adapter SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = new SqlCommand(sql, conn); // Tạo và lấp đầy DataSet DataSet ds = new DataSet(); da.Fill(ds, "customers"); // Lấy Data Table Collection DataTableCollection dtc = ds.Tables; // Xử lý Table thứ nhất Console.WriteLine("Result from Customers table : "); Console.WriteLine("Company Name".PadRight(20) + "Contact Name".PadLeft(23) + "\n"); // Thiệt lập Filter string filter = "country = 'Germany'"; // Thiết lập Sort string sort = "companyname ASC"; // Hiển thị thông tin đã sort và filter foreach (DataRow row in dtc["customers"].Select(filter, sort)) { Console.WriteLine("{0}\t{1}", row["companyname"].ToString().PadRight(20), row["contactname"]); } // Xử lý table thứ hai Console.WriteLine("\n---------------------------"); Console.WriteLine("Result from Products table"); Console.WriteLine("ProductName".PadRight(20) + "UnitPrice".PadLeft(21) + "\n"); // Hiển thị thông tin foreach (DataRow row in dtc[1].Rows) { Console.WriteLine("{0}\t{1}", row["productname"].ToString().PadRight(25), row["unitprice"]); } } catch (Exception e) { // Bắt lỗi Console.WriteLine(e.Message); } finally { // Đóng kết nối conn.Close(); } } } } Hay à nha… Code này ở đây nhiều chỗ hơi bị phong độ đây. Chú ý và cẩn thận nhé. Cố gắng nhớ những gì tớ trình bày ở đây nè, hơi rắc rối một chút đây. ^_^! Ở đây xử lý 2 query sql1 và sql2 và chúng được combine vào thành 1 chuỗi query sql. Adapter tạo ra thực thi 2 query này. Vậy thì xử lý dữ liệu thế nào ?..Từ từ để sau Sau đó lấp đầy DataSet . Chú ý cài này :
Visual C# Code:
da.Fill(ds, “customers”);
Bây giờ bạn thử chèn thêm xuống dưới cùng trong khối ‘try’ đoạn code sau để phân tích thằng Fill
Visual C# Code:
Console.WriteLine(ds.Tables[0]);
Console.WriteLine(ds.Tables[1]); Sau đó bạn thử ‘foreach’ lấy hết kết quả của customers1 ra check thì nó chính là kết quả thu được từ query vào bảng ‘products’. Từ đó có thể suy luận ra cách làm việc của Fill, đầu tiên ta nhớ lại là DataSet là lưu trữ một loạt các Tables, khi Fill thì Adapter sẽ lấp đầy tất cả các kết quả từ các Table vào DataSet. Vậy thì ở đây sau khi đã query 2 tables thì fill lần lượt từ ‘customer’ đến ‘products’ với các Table sau customer bị đổi tên thành ‘customerN’ hết. Để muốn lấy lại tên ban đầu cho ‘products’ thì bạn chỉ cần thay đổi tên đi là được :
Visual C# Code:
ds.Tables[1].TableName = “products”;
Bây giờ nghĩ ra một cái hay nha.
Code:
da.Fill(ds, “products”); Bị lỗi : Object Reference is not an instance of an object. Là sao ? Tức là con trỏ vào đối tượng bị NULL. Tại sao bị NULL ? Thế này, theo thứ tự query thì ‘customers’ ở trước ‘products’. Cho nên khi Fill cũng theo thứ tự đó. Nghĩa là phải fill bắt đầu từ Customers thì con trỏ bắt đầu đi từ Tables[0]. Ở đây ta bỏ qua ‘customers’ mà vào luôn ‘products’ tức là Table[1], vậy là không có con trỏ tới Tables[0]. Đây bị coi là một Exception trong .NET. Vì thế nếu muốn xử lý products trước thì phải thay đổi thứ tự query tức là : Sql = sql2 + sql1; Lúc đó nếu Fill như trên thì tên của bảng ‘customers’ sẽ bị đổi thành ‘products1’. Ok. Tiếp ! Lúc này DataSet chứa nhiệu Table và ta muốn lấy tất cả thì dùng DataTableCollection để thu lượm tât cả các table trong DataSet. Hoặc nếu trình cao thì cứ lấy lần lượt theo index ds.Tables[int index] Bạn để ý tiếp có 2 string mới tạo là ‘filter’ và ‘sort’ Đây là dùng để lọc và sắp xếp dữ liệu. Vậy thì nguyên tắc làm thế nào ? Đơn giản là bạn dùng bộ lọc của SQL, tức là tạo chuỗi ‘filter’ và ‘sort’ theo syntax viết một câu SQL ấy. Có gì xem bài viết đầu tiên về SQL của tớ nha. Trong các table đều có Method Select(string filter, string sort) đễ lọc dữ liệu và sắp xếp. Ví dụ như code trên tớ dùng Select trong DataTableCollection. Nếu trong DataSet thì nó là : ds.Tables[int index].Select(string filter, string sort); Nào, chưa hết cái hay nha, tiếp. Hôm nọ tienlbhoc có hỏi tớ thế này : “ Tớ có đọc sách thấy sách nó dùng ví dụ, có Adapter và Connection mà chẳng bao giờ mở (open) connection mà chương trình chạy vẫn tốt, thế là thế nào nhỉ? “ Hì hì, vấn đề ở chỗ tớ viết trên cùng về cái máy bơm. Cái máy bơm thông với cái bể, bây giờ truyền nước và không truyền nước là do cái máy bơm quyết định. Cũng vậy ở đây bạn so sánh 2 cái ví dụ ở trên, một cái mở kết nối conn.Open() còn cái ví dụ dưới thì không cần mở. Nhắc lại method Fill(), method này là một đặc trưng của ADO.NET được cung cấp để truyền dữ liệu các DataSet và nó TỰ ĐỘNG mở kết nối khi gọi nó nếu như kết nối không được mở. Và sau khi fill vào DataSet thì lại tự động đóng kết nối. Mọi việc ở đây nằm trong quyền kiểm soát của cái Adapter hết. Bạn có thể tự kiểm tra tình trạng kết nối State để xác minh. Sử dụng DataView DataView được dùng để xem thông tin dữ liệu của một bảng, giống như SQL view, thêm nữa nó không giữ một tí dữ liệu nào. Vi dụ : Sử dụng DataView
Visual C# Code:
using System;
using System.Data; using System.Data.SqlClient; namespace MSSQL_Server { class Database { static void Main(string[] args) { // Tạo connection strin string connString = @"Server = .\SQLEXPRESS; Integrated Security = True; Database = Northwind"; // Tạo SQL query string sql = @"SELECT contactname, country FROM customers "; // Tạo connection SqlConnection conn = new SqlConnection(connString); try { // Tạo Adapter SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = new SqlCommand(sql, conn); // Tạo và lấp đầy DataSet DataSet ds = new DataSet(); da.Fill(ds, "customers"); // Lấy thông tin Table vào DataTable DataTable dt = ds.Tables["customers"]; // Tạo DataView DataView dv = new DataView(dt, "country = 'Germany'", "country", DataViewRowState.CurrentRows); // Hiển thị thông tin trong DataView foreach (DataRowView drv in dv) { for (int i = 0; i < dv.Table.Columns.Count; i++) { Console.Write(drv[i] + "\t"); } Console.WriteLine(""); } } catch (Exception e) { // Bắt lỗi Console.WriteLine(e.Message); } finally { // Đóng kết nối conn.Close(); } } } } Với 4 đối số : a. tên Table b.filter c. sort d.DataViewRowState enum Giải thích một chút về DataViewRowState · Added : dòng mới · CurrentRows : các dòng hiện tại, chưa bị thay đổi, mới và đã bị sửa đổi · Deleted : dòng đã xóa · ModifiedCurrent : giá trị đã sửa của dòng đã sửa · ModifiedOriginal : giá trị trước khi sửa của dòng đã sửa · None : Không lấy dòng nào · OriginalRows : tất cả dòng ban đầu · Unchanged : một dòng chưa bị sửa đổi. Mỗi thao tác của bạn sẽ có thể làm thay đổi RowState, vì vậy nên chú ý và sử dụng cho hợp lý. Sửa dữ liệu trong DataSet Dưới đây là minh họa sửa đổi dữ liệu trong DataSet. Nên nhớ là thay đổi trong dataset không hề ảnh hưởng gì đến Data Source. Muốn thay đổi trong Data Source thì phải tạo một kết nối tới database và update dữ liệu thay đổi lên thông qua DataSet và DataAdapter.
Visual C# Code:
using System;
using System.Data; using System.Data.SqlClient; namespace MSSQL_Server { class Database { static void Main(string[] args) { // Tạo connection strin string connString = @"Server = .\SQLEXPRESS; Integrated Security = True; Database = Northwind"; // Tạo SQL query string sql = @"SELECT * FROM employees WHERE country = 'UK' "; // Tạo connection SqlConnection conn = new SqlConnection(connString); try { // Tạo Adapter SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = new SqlCommand(sql, conn); // Tạo và lấp đầy DataSet DataSet ds = new DataSet(); da.Fill(ds, "employees"); // Lấy thông tin Table vào DataTable DataTable dt = ds.Tables["employees"]; // Cột FirstName có thể Null dt.Columns["FirstName"].AllowDBNull = true; // Thay đổi City của Row đầu tiên dt.Rows[0]["City"] = "Seoul"; // Thêm một dòng mới nha DataRow newRow = dt.NewRow(); newRow["FirstName"] = "Pete"; newRow["LastName"] = "Houston"; newRow["TitleOfCourtesy"] = "Sir"; newRow["City"] = "Seoul"; newRow["Country"] = "South Korea"; dt.Rows.Add(newRow); // Add xong hiển thị thông tin từ DataSet ra màn hình xem // đã update chưa foreach (DataRow row in dt.Rows) { Console.WriteLine("{0} {1} {2}", row["FirstName"].ToString().PadRight(10), row["LastName"].ToString().PadLeft(10), row["City"]); } } catch (Exception e) { // Bắt lỗi Console.WriteLine(e.Message); } finally { // Đóng kết nối conn.Close(); } } } } Run code trên xong, bạn thấy kết quả dòng trên cùng City là ‘Seoul’ và dưới cùng là một dòng mới, đó chính là thông tin của newRow đã thêm. Ở đây có thay đổi settings của Table, mặc định thì cột FirstName không được Null, mình ở đây sửa lại phát cho phép null luôn, và thay đổi dòng đầu tiên ở cột City. Sau đó thêm dòng mới vào DataSet. Chắc không có gì nói nhiều về cái này nhỉ. Thay đổi dữ liệu trong Data Source Quay về Adapter, để update thông tin thì ta dùng các thuộc tính : UpdateCommand, InsertCommand, DeleteCommand, còn SelectCommand thì không phải vì nó cung cấp SqlCommand để thực thi và chẳng ảnh hưởng gì đến xã hội cơ sở dữ liệu Thuộc tính UpdateCommand Như tên gọi đã nói lên đây là thực hiện Statement thay đổi dữ liệu trong database hay là câu lệnh UPDATE….SET Ví dụ thưc hiện Update :
Visual C# Code:
Visual C# Code:
using System;
using System.Data; using System.Data.SqlClient; namespace MSSQL_Server { class Database { static void Main(string[] args) { // Tạo connection strin string connString = @"Server = .\SQLEXPRESS; Integrated Security = True; Database = Northwind"; // Tạo SQL query string qry = @"SELECT * FROM employees WHERE country = 'UK' "; string upd = @"UPDATE employees SET city = @city WHERE employeeid = @employeeid "; // Tạo connection SqlConnection conn = new SqlConnection(connString); try { // Tạo Adapter SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = new SqlCommand(qry, conn); // Tạo và lấp đầy DataSet DataSet ds = new DataSet(); da.Fill(ds, "employees"); // Lấy thông tin Table vào DataTable DataTable dt = ds.Tables["employees"]; // Sửa dòng đàu tiên dt.Rows[0]["city"] = "Seoul"; // In ra màn hình xem sự thay đổi trong DataSet foreach (DataRow row in dt.Rows) { Console.WriteLine("{0} {1} {2}", row["firstname"].ToString().PadLeft(14), row["lastname"].ToString().PadRight(15), row["city"]); } // Tiến hành update vào database Source // tạo command trước SqlCommand cmd = new SqlCommand(upd, conn); // Xử lý các Parameter trong command cmd.Parameters.Add("@city", SqlDbType.NVarChar, 15, "city"); SqlParameter param = cmd.Parameters.Add("@employeeid", SqlDbType.Int, 4, "employeeid"); param.SourceVersion = DataRowVersion.Original; // UPDATE da.UpdateCommand = cmd; da.Update(ds, "employees"); } catch (Exception e) { // Bắt lỗi Console.WriteLine(e.Message); } finally { // Đóng kết nối conn.Close(); } } } }
Code:
use Northwind SELECT firstname,lastname,city FROM employees WHERE country = 'UK'
Thuộc tính InsertCommand
Ví dụ thử Insert thêm một dòng heng
Visual C# Code:
using System;
using System.Data; using System.Data.SqlClient; namespace MSSQL_Server { class Database { static void Main(string[] args) { // Tạo connection strin string connString = @"Server = .\SQLEXPRESS; Integrated Security = True; Database = Northwind"; // Tạo SQL query string qry = @"SELECT * FROM employees WHERE country = 'UK' "; string ins = @"INSERT INTO employees (firstname, lastname, titleofcourtesy, city, country) VALUES (@firstname, @lastname, @titleofcourtesy, @city, @country) "; // Tạo connection SqlConnection conn = new SqlConnection(connString); try { // Tạo Adapter SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = new SqlCommand(qry, conn); // Tạo và lấp đầy DataSet DataSet ds = new DataSet(); da.Fill(ds, "employees"); // Lấy thông tin Table vào DataTable DataTable dt = ds.Tables["employees"]; // Tạo thêm row mới DataRow newRow = dt.NewRow(); newRow["firstname"] = "Pete"; newRow["lastname"] = "Houston"; newRow["titleofcourtesy"] = "Sir"; newRow["city"] = "Seoul"; newRow["country"] = "South Korea"; dt.Rows.Add(newRow); // Hiển thị thông tin các rows trong DataSet foreach (DataRow row in dt.Rows) { Console.WriteLine("{0} {1} {2}", row["firstname"].ToString().PadRight(15), row["lastname"].ToString().PadLeft(15), row["city"]); } // Làm việc với Insert SqlCommand cmd = new SqlCommand(ins, conn); cmd.Parameters.Add("@firstname", SqlDbType.NVarChar, 10, "firstname"); cmd.Parameters.Add("@lastname", SqlDbType.NVarChar, 20, "lastname"); cmd.Parameters.Add("@titleofcourtesy", SqlDbType.NVarChar, 25, "titleofcourtesy"); cmd.Parameters.Add("@city", SqlDbType.NVarChar, 15, "city"); cmd.Parameters.Add("@country", SqlDbType.NVarChar, 15, "country"); // Tiến hành insert vào database Source da.InsertCommand = cmd; da.Update(ds, "employees"); } catch (Exception e) { // Bắt lỗi Console.WriteLine(e.Message); } finally { // Đóng kết nối conn.Close(); } } } } Rất đơn giản nên mình không giải thích gì ở đây Thuộc tình DeleteCommand Cái này các bạn thử nghiệm tự viết code thực hành nhé. Giới thiệu về SqlCommandBuilder Nhìn lại các code ở trên để update dữ liệu lên DataSource công nhận quá dài và ‘hơi bị NẢN’ khi viết code. Mệt nhất là khoản debug, quá rắc rồi và phức tạp. Vì vậy mà thằng cu SqlCommandBuilder trong họ đã ra đời để phục vụ việc tạo các statement ‘INSERT, UPDATE, DELETE’ một cách tự động. Thêm chú ý là sau khi thay đổi thông tin trên data source thì bạn phải gọi method ‘RefreshSchema’ của commandbuilder để cập nhật thông tin của metadata tương ứng. Làm ví dụ thêm một dòng vào database dùng SqlCommandBuilder nha
Visual C# Code:
using System;
using System.Data; using System.Data.SqlClient; namespace MSSQL_Server { class Database { static void Main(string[] args) { // Tạo connection strin string connString = @"Server = .\SQLEXPRESS; Integrated Security = True; Database = Northwind"; // Tạo SQL query string qry = @"SELECT * FROM employees WHERE country = 'UK' "; // Tạo connection SqlConnection conn = new SqlConnection(connString); try { // Tạo Adapter SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = new SqlCommand(qry, conn); // Tạo commandbuider SqlCommandBuilder cb = new SqlCommandBuilder(da); // Tạo và lấp đầy DataSet DataSet ds = new DataSet(); da.Fill(ds, "employees"); // Lấy thông tin Table vào DataTable DataTable dt = ds.Tables["employees"]; // Tạo thêm row mới DataRow newRow = dt.NewRow(); newRow["firstname"] = "Pete"; newRow["lastname"] = "Houston"; newRow["titleofcourtesy"] = "Sir"; newRow["city"] = "Seoul"; newRow["country"] = "South Korea"; dt.Rows.Add(newRow); // Hiển thị thông tin các rows trong DataSet foreach (DataRow row in dt.Rows) { Console.WriteLine("{0} {1} {2}", row["firstname"].ToString().PadRight(15), row["lastname"].ToString().PadLeft(15), row["city"]); } da.Update(ds, "employees"); } catch (Exception e) { // Bắt lỗi Console.WriteLine(e.Message); } finally { // Đóng kết nối conn.Close(); } } } } DataSet và XML Bạn muốn extract dữ liệu trong DataSet ra một file định dạng XML ? Liệu có cần đòi hỏi kiến thức XML để làm việc ?...heheh . Không cần biết về XML vẫn extract được Một ví dụ viết lưu dữ liệu trong DataSet dưới dạng XML.
Visual C# Code:
using System;
using System.Data; using System.Data.SqlClient; namespace MSSQL_Server { class Database { static void Main(string[] args) { // Tạo connection strin string connString = @"Server = .\SQLEXPRESS; Integrated Security = True; Database = Northwind"; // Tạo SQL query string qry = @"SELECT firstname,lastname, city FROM employees WHERE country = 'UK' "; // Tạo connection SqlConnection conn = new SqlConnection(connString); try { // Tạo Adapter SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = new SqlCommand(qry, conn); // Tạo commandbuider SqlCommandBuilder cb = new SqlCommandBuilder(da); // Tạo và lấp đầy DataSet DataSet ds = new DataSet(); da.Fill(ds, "employees"); // Extract ra file dưới dạng XML ds.WriteXml(@"P:\database.xml"); } catch (Exception e) { // Bắt lỗi Console.WriteLine(e.Message); } finally { // Đóng kết nối conn.Close(); } } } } Bạn sẽ thấy thẻ <NewDataSet> chính là name của DataSet. Bạn có thể tùy ý thay đổi DataSetName Thêm một chú ý nữa : bạn có thể dùng DataTable để lấy thông tin trong bảng từ DataAdapter thông qua method Fill da.Fill(dt); Trong ADO.NET có một thành phần rất đặc biệt có tên là Typed DataSet. Mình sẽ nói về cái này sau. Bài viết có lẽ quá dài nên kết thúc ở đây. |
Đăng ký:
Bài đăng (Atom)




