我的KT库之----数据对象

简介:

了解或者认识KT:

http://www.cnblogs.com/kingthy/archive/2011/08/08/2130973.html

在项目中如何使用KT?

KT是一个库,所以将KT的dll文件引用到您的项目上即可使用KT里的函数功能。

本节将介绍大家认识KT库里的数据对象(DbObject)。KT里的数据对象是KT简易ORM框架里的一个对象角色,它存放于在“KT.Framework“下,当你已在你的项目里引用了KT库后,则写下以下代码就可以使用数据对象了。

using KT.Framework;

什么是数据对象

数据对象可用于简单处理数据的存储与交互,如将数据进行实体化处理。KT里的数据对象DbObject对象类似于一个“字典”对象,添加到数据对象里的数据都被放入内部的一个“槽”里进行维护,如以下的代码:

DbObject obj = new DbObject();
obj["name"] = "张三";
obj["age"] = 23;
Console.WriteLine("姓名:{0}", obj["name"]);
Console.WriteLine("年龄:{0}", obj["age"]);

//或者通过SetData/GetData<T>方法设置/获取数据
obj.SetData("name", "李四");
Console.WriteLine("姓名:{0}", obj.GetData<string>("name"));
Console.WriteLine("年龄:{0}", obj.GetData<int>("age"));
Console.Read();

 

扩展数据对象

虽可以直接将数据对象当作一个字典对象使用,但很多场合下我们却是需要将数据进行实体化处理,所以我们需要将数据对象进行扩展。如以下的代码示例:

/// <summary>
/// 用户对象
/// </summary>
public class DbUser : DbObject
{
    public User()
    {

    }
    /// <summary>
    /// 姓名
    /// </summary>
    public string Name
    {
        get
        {
            return this.GetData<string>("Name", null);
        }
        set
        {
            this["Name"] = value;
        }
    }
    /// <summary>
    /// 年龄
    /// </summary>
    public int Age
    {
        get
        {
            return this.GetData<int>("Age", 0);
        }
        set
        {
            this["Age"] = value;
        }
    }
}

 

这样扩展后,我们的数据对象User就是强类型的了,如下面的使用代码示例:

DbUser user = new DbUser();
user.Name = "张三";
user.Age = 12;

 

有时我们的类里需要使用到类内部的“字段”,则我们也可以将“字段”关联到数据对象里,如下面的扩展方法处理

/// <summary>
/// 用户对象
/// </summary>
public class DbUser : DbObject
{
    public DbUser()
    {
        this.AddInternalData("Id", () => this.Id, (o) => this.Id = o.As<int>());
    }
    /// <summary>
    /// 编号
    /// </summary>
    public int Id;

    /// <summary>
    /// 姓名
    /// </summary>
    public string Name
    {
        get
        {
            return this.GetData<string>("Name", null);
        }
        set
        {
            this["Name"] = value;
        }
    }
    /// <summary>
    /// 年龄
    /// </summary>
    public int Age
    {
        get
        {
            return this.GetData<int>("Age", 0);
        }
        set
        {
            this["Age"] = value;
        }
    }
}

我们通过“AddInternalData”方法,将Id字段加入到了数据对象里,这样我们就可以在数据对象里使用”Id”数据了,如下面代码

            DbUser user = new DbUser();
            user["Id"] = 33;
            Console.WriteLine(user.Id);  //输出33
            user.Id = 22;
            Console.WriteLine(user.GetData<int>("Id"));  //输出22

 

 

还有一种情况,有时对一种数据,我们多有种不同的名称,比如“用户名”,有时使用为“name“,有时又为“username“,比如以下两句SQL语句

 

SELECT Name FROM [User]
SELECT B.BookName,U.UserId,U.Name AS UserName FROM [Book] B INNER JOIN [User] U ON U.Id=B.UserId

在第一句SQL语句里,因为只单纯查询用户表,所以可以使用“name”做用户的名称,但在第二句SQL语句里,为了区别用户的数据,又采用了"username”做为用户名数据,对于这种情况,我们也可以在数据对象里进行扩展,如以下示例代码

/// <summary>
/// 用户对象
/// </summary>
public class DbUser : DbObject
{
    public DbUser()
    {
        this.AddInternalData("Id", () => this.Id, (o) => this.Id = o.As<int>());
    }
    /// <summary>
    /// 编号
    /// </summary>
    public int Id;

    /// <summary>
    /// 姓名
    /// </summary>
    public string Name
    {
        get
        {
            return this.GetData<string>("Name", null);
        }
        set
        {
            this["Name"] = value;
        }
    }
    /// <summary>
    /// 年龄
    /// </summary>
    public int Age
    {
        get
        {
            return this.GetData<int>("Age", 0);
        }
        set
        {
            this["Age"] = value;
        }
    }

    protected override bool OnBeforeSetData(string name, object value)
    {
        if ("username".Equals(name, StringComparison.OrdinalIgnoreCase))
        {
            //调用内部的SetDataImp方法,可避免再一次触发OnBeforeSetData方法
            this.SetDataImp("name", value);

            /**
             * 注:以下两种方式都会再一次触发OnBeforeSetData方法,所以尽量不要使用
             * this.SetData("name", value);
             * this.Name = value.As<string>();
            **/
            return false;
        }
        return base.OnBeforeSetData(name, value);
    }
}

 

使用示例

            DbUser user = new DbUser();
            user.Name = "张三";
            Console.WriteLine(user.Name);  //输出"张三"
            user["username"] = "李四";
            Console.WriteLine(user.Name);  //输出"李四"

 

 

 

数据对象的使用

在上面示例代码里,也许会有很多同学都会问“这样的数据对象,看不出它的好处在哪里,并且比直接写一个类结构还更复杂”,是的,直接这样使用数据对象,真的体现不出它的好处在哪里,但如果将数据对象与“数据库”挂上关系,那就可以体现数据对象的好处在哪里了。比如我们的数据库有这样的两个表

 
 

表1:User 用户表

Id int
Name nvarchar(20)
Age int
Phone nvarchar(20)
LocationId int

表2:Location 位置表

Id int
UserId int
City nvarchar(30)
Address nvarchar(200)
Zipcode nvarchar(6)

 

现在我们需要获取User表里的数据,比如有以下的SQL语句

SELECT * FROM [User]

根据上表可以知道,这样的查询语句,将获取到的数据共有5个(Id,Name,Age,Phone,LocationId),但如果将这些数据映射到某个实体类去,并且实现数据的一一对应,那我们就需要定义这5个属性或字段,如下面的类

/// <summary>
/// 用户对象
/// </summary>
public class User 
{
    public User()
    {

    }
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Phone { get; set; }
    public int LocationId { get; set; }
}

 

但假如我们现在在获取用户数据时还需要同时获取用户的地址位置数据,如以下的SQL语句

SELECT U.Id,U.Name,L.City,L.Address,L.Zipcode FROM [User] U INNER JOIN [Location] L ON L.Id=U.Location.Id

 

这条查询语句我们共需要获取Id,Name,City,Address,Zipcode这5个数据,很明显,这里的数据与上面的User类结构是不相同的,也就是如果需要将这条SQL语句映射为类对象,我们又需要建多一个类结构对象。也就是每当我们SQL语句有变化时,我们就需要增加不同的类对象,这样对我们来说是非常麻烦且工作量是非常之大的。

 

如果我们使用数据对象来做数据映射,因为数据对象本来就是一个“字典”对象,所以不管我们的SQL语句如何变化,数据都是进入到数据对象里的“槽”里,再根据“扩展数据对象”反映到对象的“属性”或“字段”里。比如上面两句SQL语句我们都可以将其映射为“扩展数据对象”那段里定义的“DbUser”对象,对于未“扩展”的“Phone,LocationId,City,Address,Zipcode“等数据,我们则可以在需要时通过数据对象的“GetData<T>”方法获取,如下:

var phone = user.GetData<string>("Phone");
var locationId = user.GetData<int>("LocationId");

 

从上面的示例中,我们可以看到DbObject有点类似于DataTable,确切的说应该是像DataRow,只当一个相同的DbObject列表集时,才能说象DataTable。KT也提供了DbObject的扩展方法,通过扩展方法DataTable与List<DbObject>可以互相转换。如下示例:

DataTable new DataTable"name"typeofstring"age"typeofint"张三""李四"var DbUserConsole//输出:2
            Console//输出:张三
            var Console//输出:2
            Console"Name"//输出:张三
本文转自Kingthy博客园博客,原文链接:http://www.cnblogs.com/kingthy/archive/2011/08/24/2152641.html ,如需转载请自行联系原作者
相关文章
|
缓存 NoSQL 应用服务中间件
万字攻略,社招腾讯天美C++后台面经,面试题整理(上)
万字攻略,社招腾讯天美C++后台面经,面试题整理
|
11月前
|
存储 Rust 前端开发
Tauri 开发实践 — Tauri 配置介绍
本文首发于微信公众号“前端徐徐”,主要讲解`package.json`、`Cargo.toml`及`tauri.conf.json`三个文件的配置。其中,`tauri.conf.json`最为复杂,涉及众多配置项。`package.json`用于配置前端依赖与脚本;`Cargo.toml`用于声明Rust应用依赖;`tauri.conf.json`则管理前端资源、API白名单等。这些配置对于Tauri应用的开发至关重要。
563 5
|
11月前
|
Rust 前端开发 关系型数据库
Tauri 开发实践 — Tauri 集成本地数据库
本文介绍了在 Tauri 框架中集成本地数据库的几种方案,包括直接绑定 SQLite、使用第三方数据库库和使用 tauri-plugin-sql-api 插件。最终选择了 tauri-plugin-sql-api,因为它集成简单、支持多种数据库类型,并且与 Tauri 框架深度整合,提升了开发效率和安全性。文章详细介绍了如何安装和使用该插件,以及如何编写核心代码实现数据库操作。
847 2
|
Rust Cloud Native 安全
哇塞!Rust 在云原生环境中搞大事啦!构建微服务竟如此酷炫,你还不来看看?
【8月更文挑战第31天】《构建微服务:Rust 在云原生环境中的实践》探讨了 Rust 语言凭借其内存安全、高性能及可靠性等特性,在快速发展的云计算领域构建微服务的优势。书中介绍了选择合适框架(如 Axum 和 Tide)、容器化部署、服务间通信及确保服务可靠性等方面的内容,并展示了 Rust 在云原生环境中的广泛应用前景。
583 1
|
Java 测试技术 开发工具
使用Spring Boot和Spock进行单元测试
使用Spring Boot和Spock进行单元测试
|
Java Serverless Kotlin
Kotlin中的异常处理
Kotlin中的异常处理
328 1
|
SQL 存储 前端开发
JAVA中怎样实现树形菜单
在这篇文章中,作者介绍了如何用两种方法实现目录树数据结构。首先,定义了目录结构在实际开发中的作用,即后端向前端返回整理好的数据,类似书目录的形式。接着,作者逐步讲解了实现目录树的步骤,包括创建数据表、插入数据、创建对象类以及编写逻辑代码。在逻辑代码部分,提供了两种写法,一种适合新手理解,另一种简洁但可能对初学者较难。每种写法都包含了获取数据、转换数据、构建树结构和获取顶层节点的过程。最后,展示了实现后的目录树结构数据。
226 2
|
JSON Kubernetes Go
IDEA使用Kubernetes插件编写YAML
IDEA使用Kubernetes插件编写YAML
445 0
IDEA使用Kubernetes插件编写YAML
|
存储 编解码 缓存
【ffmpeg 移动视频流位置】深入理解FFmpeg:精细探讨seek操作和编解码上下文
【ffmpeg 移动视频流位置】深入理解FFmpeg:精细探讨seek操作和编解码上下文
661 0
|
编解码 Linux 数据安全/隐私保护
深度探索:使用FFmpeg实现视频Logo的添加与移除(一)
深度探索:使用FFmpeg实现视频Logo的添加与移除
450 0