65.9K
CodeProject 正在变化。 阅读更多。
Home

使用部分方法在 Entity Framework 中执行验证的初学者教程

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.70/5 (8投票s)

2012 年 10 月 6 日

CPOL

4分钟阅读

viewsIcon

36750

downloadIcon

805

本文介绍了在使用 Entity Framework 时执行验证的方法。我们将了解实体如何通过部分方法实现验证。

引言

本文介绍了在使用 Entity Framework 时执行验证的方法。我们将了解实体如何通过部分方法实现验证。我们还将简要回顾 C# 中部分类和部分方法的概念。

背景

很多时候,我们需要在向数据库插入或更新数据时执行业务规则验证。在使用经典的 ADO.NET 时,这可以在数据访问层业务逻辑层中轻松完成。

如果我们在数据访问层中使用 Entity Framework,那么在处理实体时,如何确保业务规则验证得到遵循呢?Entity Framework 为我们提供了一种漂亮的验证机制。这是通过使用部分方法来实现的。让我们看看如何使用部分方法,并在 Entity Framework 中执行验证。

使用代码

了解部分类和部分方法。

C# 提供了使用部分方法将 class 定义分散到多个文件中的灵活性。这在 IDE 生成的代码与自定义代码结合使用时尤其有用。我们可以通过使用 partial 关键字将类定义分散到多个位置。以下代码展示了如何在 C# 中定义部分类。

// Assume this is the class definition we are not supposed to touch
partial class Person
{
    string m_Name;
    string m_Designation;

    public string Name
    {
        get
        {
            return m_Name;
        }
    }

    public string Designation
    {
        get
        {
            return m_Designation;
        }
        set
        {            
            m_Designation = value;
        }
    }

    public Person(string name, string designation)
    {
        m_Name = name;
        m_Designation = designation;
    }
}

// We can still add functions to this class by having another partial class
// with same name. this will effectively create a single class with all functions.
partial class Person
{
    public override string ToString()
    {
        return string.Format("Name = {0}, Designation = {1}", m_Name, m_Designation);
    }   
}

部分方法的概念将这种方法向前推进了一步。它使我有可能在一个部分类中创建方法的声明,而在另一个部分类中提供定义。所以,让我们在上面代码片段的第一个部分 Person 类中添加一个部分方法。

partial class Person
{
    string m_Name;
    string m_Designation;

    public string Name
    {
        get
        {
            return m_Name;
        }
    }

    public string Designation
    {
        get
        {
            return m_Designation;
        }
        set
        {
            OnDesignationChanging(value);
            m_Designation = value;
        }
    }

    public Person(string name, string designation)
    {
        m_Name = name;
        m_Designation = designation;
    }

    partial void OnDesignationChanging(string value);
}

现在我们所做的是,我们在部分类中创建了一个部分方法 OnDesignationChanging,并且每当有人从外部设置 Designation 时,我都会调用这个方法。目前,由于没有函数的定义,函数调用将被简单地忽略。

所以,让我们在另一个部分类中提供这个函数的定义,这样每当调用函数时,我们提供的定义就会执行。

partial class Person
{
    public override string ToString()
    {
        return string.Format("Name = {0}, Designation = {1}", m_Name, m_Designation);
    }

    partial void OnDesignationChanging(string value)
    {
        Console.WriteLine("{0}'s designation has been changed to: {1}", m_Name, value);
    }
}

现在让我们看看在第二个部分类中定义的这个函数如何与具有部分方法声明的现有部分类协同工作。

static void Main(string[] args)
{
    Person p = new Person("Rahul", "Software Developer");

    // Lets print it
    Console.WriteLine("Person before promotion");
    Console.WriteLine(p.ToString());

    //Lets now try to change the designation
    p.Designation = "Project Manager";

    // Lets print it
    Console.WriteLine("Person after promotion");
    Console.WriteLine(p.ToString());
}

因此,我们现在可以肯定地说,部分方法可以用作现有类的钩子。原始类可以定义一个部分方法,我们可以通过实现这个部分方法来挂接我们的功能。

Entity Framework CRUD 操作回顾

让我们开始创建一个小型应用程序,使用 Entity Framework 执行基本的 CRUD 操作。我们将定义一个小数据库,其中包含一个用于存储 Bike 和制造商名称数据的表。


然后,我们将有一个包含添加了 ADO.NET 实体的类库,这将允许我们访问此数据库。最终的应用程序将是一个控制台应用程序,它将对该表执行基本的 CRUD 操作。

注意:请参阅随附的示例项目了解详情。此处仅包含 CRUD 操作的代码片段。

// Select
using (MotorBikeShopDbEntities db = new MotorBikeShopDbEntities())
{
    List bikes = db.Bikes.ToList();                                
}

// Insert
Bike bike = new Bike();
Console.WriteLine("Enter Bike Name");
bike.BikeName = Console.ReadLine();
Console.WriteLine("Enter Bike Manufacturer");
bike.Manufacturer = Console.ReadLine();
Console.WriteLine("Enter Bike ModelNumber");
bike.Modelumber = Console.ReadLine();

using (MotorBikeShopDbEntities db = new MotorBikeShopDbEntities())
{
    db.Bikes.AddObject(bike);
    db.SaveChanges();
}

// Update
using (MotorBikeShopDbEntities db = new MotorBikeShopDbEntities())
{
    Bike bikeToUpdate = db.Bikes.SingleOrDefault(p => p.BikeID == bikeID);
    if (bikeToUpdate != null)
    {
        Console.WriteLine("Enter new manufacturer name.");
        string newManf = Console.ReadLine();

        bikeToUpdate.Manufacturer = newManf;
        db.SaveChanges();
    }
}
    
// Delete
using (MotorBikeShopDbEntities db = new MotorBikeShopDbEntities())
{
    Bike bikeToDelete = db.Bikes.SingleOrDefault(p => p.BikeID == bikeID);
    if (bikeToDelete != null)
    {
        db.DeleteObject(bikeToDelete);
    }
}

让我们看看这段代码的实际运行效果


重要:示例项目包含完整的 Entity Framework 数据访问层和完整的控制台应用程序。要运行示例应用程序,只需创建上面显示的数据库和表,更改控制台应用程序 App.config 中的配置文件字符串,应用程序即可运行。

注意:要详细了解 Entity Framework 的 CRUD 操作,请参阅: An Introduction to Entity-Framework for Absolute Beginners 

使用 Entity Framework 进行验证 

现在,如果我们查看生成的实体,我们可以看到实体类提供了 OnChangingOnChanged 等部分方法。


我们需要做的就是创建一个与实体类同名的部分类,并在该类中实现这个部分方法。在这个部分方法中,我们可以编写自定义验证逻辑,根据业务规则进行验证。

假设我们想执行一个验证,即用户不应该能够添加包含数字的制造商名称。为此,我们需要实现 OnManufacturerChanging 函数。所以,让我们添加一个与我们的实体同名的部分类,即 Bike,然后实现这个函数。

public partial class Bike : EntityObject    
{
    partial void OnManufacturerChanging(global::System.String value)
    {
        if (Regex.IsMatch(value, @"^[a-zA-Z]+$", RegexOptions.None) == false)
        {
            throw new Exception("Manufacturer name should only contain alphabets");
        }
    }
}

现在,每当我们尝试添加或更新包含数字的制造商名称的数据时,都会抛出异常,我们可以在应用程序中处理它,然后通知用户。


这样,我们就可以在实体更改或已更改时设置钩子。这为在使用 Entity Framework 时处理验证场景提供了一种非常干净的方式。

注意:要运行该解决方案,请创建上面显示的表,然后在 App.config 文件中的 ConnectionString 中更改数据库路径。

关注点

我们尝试了解了部分方法和部分函数,以及部分函数如何用作类的钩子。我们看到了如何使用 Entity Framework 提供的部分函数来执行自定义验证。

历史

  • 2012年10月06日:初版。
© . All rights reserved.