10/31/13

[Window Form] Multi Language (đa ngôn ngữ) trong Window Form

Để tạo một ứng dụng đa ngôn ngữ, cách điển hình là tạo các string table để lưu trữ các văn bản, chuỗi cho mỗi ngôn ngữ. Trong .NET, bạn có thể dùng các Resource để tạo ra các string table này và dùng lớp ResourceManager để quản lý và lấy ra các chuỗi cụ thể dựa vào một đối tượng CultureInfo.


Trước hết tôi tạo một ứng dụng WinFoms với tên WinFormsMultilingual, tạo thêm một thư mục tên là “Lang”. Sau đó thêm một Resources File với tên MyResource.resx vào thư mục này.


Tạo thêm hai Resource vào thư mục Lang tương ứng cho hai ngôn ngữ là English và Vietnamese. Các Resource này phải có tên theo dạng < default resource name >.<culture>.resx với <default resource name > chính là MyResource mà tôi đặt ở bước trên.
Solution Explorer sẽ có dạng:


Thêm dữ liệu vào các file MyResource.en-US.resx và  MyResource.vi-VN.resx. Mỗi dòng bao gồm hai cột cần có dữ liệu là Name và Value. Cột Name là định danh giúp lấy ra Value của bảng khi bạn dùng ResourceManager để làm việc:


Viết phương thức SetLanguage() để thay đổi ngôn ngữ cho giao diện. Các giá trị của tham số cultureName bạn có thể tham khảo ở cuối bài viết:

01private void SetLanguage(string cultureName)
02{
03    culture = CultureInfo.CreateSpecificCulture(cultureName);
04    ResourceManager rm = new
05        ResourceManager("WinFormsMultiLingual.Lang.MyResource",typeof(Form1).Assembly);
06
07    btnHello.Text = rm.GetString("hello", culture);
08    radEnglish.Text = rm.GetString("english", culture);
09    radVietnamese.Text = rm.GetString("vietnamese", culture);
10    helloWorldString = rm.GetString("helloworld", culture);
11}

Mã nguồn code-behind hoàn chỉnh của Form1.cs:

01using System;
02using System.Windows.Forms;
03using System.Resources;
04using System.Globalization;
05
06namespace WinFormsMultiLingual
07{
08    public partial class Form1 : Form
09    {
10        CultureInfo culture;
11        string helloWorldString = "Hello World!";
12
13        public Form1()
14        {
15            InitializeComponent();
16
17            culture = CultureInfo.CurrentCulture;
18
19        }
20
21        private void btnHello_Click(object sender, EventArgs e)
22        {
23            MessageBox.Show(helloWorldString);
24        }
25
26        private void LanguageRadioButtons_CheckedChanged(object sender, EventArgs e)
27        {
28            if (radEnglish.Checked)
29                SetLanguage("en-US");
30            else if (radVietnamese.Checked)
31                SetLanguage("vi-VN");
32            //else
33            //    ...
34
35        }
36
37        private void SetLanguage(string cultureName)
38        {
39            culture = CultureInfo.CreateSpecificCulture(cultureName);
40            ResourceManager rm = new
41                ResourceManager("WinFormsMultiLingual.Lang.MyResource",typeof(Form1).Assembly);
42
43            btnHello.Text = rm.GetString("hello", culture);
44            radEnglish.Text = rm.GetString("english", culture);
45            radVietnamese.Text = rm.GetString("vietnamese", culture);
46            helloWorldString = rm.GetString("helloworld", culture);
47        }
48    }
49}

Khi biên dịch, mỗi một tập tin Resource sẽ được tạo ra trong một thư mục mới với tên tương ứng là en-US và vi-VN. Mỗi thư mục này sẽ chứa một tập tin có tên WinFormsMultiLingual.resources.dll.
Kết quả:

[Window Form] TextBox chỉ cho phép nhập số

Trong rất nhiều ứng dụng, ta thường thấy có một vài textbox chỉ cho phép nhập số hoặc một vài ký tự đặc biệt nào đó. Mục đích là để đảm bảo dữ liệu mà người dùng nhập vào luôn hợp lệ. Chỉ với thủ thuật nhỏ dưới đây, bạn sẽ giải quyết vấn đề trên một cách dễ dàng.

Để ràng buộc dữ liệu nhập vào của textbox, ta sẽ xử lý sự kiện KeyPress của nó. Sự kiện này có ở hầu hết các control của C# và nó xảy ra khi người dùng nhấn một phím bất kỳ trên bàn phím.

  1. private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
  2. {
  3.     string ValidChar = "0123456789" + Convert.ToChar(8).ToString();
  4.     if (!ValidChar.Contains(e.KeyChar))
  5.         e.Handled = true;
  6. }
Đầu tiên ta sẽ tạo một chuỗi chứa những ký tự được phép nhập. Tại sao lại có dòng + Convert.ToChar(8).ToString() ? Bởi vì khi người dùng nhập dữ liệu, họ sẽ cần đến phím backspace để xóa các ký tự. Do đó ta phải đưa phím backspace (có mã ASCII là 8) vào dãy các ký tự hợp lệ ở trên.
Dòng e.Handled = true;  nghĩa là ta bỏ qua việc xử lý dữ liệu nhập vào của C#. Như vậy, vấn đề đã được giải quyết chỉ với vài dòng code. Thật đơn giản phải không.


Chúc các bạn thành công.

Tối ưu hóa chương trình C# - Cơ Bản

Đây là một số kinh nghiệm về tối ưu hóa mã nguồn C# sau một khoảng thời gian làm việc với nó. Bạn có thể áp dụng một số thủ thuật này trong các ngôn ngữ khác như VB.Net, Java…

Để đo thời gian thực thi của các đoạn mã ví dụ bên dưới, bạn có thể dùng DateTime.Now.Ticks lưu thời điểm bắt đầu và kết thúc. Tuy nhiên .Net cung cấp cho bạn sẵn đối tượng Stopwatch (đồng hồ bấm giờ) nằm trong không gian tên System.Diagnostics để dùng cho những công việc dạng này.

Trong mỗi phần tôi sẽ so sánh hai phương pháp (đoạn mã), phương pháp thứ hai sẽ là phương pháp tối ưu hơn cho bạn lựa chọn. Mặc dù các giải pháp thay thế có thể tốt hơn nhưng không hẳn đã là tối ưu, việc tối ưu một đoạn mã đòi hỏi sự hiểu biết và phân tích khá sâu vào nền tảng .Net, hơn nữa còn phụ vào thuật toán bạn sử dụng trong từng trường hợp.

1. So sánh chuỗi:


Ở đây tôi dùng hai phương pháp so sánh chuỗi thường sử dụng (có phân biệt hoa thường). Điểm khác biệt giữa hai phương thức này là phương thức thứ 1 là tĩnh (static) nên ta có thể gọi trực tiếp từ lớp String.

- (1) int String.Compare(string strA, string strB, bool ignoreCase)

- (2) bool string.Equals(string value, StringComparison comparisonType)

string s1=”aaa”;

string s2=”AAA”;

Đoạn mã 1:
for (int i = 0; i < 100000; i++)
{
bool b = String.Compare(s1, s2,true)==0;
}
Đoạn mã 2:
for (int i = 0; i < 100000; i++)
{
bool b = s1.Equals(s2,StringComparison.OrdinalIgnoreCase);
}
Đoạn mã thứ nhất chạy chậm hơn đoạn thứ hai hơn 3 lần. Tuy nhiên nếu bạn sử dụng tham số StringComparison.CurrentCultureIgnoreCase cho phương thức Equals thì tốc độ giữa hai đoạn mã là xấp xỉ. Một số người dùng cách chuyển cả hai chuỗi về dạng chữ hoa hoặc chữ thường rồi so sánh sẽ tốn thời gian lâu nhất (hơn 2 lần so với cách một).

2. Xây dựng chuỗi – String và StringBuilder:


Đây có lẽ là điều bạn thường gặp và cũng đã nắm bắt được sự khác biệt rõ ràng giữa chúng. Với số lần lặp tương đối lớn bạn sẽ có một khoảng thời gian chờ tương đối lâu khi làm việc với lớp String, vì thế tôi sẽ giảm số lần lặp xuống trong ví dụ này.

Đoạn mã 1:
string str=”";for (int i = 0; i < 10000; i++)
{
str += “a”;
}
Đoạn mã 2:
StringBuilder str=new StringBuilder();
for (int i = 0; i < 10000; i++)
{
str.Append(“a”);
}

Kết quả cho ta thấy đoạn mã một chạy chậm hơn khoảng từ 200 đến 300 lần đoạn mã hai. Nguyên nhân là toán tử + của lớp string sẽ tạo ra một đối tượng string mới trong mỗi lần lặp, trong khi phương thức Append của StringBuilder sẽ nối trực tiếp vào chuỗi hiện tại.

Tuy nhiên cũng cần chú ý điều này có thể ngược lại nếu như bạn cần chuyển chuỗi StringBuilder thành String trong mỗi lần lặp. Tốc độ thực thi của đoạn mã thứ hai sẽ lâu hơn so với đoạn mã một. Hãy kiểm chứng bằng cách chạy thử đoạn mã hai sau khi sửa lại như sau:


Đoạn mã 2 (đã sửa):
StringBuilder str = new StringBuilder();
string strRet;
for (int i = 0; i < 10000; i++)
{
    str.Append(“a”);
    strRet = str.ToString();
}

3. Nối chuỗi – Phương thức Insert() và toán tử +:


Bạn thường sử dụng hai cách để nối hai chuỗi lại với nhau là dùng toán tử + và phương thức Insert() của đối tượng string. Cách đầu tiên được sử dụng nhiều hơn vì cách viết tiện lợi và dễ hiểu hơn, tuy nhiên bạn chỉ có thể nối vào đầu hoặc cuối chuỗi. Hãy thử so sánh xem phương pháp nào cho tốc độ thực thi nhanh hơn, giả sử bạn cần nối một chuỗi con vào đầu một chuỗi.

Đoạn mã 1:
string str=”";
for (int i = 0; i < 10000; i++)
{
str = “string”;
str= str.Insert(0, “my “);
}
Đoạn mã 2:
string str=”";
for (int i = 0; i < 10000; i++)
{
str = “string”;
str = “my ” + str;
}
Nếu chạy thử vài lần, bạn sẽ nhận thấy rằng đoạn mã thứ hai chạy nhanh gấp đôi đoạn mã một. Tuy nhiên nếu như không khởi tạo lại giá trị của biến str trong mỗi lần lặp, tốc độ của hai đoạn mã này là xấp xỉ nhau.

4. Cắt chuỗi – Substring() và Remove():


Hai phương thức trên của lớp string có chức năng khá giống nhau là cắt bỏ một phần chuỗi nguồn. Cả hai phương thức đều có 2 kiểu nạp chồng, và đều yêu cầu truyền vào vị trí bắt đầu của chuỗi. Tùy vào trường hợp, Substring() thích hợp cho việc cắt bỏ chuỗi phía trước, còn Remove() lại thường dùng để cắt bỏ phía sau chuỗi. Trong ví dụ này tôi sẽ dùng hai phương thức này để cắt bỏ 1 kí tự phía trước chuỗi:

Đoạn mã 1:
string str;
for (int i = 0; i < 10000; i++)
{
str = “string”;
str = str.Remove(0, 1);
}
Đoạn mã 2:
string str;
for (int i = 0; i < 10000; i++)
{
str = “string”;
str = str.Substring(1);
}
Sự khác biệt giữa đoạn mã hai so với đoạn mã một là tốc độ nhanh hơn khoảng 2 lần. Tuy nhiên sự khác biệt này sẽ trở nên khó phân biệt nếu như bạn dùng chúng để cắt ở vị trí khác, như là cuối chuỗi chẳng hạn.

5.      Chuyển đối tượng về dạng chuỗi – Format() và ToString();


Format là một phương thức khá hiệu quả trong một số trường hợp bạn cần thêm các tham số và một chuỗi, sử dụng tương tự như cách bạn in một chuỗi ra màn hình console bằng phương thức WriteLine().

Đoạn mã 1:
string str = “”;
int obj = 1;
for (int i = 0; i < 100000; i++)
{
str = String.Format(“{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}”, obj);
}
Đoạn mã 2:
string str = “”;
int obj = 1;
for (int i = 0; i < 100000; i++)
{
string s = obj.ToString();
str = s + s + s + s + s + s + s + s + s + s;
}
Ở đây tôi tạo ra một đối tượng string với giá trị là mười số 1 trong mỗi lần lặp. Cả hai phương pháp này đều chạy khá lâu với số lần lặp là 100000. Tuy nhiên đoạn mã thứ nhất sẽ tốn thời gian gấp gần 5 lần so với đoạn mã thứ hai, mặc dù đoạn mã thứ hai còn sử dụng toán tử cộng chuỗi.

6. Sự khác biệt giữa các phương thức nạp chồng (overloaded):



Bạn có thể không để ý rằng giữa các phương thức nạp chồng, thực hiện cùng một công việc lại có sự khác biệt về khoảng thời gian mà chúng thực thi. Điều này thường thấy trong các phương thức với tham số là một hoặc nhiều kiểu đối tượng được tạo ra từ những thành phần đơn giản hơn.

Chẳng hạn như phương thức khởi tạo của đối tượng Rectangle, ta sẽ thử xét hai phương thức:

- (1) Rectangle (Point location, Size size)

- (2) Rectangle (int x, int y, int width, int height)

Sự khác biệt về thời gian thực thi giữa 2 phương thức phụ thuộc vào đoạn mã chúng ta viết.

Nếu bạn so sánh giữa 2 đoạn mã sau:

Đoạn mã 1:
for (int i = 0; i < 100000; i++)
{
Rectangle rec = new Rectangle(new Point(i,i), new Size(i,i));
}
Đoạn mã 2:
for (int i = 0; i < 100000; i++)
{
Rectangle rec = new Rectangle(i,i,i,i);
}
Bạn có thể nhận thấy là đoạn mã thứ nhất chạy lâu hơn đoạn thứ hai khoảng 7 lần. Lý do xảy ra điều này bạn có thể đoán được là phương thức thứ nhất phải tạo ra 2 đối tượng trong mỗi lần lặp.

7. Hạn chế sử dụng khối try catch:


Việc xử lý các ngoại lệ trong C# thường chiếm một khoảng thời gian tương đối lâu. Một số ngoại lệ có thể dự đoán trước được ,và thay vì sử dụng khổi try catch để bao đoạn mã không an toàn này lại, bạn hãy tự xử lý thông qua các dòng lệnh kiểm tra trước khi để đoạn mã tiếp tục thực hiện. Đây là một ví dụ:

int a = 0, b = 10;

Đoạn mã 1:
for (int i = 0; i < 1000; i++)
{
try
{
int c = b / a;
}
catch { }
}
Đoạn mã 2:
for (int i = 0; i < 1000; i++)
{
if (a == 0)
continue;
int c = b / a;
}
Dòng lệnh int c = b / a dĩ nhiên luôn ném ra ngoại lệ Divide by Zero (chia cho 0) nếu được thực thi. Tuy nhiên ngoại lệ này bạn có thể đoán trước và kiểm tra mẫu số phải khác 0 trước khi tiếp tục hay không. Sự cẩn trọng như trong đoạn mã 2 giúp bạn tiết kiệm được thời gian khoảng 30,000 (30 nghìn) lần so với đoạn mã 1.

8. Hạn chế việc gọi phương thức:


Việc gọi phương thức nhiều lần có thể làm giảm tốc độ thực thi của chương trình so với việc viết trực tiếp thân hàm vào nơi cần thiết. Vì thế đối với những phương thức có nội dung đơn giản và không được gọi ở nhiều nơi khác nhau, bạn nên loại bỏ bớt đi những phương thức này. Điều này thường ít xảy ra nhưng có thể giúp bạn cẩn thận hơn trong việc quyết định có nên tạo ra một phương thức mới hay không.

Giả sử bạn có 1 phương thức Method() đơn giản như sau:
private void Method()
{
int a = 1, b = 2;
int c = a + b;
}
Bạn có hai cách để thực thi hai phương thức trên như sau:

Đoạn mã 1:
for (int i = 0; i < 1000000; i++)
{
Method();
}
Đoạn mã 2:
for (int i = 0; i < 1000000; i++)
{
int a = 1, b = 2;
int c = a + b;
}
Đoạn mã thứ hai chạy nhanh đoạn thứ nhất 3 lần. Các lệnh nhảy mặc dù rất tốn rất ít chi phí nhưng với số lượng nhiều có thể làm chậm tốc độ thực thi của chương trình khá rõ ràng.

9. Sử dụng cấu trúc thay cho lớp:


Đối với những kiểu dữ liệu đơn giản và không cần tham chiếu, bạn nên sử dụng cấu trúc (structure) thay cho lớp (class), điều này sẽ giúp giảm bớt chi phí tài nguyên tiêu hao cho chương trình của bạn. Tuy nhiên bạn cũng cần cân nhắc dựa vào yêu cầu của dự án trước khi quyết định dùng struct hay class cho phù hợp.

Giả sử bạn có một lớp và một cấu trúc có cùng thành viên và thuộc tính đơn giản như sau:
class MyClass
{
private int value;
public int Value
{
get { return this.value; }
set { this.value = value; }
}
}
struct MyStruct
{
private int value;
public int Value
{
get { return this.value; }
set { this.value = value; }
}
}
Hai đoạn mã cũng thực hiện cùng một nhiệm vụ:

Đoạn mã 1:
for (int i = 0; i < 1000000; i++)
{
MyClass myClass = new MyClass();
myClass.Value = 1;
}
Đoạn mã 2:
for (int i = 0; i < 1000000; i++)
{
MyStruct myStruct= new MyStruct();
myStruct.Value = 1;
}
Khi chạy thử bạn có thể nhận thấy đoạn mã thứ hai chạy nhanh hơn khoảng trên 4 lần so với đoạn mã thứ nhất. Lý do chính khá đơn giản là cấu trúc đơn giản và có ít tính năng hơn lớp, vì thế như đã nói trước, bạn chỉ nên sử dụng đối với những kiểu dữ liệu đơn giản, thành viên của nó thường là những kiểu dữ liệu đã được xây dựng sẵn.

10.  Sử dụng tập hợp (collection) có định kiểu:


Mục đích của việc này là giúp hạn chế tối đa việc ép kiểu khi bạn thao tác với các tập hợp này. Thường thì chúng ta chỉ chứa một loại đối tượng trong một tập hợp, vì thế thay vì dùng lớp ArrayList để lưu trữ, bạn hãy thử dùng List<T>. Các tập hợp có định kiểu được cung cấp trong namespace System.Collections.Generic.

11.  Mảng (array) và tập hợp  (collection) – tốc độ hay sự linh hoạt:


Bạn có thể đã biết rằng việc sử dụng mảng sẽ giúp truy xuất nhanh hơn tuy hơn lại không linh hoạt bằng tập hợp. Về mặt lý thuyết, tập hợp giống như một danh sách liên kết (linked list) với khả năng cấp phát động để cung cấp các thao tác thêm, xóa theo vị trí mà mảng không hỗ trợ. Trong một số trường hợp, nếu không cần đến các chức năng này của tập hợp, bạn nên sử dụng mảng để tối ưu cho chương trình của mình.

Đoạn mã 1:
List<int> list = new List<int>();
for (int i = 0; i < 1000000; i++)
{
list.Add(1);
}
Đoạn mã 2:
int[] arr = new int[1000000];
for (int i = 0; i < arr.Length; i++)
{
arr[i] = 1;
}


Tốc độ thực thi của đoạn mã thứ hai có thể nhanh hơn 4-6 lần đoạn mã một. Tuy nhiên nếu bạn sử dụng ArrayList trong đoạn mã một, sự khác biệt này có tăng lên đến 15 lần. Một lần nữa bạn thấy sự cải thiện đáng kể khi sử dụng tập hợp có định kiểu.

Trên đây chỉ là một vài kinh nghiệm cơ bản, bạn có thể tự tìm hiểu và khám phá thêm trong quá trình thực hành.


[C#] Loại bỏ dấu tiếng việt C#

Đoạn codesnippet dưới đây cho phép chuyển chuỗi văn bản tiếng việt về dạng không dấu sử dụng C# kết hợp với Regex.
        public string Change_AV(string ip_str_change)
        {
            Regex v_reg_regex = new Regex("\\p{IsCombiningDiacriticalMarks}+");
            string v_str_FormD = p_str_change.Normalize(NormalizationForm.FormD);
            return v_reg_regex.Replace(v_str_FormD, String.Empty)
            .Replace('\u0111', 'd').Replace('\u0110', 'D');
        } 


10/27/13

String Format trong C#

Trong khi lập trình, chúng ta thường gặp phải rất nhiều trường hợp cần định dạng lại một chuỗi như chuỗi số, chuỗi ngày tháng sao cho đúng yêu cầu.

Ví dụ: định dạng ngày tháng: MM/dd/yyyy ta muốn chuyển sang dd/MM/yyyy cho thuần Việt.

Sau đâu là các kiểu chuyển đổi, định dạng chuỗi trong C#

Định dạng số chữ số sau dấu chấm trong số thập phân
String.Format("{0:0.00}", 123.4567); // "123.46"
String.Format("{0:0.00}", 123.4); // "123.40"
String.Format("{0:0.00}", 123.0); // "123.00"
Định dạng số chữ số trước dấu chấm trong số thập phân
String.Format("{0:00.0}", 123.4567); // "123.5"
String.Format("{0:00.0}", 23.4567); // "23.5"
String.Format("{0:00.0}", 3.4567); // "03.5"
String.Format("{0:00.0}", -3.4567); // "-03.5"
Thêm dấu ngăn cách hàng nghìn
String.Format("{0:0,0.0}", 12345.67); // "12,345.7"
String.Format("{0:0,0}", 12345.67); // "12,346"
Thêm số 0 vào trước số

String.Format("{0:00000}", 15); // "00015"
String.Format("{0:00000}", -15); // "-00015"
Căn số sang phải hay trái dựa vào kích cỡ ta cung cấp
String.Format("{0,5}", 15); // " 15"String.Format("{0,-5}", 15); // "15 "String.Format("{0,5:000}", 15); // " 015"String.Format("{0,-5:000}", 15); // "015 "'
Định dạng ngày tháng
String.Format("{0:M/d/yyyy}", dt); // "3/9/2008"
String.Format("{0:MM/dd/yyyy}", dt); // "03/09/2008"
String.Format("{0:t}", dt); // "4:05 PM" ShortTime
String.Format("{0:d}", dt); // "3/9/2008" ShortDate
String.Format("{0:T}", dt); // "4:05:07 PM" LongTime
String.Format("{0:D}", dt); // "Sunday, March 09, 2008" LongDate
String.Format("{0:f}", dt); // "Sunday, March 09, 2008 4:05 PM" LongDate+ShortTime
String.Format("{0:F}", dt); // "Sunday, March 09, 2008 4:05:07 PM" FullDateTime
String.Format("{0:g}", dt); // "3/9/2008 4:05 PM" ShortDate+ShortTime
String.Format("{0:G}", dt); // "3/9/2008 4:05:07 PM" ShortDate+LongTime
String.Format("{0:m}", dt); // "March 09" MonthDay
String.Format("{0:y}", dt); // "March, 2008" YearMonth
String.Format("{0:r}", dt); // "Sun, 09 Mar 2008 16:05:07 GMT" RFC1123String.Format("{0:s}", dt); // "2008-03-09T16:05:07" SortableDateTime
Hi vọng với những ví dụ trên, các bạn có thể định dạng các chuỗi hiển thị lên ứng dụng của mình một cách khoa học nhất.

Import và Export Excel trong .NET

Trong bài viết hôm này, mình sẽ hướng dẫn các bạn cách Import excel từ một file có sẵn vào csdl và export dữ liệu từ csdl ra 1 file excel.
Đây là thư viện đã xây dựng sẵn, các bạn cứ thế mà dùng. Chỉ cần Add Reference đến thư viện này là được.
Trong thư viện có 2 phương thức đó là:
public DataTable ImportExcel(string strFileName,string strQuery)
Có tác dụng Import file Excel theo đường dẫn strFilename với câu truy vấn sql strQuery vào 1 DataTable.
Ví dụ:
DataTable dt=ImportExcel("D:\\123.xls","Select * from Sheet1");
Tiếp theo là
public void ExportToExcel(DataSet source,string filename)
Có tác dụng là Export dữ liệu từ DataSet source ra file Excel và lưu trữ ở đường dẫn filename
Ví dụ:
ExportToExcel(ds,"C:\\123.xls");
Đơn giản vậy thôi. Chúc các bạn thành công.

[SQL Server] Script backup toàn bộ database

Máy chủ của bạn có khoảng 100 database. Bạn muốn backup toàn bộ số database này ? Bạn hoàn toàn có thể sử dụng tool backup của SQL Server Management Studio nhưng sẽ rất mất nhiều thời gian cũng như chán nản. Thay vào đó bạn có thể sử dụng T-SQL là một phương pháp đơn giản và nhanh hơn rất nhiều


DECLARE @name VARCHAR(50) -- database name 
DECLARE @path VARCHAR(256) -- path for backup files 
DECLARE @fileName VARCHAR(256) -- filename for backup 
DECLARE @fileDate VARCHAR(20) -- used for file name
-- specify database backup directory
SET @path = 'C:\Backup\'
-- specify filename format
SELECT @fileDate = CONVERT(VARCHAR(20),GETDATE(),112) 
DECLARE db_cursor CURSOR FOR 
SELECT name
FROM master.dbo.sysdatabases
WHERE name NOT IN ('master','model','msdb','tempdb')  -- exclude these databases
OPEN db_cursor  
FETCH NEXT FROM db_cursor INTO @name  
WHILE @@FETCH_STATUS = 0  
BEGIN  
       SET @fileName = @path + @name + '_' + @fileDate + '.BAK' 
       BACKUP DATABASE @name TO DISK = @fileName 
       FETCH NEXT FROM db_cursor INTO @name  
END  
CLOSE db_cursor  
DEALLOCATE db_cursor
Nếu bạn muốn thêm thời gian vào file backup bạn sẽ thay thế đoạn script sau:


SELECT @fileDate = CONVERT(VARCHAR(20),GETDATE(),112)
bằng đoạn


SELECT @fileDate = CONVERT(VARCHAR(20),GETDATE(),112) +REPLACE(CONVERT(VARCHAR(20),GETDATE(),108),':','')

Chúc các bạn thành công