LINQ to SQL活学活用(4):监视你的一举一动

改进

这也可以运用GoF23中的观察者模式,让多个观察者对象(对象创建、修改)同时监听某一个主题对象(这里就是数据访问对象Customer)。这个主题对象Customer在状态发生变化时,会通知所有观察者对象(对象创建、修改),使它们能够自动更新自己,就可以实现监视Customer的一举一动了。

我们来实现这个功能,先看看这篇完成的整体架构。

数据访问层

1.数据访问基类

我们为整个数据访问对象定义一个公共基类,首先定义定义数据访问基类接口,让抽象数据访问基类实现这个接口,这个基类用于存放数据访问对象共有的属性,设置为抽象的。在我们的系统中,并非只有Customer这个数据访问对象,将来肯定要增加另外很多的了,这样如果将来增加另外的数据访问对象,只需继承这个基类重写属性即可。

Step1:定义数据访问基类接口:

public interface IDataAccessBase
{
    int Id { get; set; }
    DateTime CreatedDate { get; set; }
    DateTime ModifiedDate { get; set; }
    string CreatedBy { get; set; }
    string ModifiedBy { get; set; }
}

Step2:定义抽象的数据访问基类实现这个接口:针对抽象编程,减少了与具体类的耦合。

public abstract class DataAccessBase : IDataAccessBase
{
    public abstract int Id { get; set; }
    public abstract DateTime CreatedDate { get; set; }
    public abstract DateTime ModifiedDate { get; set; }
    public abstract string CreatedBy { get; set; }
    public abstract string ModifiedBy { get; set; }
}

2.数据访问对象Customer

既然在数据访问基类中定义了抽象的Id、CreatedBy、CreatedDate、ModifiedBy、ModifiedDate等属性,那么我们改修改数据访问对象Customer的属性了,看看截图

修改Customer类,增加了CreatedBy、CreatedDate、ModifiedBy、ModifiedDate属性,并把CustomerId换为Id,需要特别声明的是,这些字段属性的修饰符必须修改为重写“override"。

修改数据访问对象Customer接口,继承数据访问基类接口IDataAccessBase。

public interface ICustomer : IDataAccessBase
{
    int Id { get; set; }
    string FirstName { get; set; }
    string LastName { get; set; }
}

修改数据访问对象Customer分部类,继承数据访问基类接口IDataAccessBase和数据访问对象Customer接口,这时数据访问对象Customer一共七个属性了。

public partial class Customer : DataAccessBase, ICustomer
{

}

数据访问对象Customer修改完成,如果我们要添加另外的数据访问对象,很容易的去扩展,也很容易的重写自己的属性。

3.数据访问对象DataContext

定义数据访问对象DataContext分部类DataAccessEntitiesDataContext,用于存放一些操作对象的公共方法,例如是谁创建数据的?何时创建这个数据的?是谁修改数据的?何时修改的?我们可以重写LINQ to SQL内置的方法实现。

DataContext为每个实体都定义了以下三个分部方法:InsertEntityName()、UpdateEntityName()、DeleteEntityName()。

我们在OR设计器中添加了Customer类,内置定义了三个分部方法,就是:

partial void InsertCustomer(Customer instance);
partial void UpdateCustomer(Customer instance);
partial void DeleteCustomer(Customer instance);

我们就重写上面三个方法实现观察的作用,在重写上面的方法的时需要调用ExecuteDynamicInsert()、ExecuteDynamicUpdate()、ExecuteDynamicDelete()方法。

  • ExecuteDynamicInsert()方法:在插入重写方法中调用,以向LINQ to SQL重新委托生成和执行插入操作的动态SQL的任务。
  • ExecuteDynamicUpdate()方法:在更新重写方法中调用,以向LINQ to SQL重新委托生成和执行更新操作的动态SQL的任务。
  • ExecuteDynamicDelete()方法:在删除重写方法中调用,以向LINQ to SQL重新委托生成和执行删除操作的动态SQL的任务。

我们重写新建一个分部类DataAccessEntitiesDataContext.cs,在这个分部类中重写上面三个分部方法的具体实现。这篇我只需重写InsertCustomer方法(插入Customer时触发)和UpdateCustomer(更新Customer时触发)两个方法,为了程序可以复用,我们把插入数据访问对象时、修改数据访问对象时记录信息封装成两个方法实现。

Step1:创建数据访问对象实现记录创建者(这里获取机器当前用户名)和创建时间,由于修改字段不为空,这里默认使用创建时的信息。

private void InsertDataAccessBase(DataAccessBase instance)
{
    //创建对象时(记录创建者和时间)
    instance.CreatedBy = WindowsIdentity.GetCurrent().Name;
    instance.CreatedDate = DateTime.Now;
    //修改对象时(记录修改者和时间)
    instance.ModifiedBy = WindowsIdentity.GetCurrent().Name;
    instance.ModifiedDate = DateTime.Now;
    //在插入重写方法中调用
    //向LINQ to SQL重新委托生成和执行插入操作的动态SQL的任务
    ExecuteDynamicInsert(instance);
}

Step2:修改数据访问对象实现记录修改者(这里获取机器当前用户名)和修改时间。

private void UpdateDataAccessBase(DataAccessBase instance)
{
    //修改对象时(记录修改者和时间)
    instance.ModifiedBy = WindowsIdentity.GetCurrent().Name;
    instance.ModifiedDate = DateTime.Now;
    ExecuteDynamicUpdate(instance);
}

Step3:重写InsertCustomer()分部方法,调用InsertDataAccessBase()方法即可。

partial void InsertCustomer(Customer instance)
{
    InsertDataAccessBase(instance);
}

Step4:重写UpdateCustomer()分部方法,调用UpdateDataAccessBase()方法即可。

partial void UpdateCustomer(Customer instance)
{
    UpdateDataAccessBase(instance);
}

如果系统又要增加别的数据访问对象的话,如果想实现记录功能只需要调用InsertDataAccessBase()、UpdateDataAccessBase()方法即可,这样就提高了代码的复用性。

4.数据访问对象Customer外观Facade

这个同上一篇一样,无需任何改动,外观Facade依赖关系为Customer接口,这里Customer接口没有变化哦!

单元测试层

以上所有的工作离不开测试!只有通过测试,才可以验证我们程序的正确性!好了,我们开始,既然我们修改了数据访问对象,那么也要修改对应的测试了!

1.创建数据访问对象测试

测试创建数据访问对象,比较创建者是否同机器用户名一致!

[Test]
public void UpdateTest()
{
    ICustomer newCustomer = CreateAndSaveNewCustomer("YJing", "Lee");
    Assert.AreNotEqual(0, newCustomer.Id);
    Assert.AreEqual("YJing", newCustomer.FirstName);

    Assert.AreNotEqual(DateTime.MinValue, newCustomer.CreatedDate);
    Assert.AreNotEqual(DateTime.MinValue, newCustomer.ModifiedDate);
    Assert.IsNotNull(newCustomer.CreatedBy);
    Assert.IsNotNull(newCustomer.ModifiedBy);
    //获取机器当前用户名
    string currentUserName = WindowsIdentity.GetCurrent().Name;
    //比较创建者和修改者
    Assert.AreEqual(currentUserName, newCustomer.CreatedBy);
    Assert.AreEqual(currentUserName, newCustomer.ModifiedBy);
}

测试输出如下

分析一下:先验证数据库是否存在,存在删除,然后重新创建一个新的数据库架构和Customer表,这个表有7个字段。我们向数据库中插入了一条数据,系统自动增加了创建者、创建时间、修改者、修改时间等信息。

2.修改数据访问对象测试

既然我们增加了这个功能,那么我们来测试验证一下:先插入一条数据,然后等待3秒,更新这个对象,看看修改时间是否是我们预期的变化值。

[Test]
public void ModifyCustomerUpdatesModifiedDateTest()
{
    ICustomer tempCustomer = CreateAndSaveNewCustomer("YJing", "Lee");
    DateTime originalLastModifiedDate = tempCustomer.ModifiedDate;

    Thread.Sleep(1500);
    tempCustomer.FirstName = "CnBlogs";
    Facade.UpdateCustomer(tempCustomer);
    Assert.AreNotEqual(originalLastModifiedDate, tempCustomer.ModifiedDate);
}

测试输出如下:

这里省略了创建数据库的过程,第一句插入一个对象,第二句更新一个对象,仔细看看其修改时间是否变化了。

大家再测试下原先的几个测试吧!

结语

这篇通过重写分部方法的方法,来实现了非常酷的功能,时刻监视着数据。也从设计的角度知道针对抽象编程,减少了与具体类的耦合。在这里我们很少和Customer类打交道。

版权声明:本文为博主http://www.zuiniusn.com 原创文章,未经博主允许不得转载。

时间: 2024-11-06 16:26:37

LINQ to SQL活学活用(4):监视你的一举一动的相关文章

pandas pivot_table 活学活用实例教程

pandas pivot_table 活学活用实例教程 导入相关数据分析的库 首先进行commentTime时间进行数据预处理 查看数据类型信息 最简单的透视表 直接敲击该函数,在notebook中可以查看该函数的参数 多个索引列 特定列的统计 规定特定的聚合函数 传入多个聚合函数 传入columns参数 生成的DataFrame可以导出excel或csv文件 修改index中的数据类型,显示完整的索引列 传入fill_value参数,处理缺失值 设添加margins参数,定margin_nam

LINQ to SQL活学活用(3):嗅出“臭味”烟消云散

改进 知道程序的"臭味",我们如何改进呢?想想,通过接口隐藏实体.我们利用接口实现,为Customer创建分部类,创建ICustomer接口,Customer实现ICustomer接口,利用ICustomer接口编写CustomerFacade,根据新的ICustomer接口更新单元测试,而不是上一节的对Customer对象做单元测试,这样客户就不知道数据访问层中具体实现了.这就是我们这一节做的工作. 数据访问层 进一步改进我们的程序,看看数据访问层的类图设计: 1.新建ICustom

LINQ to SQL活学活用(1):这要打破旧观念

程序架构 现在比较经典的架构,看看下面图片. 如何实现 在一个N层应用程序中我们如何使用LINQ to SQL呢?这给刚刚入门的朋友的确是个难题,使用LINQ to SQL就是ORM技术,可以很轻松的实现对数据库记录增删查改操作,但是我们如何去"构建它"才更合理,更科学,更好用?这才是我们真正要学习的,使用面向对象的接口.抽象达到这个目的,面向接口编程就是更好的选择,可以更好的维护和测试. 下面一步一步完成这个程序吧,看到标题了吗?这篇是打破旧观念!看看接下来有什么神秘的地方.首先新建

LINQ to SQL活学活用(2):躲起来别让我看见

改进 这可以考虑到GoF23中的外观模式(Facade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 考虑在数据访问层中建立外观Facade,这样可以为复杂的数据访问方法提供一个简单的类,使得耦合大大降低.增加外观Facade可以只向客户提供一个简单的接口,减少客户与数据访问层之间的依赖,更容易维护和扩展了. 数据访问层 我们就使用这种方法来改进第一篇的程序吧.首先创建一个基类用于存放公共的方法,然后各个数据访问对象(这里只有Custo

活学活用,webapi HTTPBasicAuthorize搭建小型云应用的实践

HTTP使用BASIC认证,WebAPI使用[HTTPBasicAuthorize]标记控制器就是使用了BASIC认证. BASIC认证的缺点HTTP基本认证的目标是提供简单的用户验证功能,其认证过程简单明了,适合于对安全性要求不高的 系统或设备中,如大家所用路由器的配置页面的认证,几乎 都采取了这种方式.其缺点是没有灵活可靠的认证策略,如 无法提供域(domain或realm)认证功能,另外,BASE64的加密强度非常低,可以说仅 能防止sohu的搜索把它搜到了. 当然,HTTP基本认证系统也

活学活用wxPython基础框架

看活活用wxpython这本书,基本框架是这样子的,这里有定义输出,然后打印出整个流程,可以看到是怎样执行的,明天请假了,五一回去玩几天,哈哈,估计假期过来都忘了 import wx import sys class Frame(wx.Frame): def __init__(self,parent,id,title): print "Frame __init__" wx.Frame.__init__(self,parent,id,title) class App(wx.App): d

JVM活学活用——Jvm内存结构

Java内存结构: JVM内存结构主要是有三大块:堆内存.方法区和栈.堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分为三部分,Eden空间.From Survivor空间.To Survivor空间,默认情况下年轻代按照8:1:1的比例来分配: 方法区存储类信息.常量.静态变量等数据,是线程共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆): 栈又分为Java虚拟机栈和本地方法栈,主要用于方法的执行. 在通过一张图来了解如何通过参数来控制各区域的内存大

xhost命令详解(活学活用)

xhost命令是X服务器的访问控制工具,用来控制哪些X客户端能够在X服务器上显示.该命令必须从有显示连接的机器上运行.可以通过使用-host参数,从访问列表中除去一个名称.不要从访问列表中除去当前的名称.如果已经这样做了,请在作出任何更改之前注销系统. xhost 是用来控制X server访问权限的. 通常当你从hostA登陆到hostB上运行hostB上的应用程序时, 做为应用程序来说,hostA是client,但是作为图形来说, 是在hostA上显示的,需要使用hostA的Xserver,

活学活用 screen

新建桌面 screen 列出所有桌面 screen -ls 离开桌面 ctrl-A  D 进入之前的桌面 screen -RR 干掉当前桌面 ctrl-A  :quit 原文地址:https://www.cnblogs.com/yc2019/p/10459406.html