Cập nhật dữ liệu trong Entity Framework – thêm/sửa/xóa entity

    0

    Cập nhật dữ liệu (thêm/sửa/xóa) là yêu cầu bắt buộc của bất kỳ chương trình nào làm việc với cơ sở dữ liệu. Trong Entity Framework, việc cập nhật dữ liệu rất đơn giản và không yêu cầu bạn phải viết các truy vấn SQL. Tất cả đều được Entity Framework hỗ trợ tự động. Bài học này sẽ hướng dẫn bạn cách thức thực hiện các thao tác thêm/sửa/xóa dữ liệu cơ bản.

    Vấn đề cập nhật dữ liệu trong Entity Framework

    Các thao tác cập nhật dữ liệu cơ bản bao gồm: Thêm mới (Created), Chỉnh sửa (Update), Xóa bỏ (Delete). Nhóm chức năng này thường được gọi tắt là CUD (trong tổng thể 4 chức năng CRUD với dữ liệu).

    Entity Framework hỗ trợ hầu hết các thao tác liên quan đến cập nhật dữ liệu khiến việc cập nhật dữ liệu trở nên rất đơn giản:

    (1) Bạn không cần tự mình viết các truy vấn SQL như INSERT, UPDATE, DELETE;

    (2) Entity Framework có khả năng theo dõi trạng thái của tất cả các object (change tracking) và sinh ra truy vấn phù hợp;

    (3) Quá trình lưu trữ dữ liệu được thực hiện theo một quy trình (pipeline) phức tạp để đảm bảo an toàn cho việc cập nhật dữ liệu nhưng bạn không cần can thiệp vào nó;

    (4) Entity Framework hỗ trợ bạn quản lý quan hệ giữa các entity object giúp đơn giản hóa làm việc với dữ liệu quan hệ.

    Tuy rằng Entity Framework đã hỗ trợ tất cả, bạn cần hiểu quá trình làm việc của nó để khai thác đầy đủ và chính xác các tính năng cập nhật dữ liệu phục vụ cho chương trình.

    Trong bài học này chúng ta sẽ bắt đầu học cách cập nhật dữ liệu trên từng entity đơn lẻ. Trong các bài học sau chúng ta sẽ lần lượt học các tình huống phức tạp hơn như xử lý quan hệ, làm việc với hệ thống theo dõi thay đổi của Entity Framework.

    Để thực hiện các ví dụ trong bài học này chúng ta sử dụng solution đã tạo ở bài học Thực hành xây dựng EDM.
    Bạn hãy tạo thêm project P04_UpdateSingle trong solution và thực hiện các cài đặt cần thiết (như đã làm trong các bài học trước): cài đặt Entity Framework, tham chiếu sang Models và DataAccess, bổ sung connectionStrings trong App.config.
    Bạn có thể tải mã nguồn solution theo link ở cuối bài và mở project P04_UpdateSingle.

    Thêm entity mới

    Hãy cùng thực hiện một ví dụ:

    using System;
    using static System.Console;
    using Models;
    using DataAccess;
    
    namespace P04_UpdateSingle
    {
        class Program
        {
            static void Main(string[] args)
            {
                using (var context = new UniversityContext())
                {
                    Title = "CRUD Operations";
                    Adding(context);
                    PrintAllCourses(context);
                }
    
                ReadKey();
            }
    
            static void PrintAllCourses(UniversityContext context)
            {
                ForegroundColor = ConsoleColor.Magenta;
                WriteLine("### COURSES IN HOGWARTS ###");
                foreach (var c in context.Courses)
                {
                    ForegroundColor = ConsoleColor.Green;
                    WriteLine($"# {c.Name} ({c.Credit} credits)");
                    ResetColor();
                    if (!string.IsNullOrEmpty(c.Description)) WriteLine($" -> {c.Description}");
                }
            }
    
            static void Adding(UniversityContext context)
            {
                var course = new Course
                {
                    Name = "Magical Theory",
                    Credit = 3,
                    Description = "Covers magic from a purely theoretical view"
                };
                context.Courses.Add(course);
                context.SaveChanges();
            }
        }
    }

    Trong ví dụ trên bạn đã tạo ra một khóa học mới “Magical Theory” 3 tín chỉ và lưu thay đổi vào cơ sở dữ liệu. Kết quả chạy chương trình như sau:

    thêm dữ liệu trong entity framework

    Như bạn đã thấy, quy trình thêm dữ liệu rất đơn giản:

    • (1) tạo một object mới;
    • (2) đăng ký nó với DbSet tương ứng qua phương thức Add;
    • (3) gọi phương thức SaveChanges.

    Phương thức SaveChanges sẽ kích hoạt quy trình lưu dữ liệu vào cơ sở dữ liệu. Trong tình huống này, một truy vấn INSERT tới bảng tương ứng sẽ được Entity Framework sinh ra và thực thi.

    Khi thêm một một entity bạn cần lưu ý một số điểm sau:

    (1) Object bạn tạo ra không cần đến giá trị Id. Giá trị Id sẽ được cơ sở dữ liệu tự động sinh ra. Vì lý do này, khi xây dựng model tương ứng người ta thường đặt Set accessor của Id là private.

    (2) Khi thực hiện truy vấn INSERT thành công, Id của bản ghi mới được tự động sinh ra, Entity Framework đồng thời tự sinh ra thêm một truy vấn nữa để lấy giá trị Id mới này và gán trở lại cho object.

    (3) Phương thức SaveChanges sẽ trả lại số lượng bản chịu tác động. Trong trường hợp trên chúng ta thêm một object. Nếu thành công thì SaveChanges sẽ trả lại giá trị 1.

    Chỉnh sửa entity

    Chúng ta cùng làm một ví dụ:

    static void Updating(UniversityContext context)
    {
        var course = context.Courses.FirstOrDefault(c => c.Name.Contains("Magic"));
        if (course != null)
        {
            course.Description = "The most awesome magic course in Hogwarts";
            context.SaveChanges();
        }
        else
            WriteLine("Course not found");
    }
    static void Main(string[] args)
    {
        using (var context = new UniversityContext())
        {
            Title = "CRUD Operations";        
            Updating(context);        
            PrintAllCourses(context);
        }
    
        ReadKey();
    }
    cập nhật dữ liệu trong entity framework

    Trong ví dụ trên bạn tìm và tải khóa học đầu tiên có chứa từ “Magic”, sau đó gán giá trị mới cho trường Description. Cuối cùng bạn gọi SaveChanges để lưu lại thay đổi vào cơ sở dữ liệu.

    Khi chỉnh sửa entity bạn gặp hai tình huống: (1) tải một entity từ cơ sở dữ liệu vào và cập nhật nó; (2) sửa một entity mới (bạn chưa phát lệnh SaveChanges để lưu lại). Ví dụ ở trên là của tình huống 1.

    Đối với tình huống 1, quy trình như sau: (1) tải object từ cơ sở dữ liệu; (2) thực hiện những thay đổi cần thiết bằng cách gán giá trị mới cho property tương ứng; (3) gọi lệnh SaveChanges(). Khi này Entity Framework sẽ tự động sinh ra truy vấn UPDATE sử dung Id của object với các giá trị đã thay đổi.

    Đối với tình huống 2, do object chưa được lưu vào cơ sở dữ liệu, những gì bạn thay đổi trên object không tạo ra truy vấn UPDATE. Entity Framework vẫn chỉ tạo ra truy vấn INSERT như đối với trường hợp thêm object mới.

    Xóa bỏ entity

    Hãy cùng thực hiện một ví dụ:

    static void Deleting(UniversityContext context)
    {
        var course = context.Courses.FirstOrDefault(c => c.Name.Contains("Potions"));
        if (course != null)
        {
            context.Courses.Remove(course);
            context.SaveChanges();
        }
        else
            WriteLine("Course not found");
    }

    Trong đoạn code trên bạn tìm kiếm khóa học Potions và xóa bỏ nó.

    Để xóa bỏ một entity bạn sử dụng phương thức Remove của DbSet. Có thể sử dụng Remove với (1) entity tải từ cơ sở dữ liệu và (2) entity vừa thêm mới (nhưng chưa lưu). Để lưu kết quả lại, bạn gọi SaveChanges.

    Đối với trường hợp thứ nhất, phương thức Remove sẽ đánh dấu xóa cho entity đó (nhưng không xóa ngay). Khi bạn gọi SaveChanges, truy vấn DELETE sẽ được tạo ra cho object tương ứng để thực sự xóa nó ra khỏi cơ sở dữ liệu.

    Đối với trường hợp thứ hai, Remove sẽ bỏ nó ra khỏi danh sách object mới đồng thời chấm dứt theo dõi trạng thái của nó. Không có hoạt động nào liên quan đến cơ sở dữ liệu trong trường hợp này.

    Khác biệt với Update, khi xóa dữ liệu có sẵn bạn không nhất thiết phải tải nó vào chương trình như chúng ta đã làm.

    Ví dụ, khi bạn biết chính xác Id của object mình cần xóa và nó chưa được tải vào chương trình, bạn hoàn toàn có thể xóa bỏ nó mà không cần tải object đó vào chương trình. Tình huống này thường diễn ra ở những chương trình hoạt động kiểu disconnected như ứng dụng web hoặc ứng dụng client/server sử dụng web api.

    Entity Framework có loại kỹ thuật cho phép bạn thực hiện thao tác xóa mà không cần tải dữ liệu sử dụng một object đặc biệt gọi là stub. Stub là một object “đại diện” cho object thực (trong cơ sở dữ liệu) bạn cần xóa nhưng không chứa đầy đủ thông tin của object thực. Stub chỉ yêu cầu duy nhất giá trị Id của object thực cần xóa.

    Hãy cùng thực hiện đoạn code sau:

    static void DeletingStub(UniversityContext context)
    {
        // lưu ý mở bảng dữ liệu Courses từ SSMS hoặc Server Explorer để lấy giá trị Id của course cần xóa
        var stub = new Course { Id = 20 };
        context.Courses.Attach(stub);
        context.Courses.Remove(stub);
        context.SaveChanges();
    }

    Quy trình xóa dữ liệu sử dụng stub như sau:

    • (1) Tạo stub với giá trị Id của object cần xóa;
    • (2) Sử dụng phương thức Attach để đăng ký stub với DbSet tương ứng;
    • (3) Gọi phương thức Remove đối với stub;
    • (4) Gọi phương thức SaveChanges để lưu kết quả.

    Bạn sẽ gặp lại Attach và học kỹ hơn về nó trong một bài học khác.

    Lưu ý rằng, nếu object thực đã được tải vào chương trình, bạn sẽ không sử dụng được stub nữa. Dĩ nhiên, nếu đã có object thực thì cần gì phải dùng kỹ thuật này.

    Thực hiện nhiều cập nhật

    Ở trên chúng ta đã xem xét các kỹ thuật cập nhật Create-Update-Delete riêng rẽ. Trên thực tế khi chương trình hoạt động bạn thường xuyên phải thực hiện nhiều thác tác cập nhật khác nhau.

    Ngoài ra bạn cũng thường xuyên cần đến các tính năng như (1) thêm nhiều object cùng lúc, (2) xóa nhiều object cùng lúc. Riêng đối với cập nhật bạn bắt buộc phải thực hiện lần lượt cho từng object.

    Hãy cùng thực hiện một ví dụ:

    static void MultiCUD(UniversityContext context)
    {
        // thêm khóa học mới
        var ghoulStudies = new Course
        {
            Name = "Ghoul Studies",
            Credit = 4,
            Description = "Learn about ghouls like poltergeists, vampires, Veela"
        };
        context.Courses.Add(ghoulStudies);
    
        // cập nhật số tín chỉ
        ghoulStudies.Credit = 5;
    
        // thêm đồng thời nhiều khóa học
        var courses = new Course[]
        {
            new Course{Name = "Xylomancy", Credit = 2, Description = ""},
            new Course{Name = "Ancient Studies", Credit = 3, Description = ""},
            new Course{Name = "Apparition", Credit = 3, Description = ""},
        };
        context.Courses.AddRange(courses);
    
        // lấy tất cả các khóa học chứa từ khóa Magic
        var magicCourses = context.Courses.Where(c => c.Name.Contains("Magic"));
        foreach (var c in magicCourses)
        {
            c.Credit = 6;
            c.Description = "Taught by the most powerfull Albus Dumbledore";
        }
    
        // tìm và xóa tất cả cá khóa học có chứa từ khóa Muggles
        var muggleCourses = context.Courses.Where(c => c.Name.Contains("Muggles"));
        context.Courses.RemoveRange(muggleCourses);
    
        context.SaveChanges();
    }
    thực thi nhiều lệnh CUD

    Như bạn đã thấy, để thêm nhiều object cùng lúc bạn sử dụng phương thức AddRange của DbSet. Để xóa nhiều object, bạn có thể sử dụng phương thức RemoveRange.

    Bạn cũng để ý thấy rằng, chúng ta chỉ gọi SaveChanges một lần duy nhất ở cuối phương thức chứ không gọi sau mỗi thay đổi.

    Một quy tắc bạn cần ghi nhớ: gọi phương thức SaveChanges ít nhất có thể. Hay cũng có thể giải thích theo cách khác: thực hiện tất cả các cập nhật có thể trước khi gọi SaveChanges. Tuyệt đối không gọi SaveChanges trong vòng lặp, cũng không gọi SaveChanges ngay sau mỗi thao tác cập nhật.

    Sở dĩ phải hạn chế gọi SaveChanges là vì mỗi khi gọi phương thức này, Entity Framework phải phát đi truy vấn tới cơ sở dữ liệu. Như bạn đã biết, thực thi mỗi truy vấn trên SQL Server đều mất nhiều thời gian so với xử lý trong bộ nhớ của chương trình.

    Bạn có thể băn khoăn, nếu không gọi ngay thì sao Entity Framework biết phải làm gì. Bạn không cần lo lắng hộ.

    Entity Framework có cơ chế Change Tracking giúp theo dõi tất cả những gì bạn thực hiện trên object của DbSet. Nói cách khác, mỗi khi bạn thực hiện thay đổi gì trên object (thêm mới, sửa đổi, xóa bỏ), cơ chế này sẽ lưu lại những thay đổi đó thông qua đánh dấu trạng thái của mỗi object.

    Khi bạn gọi SaveChanges, Entity Framework sẽ kiểm tra trạng thái của tất cả các object trong DbSet nó theo dõi và tự động sinh ra truy vấn SQL phù hợp cho từng thay đổi.

    Chúng ta sẽ quay lại xem xét kỹ cơ chế Change Tracking trong một bài học riêng.

    Kết luận

    Trong bài học này chúng ta đã học các kỹ thuật cập nhật dữ liệu cơ bản trong Entity Framework. Nhìn chung các kỹ thuật này rất đơn giản, giống như bạn xử lý một danh sách thông thường. Khác biệt ở chỗ bạn cần gọi phương thức SaveChanges để lưu những cập nhật này trở lại cơ sở dữ liệu.

    Trong những bài học tiếp theo chúng ta sẽ xem xét những tình huống phức tạp hơn như cập nhật dữ liệu quan hệ và khai thác tính năng theo dõi object (change tracking) của Entity Framework.

    Bạn có thể tải mã nguồn solution từ link dưới đây để tham khảo.

    Nếu có thắc mắc hoặc cần trao đổi thêm, mời bạn viết trong phần Bình luận ở cuối trang. Nếu cần trao đổi riêng, hãy gửi email hoặc nhắn tin qua form liên hệ. Nếu bài viết hữu ích với bạn, hãy giúp chúng tôi chia sẻ tới mọi người. Cảm ơn bạn!

    Bình luận

    avatar
      Đăng ký theo dõi  
    Thông báo về