• 讲讲Linq to SQL映射(基础篇)


           

    讲讲Linq to SQL映射(基础篇)

    这篇主要讲Linq to  SQL基于属性的映射。即映射数据库,映射表,映射列,映射关系,映射存储过程,

    映射函数。然而创建这种映射有三种方法,他们分别是ORD工具,SQLMetal命令行工具,以及编写手工代码

    创建。

            咱们首先了解下手工创建属性映射的方法,这样你就能看懂基于工具产生的代码了。他们的区别也就是

    使用工具效率会更高些,但前提需要先设计好数据库,这样就可以直接通过数据库的结构输出你的实体类。

    1、映射数据库

    映射数据库主要通过Database属性来指定,引用命名空间System.Data.Linq.Mapping;

    具体看如下代码:

    复制代码
    //这里在连接的时候 如果MyDatabase不指定Database属性,生成的数据库名为MyDbContext类名
        //如果指定,则为Database属性里的名称,在这里生成的数据库名为IThinks
        [Database(Name = "IThinks")]
        public class MyDbContext : DataContext
        {
            //必须构建此表,不然创建数据库时会提示没有表,无法创建。
            public Table<LoginUser> LoginUsers;
            public Table<UserBaseInfo> UserBaseInfos;
            public Table<Aritcal> Articals;
            public MyDbContext(string connection)  : base(connection)
            {
            }
        }
    复制代码

    然后再创建数据库连接的时候,就可以这样写,如果database 不设置的话,默认的数据库名就会为MyDbContext 类名:

    MyDbContext db = new MyDbContext("Data Source=localhost;Integrated Security=true;");

    这样的话,输出的连接sql语句为:

    QQ20130904233637_thumb13

    2、映射表

    映射表使用的attribute属性为Table

    //Table:映射数据库中对应表或视图名,NAME指定数据库表名,若无此表,创建数据库时,会自动创建 
        [Table(Name="UserBaseInfo")]
        public class UserBaseInfo

    3、映射列

    映射列使用的attribute属性为Column,参数设置比较多,具体看如下代码:

    复制代码
           //Column:映射数据库表中字段 其特性为:
           //Name:数据库中列的名称
            //DbType:数据库列的数据库类型
            //Storage:获取或设置私有存储字段以保存列值
            //IsPrimaryKey:指示所关联的列是否是相应表的主键 默认false
           //CanBeNull:指示所关联的列能否包含空值 
            //CanBeNull不能乱用,如果某列CanBeNull设置为true,但从数据库中查出来的值为null的话,
             //这一列在update的时候会提示找不到此行或行已更改,因为其查询的语句为where 0 = 1 所以找不到 
               //可以查看:http://stackoverflow.com/questions/2275442/linq-update-query-generates-where-0-1
               //如果你非要设置canbenull=true,可以通过继续设置其updatecheck为never或whenchanged来规避where 0=1这个问题。
           //AutoSync:在执行insert或者update操作之后获取列值,默认为never;
            //UpdateCheck:即设置是否检查冲突,默认是Always
            //IsDbGenerated=true 是否数据库自动生成值,如果设置为true的话,那么在实例化实体给此列赋值将会无效,在执行插入时,会传值为null进入
    //如果这时候数据库未给予默认值或值自增设置,则会报此字段为空的错误,虽然你在实例化时已经赋值。 
    
            [Column(DbType = "int", IsPrimaryKey = true, IsDbGenerated = true)]
            public int UserID { get; set; }
            [Column(DbType = "nvarchar(50) not null", CanBeNull = false, UpdateCheck = UpdateCheck.WhenChanged)]
            public string UserName { get; set; }
            [Column(DbType = "nvarchar(50)", CanBeNull = false, UpdateCheck = UpdateCheck.Never)]
            public string UserNickName { get; set; }
    复制代码

    4、映射关系

    这里的关系是指的数据库中一对多和一对一。主键基表和外键基表的设置也能通过实体字段的Association属性(IsForeignKey=true)来进行关联,从而在创建数据库时,自动创建表之间的关系。

    但要结合EntityRef<T>或 EntitySet<T> 来定义并表示一个关系

    EntityRef代表一对多关系中的单一实例方,EntitySet主要代表一对多和一对一关系中的集合方,下面分别用代码介绍

    以用户基本信息表 UserBaseInfo和用户文章表Aritcal来作为介绍,他们是一对多的关系

    1)EntityRef+Association的使用

    因为EntityRef代表的是1:M关系中的1,所以它应该为Aritcal实体的成员,泛型对象为UserBaseInfo

    这里UserBaseInfo的实体和Artical实体分别为:

    复制代码
      //Table:映射数据库中对应表或视图名,若无此表,会自动创建 
        [Table(Name = "UserBaseInfo")]
        public class UserBaseInfo
        {
    
            [Column(DbType = "int", IsPrimaryKey = true, IsDbGenerated = true)]
            public int UserID { get; set; }
            [Column(DbType = "nvarchar(50) not null", CanBeNull = false, UpdateCheck = UpdateCheck.WhenChanged)]
            public string UserName { get; set; }
            private EntitySet<Aritcal> _Artiacle;
            [Association(ThisKey = "UserID", OtherKey = "UserID")]
            public EntitySet<Aritcal> Articals
            {
                get { return _Artiacle; }
                set { _Artiacle.Assign(value); }
            }
        }
        [Table(Name = "Artical")]
        public class Aritcal
        {
            [Description("文章ID"), Column(IsPrimaryKey = true, CanBeNull = false, DbType = "int not null")]
            public int ArticalID { get; set; }
            [Description("用户ID"), Column(CanBeNull = false, DbType = "int not null")]
            public int UserID { get; set; }
            [Description("文章标题"), Column(DbType = "nvarchar(100) not null", UpdateCheck = UpdateCheck.Never)]
            public string ArticalTitle { get; set; }
            [Description("文章分类"), Column(DbType = "int not null", UpdateCheck = UpdateCheck.Never)]
            public int CategoryID { get; set; }
            [Description("模块分类"), Column(DbType = "int", UpdateCheck = UpdateCheck.Never)]
            public int ModuleID { get; set; }
            [Description("文章内容"), Column(DbType = "ntext not null", UpdateCheck = UpdateCheck.Never)]
            public string Content { get; set; }
    private EntityRef<UserBaseInfo> _UserBaseInfo;
            //Name:外键名
            //ThisKey:外键表的外键列  可以不为主键 除非1:1关系中
            //OtherKey:主键表的主键列 必须是主键
            //IsForeignKey:是否外键
            //Storage:用来存储的变量
            [Association(Name = "FK_Aritcal_UserBaseInfo_UserID", ThisKey = "UserID", OtherKey = "UserID", IsForeignKey = true, 
            Storage = "_UserBaseInfo")]
            public UserBaseInfo UserBaseInfo
            {
                get { return _UserBaseInfo.Entity; }
                set { _UserBaseInfo.Entity = value; }
            }
        }
    复制代码

    这样Artical自动创建外键,生成的表结构关系为

    QQ20130905210648_thumb

    2)下面在讲下EntitySet<T> 和Association

    在UserBaseInfo表中创建下面成员,这样做的好处是,进行数据库关联查询时便能查询出数据

    复制代码
            private EntitySet<Aritcal> _Artiacle;
            [Association(ThisKey = "UserID", OtherKey = "UserID")]
            public EntitySet<Aritcal> Articals
            {
                get { return _Artiacle; }
                set { _Artiacle.Assign(value); }
            }
    复制代码
    见查询代码:  查询用户信息表中用户ID为1的用户信息,通过调用Articals成员,自动关联查询出用户id为1的文章列表
    复制代码
                UserBaseInfo userbase = db.GetTable<UserBaseInfo>().Where(a => a.UserID == 1).FirstOrDefault();
                foreach (Aritcal artical in userbase.Articals.ToList())
                {
                    Console.WriteLine(string.Format("userid:{0}  aritical userid:{1} articalid:{2} ispublist{3}",
                                                 userbase.UserID, artical.UserID, artical.ArticalID, artical.IsPublish));
                }
    复制代码

    查询结果如下:

    QQ20130905210649_thumb

    5、映射存储过程

    通过调用Function属性实现调用存储过程,只有一个Name特性,来指定存储过程的名称

    如下面的实例通过用户名ID,获取用户的密码:

    首先创建存储过程

    复制代码
    create  procedure [dbo].[GetPassword]
    (@userid int ,
    @password nvarchar(30) output
    )
    as 
    begin
    select @password = c.Password from LoginUser c where c.UserID=@userid
    end
    复制代码
    然后在MyDbContext类中添加如下方法
    复制代码
            /// <summary>
            /// 获取用户密码
             /// </summary>
            /// <param name="userid">用户名ID</param>
            /// <param name="password">用来返回获取到的密码</param>
            /// <returns></returns>
            [Function(Name = "GetPassword")]
            public int GetPassword([Parameter(DbType = "int")] int userid, [Parameter(DbType = "nvarchar(30)")] out string password)
            {
                password = "";
                IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)MethodInfo.GetCurrentMethod()), userid, password);
                password = (string)result.GetParameterValue(1); //返回需要的密码数据 必须用out 或者ref引用,不然得到空值
                return (int)result.ReturnValue; //这里返回0 表示执行成功
            }
    复制代码

    调用代码如下:

               string  str;
               db.GetPassword(userbase.UserID,  out str);
               Console.WriteLine("pwd:"+str);

    调用结果如下:

    QQ20130905210650_thumb

    6、映射函数

    用户自定义函数(UDF)在linq to sql中用到的属性是一样的,不过函数和存储过程的区别导致了函数只能返回单个值,而不能像存储过程那样返回多个参数

    具体实现看如下代码

    首先在数据库中定义函数

    复制代码
    --创建通过用户ID获取密码的函数
    create function Fun_GetPassword
    (@userid int )
    returns nvarchar(30)
    as
    begin 
     declare @password nvarchar(30) 
     select @password = c.Password  from LoginUser c where c.UserID=@userid
     return  @password
    end
    复制代码

    然后在vs中编写代码调用

    复制代码
           //调用函数 这里要加dbo.,不然你若返回的不是表,则会提示Fun_GetPassword不是可以识别的 内置函数名称。
            //另外调用函数,要定义IsComposable特性为true,这样他才知道是调用的存储过程
            [Function(Name = "dbo.Fun_GetPassword", IsComposable = true)]
            public string Fun_GetPassword([Parameter(DbType = "int")] int userid)
            {
                IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)MethodInfo.GetCurrentMethod()), userid);
                return (string)result.ReturnValue;
            }
    
                //调用自定义函数 获取密码
               string mypwd= db.Fun_GetPassword(userbase.UserID);
               Console.WriteLine("pwd:"+mypwd);
    复制代码

    调用结果如下:

    QQ20130905210650_thumb3

    下载源码

  • 相关阅读:
    基于Java的Socket类Tcp网络编程实现实时聊天互动程序(一):QQ聊天界面的搭建
    前端开发者的福音!通过拖拽就可生成Vue代码的平台来了!
    爬虫实战 如何爬取B站视频评论?
    年轻就该多尝试,教你20小时Get一项新技能
    利用Python将多张图片合成视频
    利用myqr库创建自己的二维码
    用Python爬取日向、樱坂成员blog中的JPG文件的url并将其下载到本地
    【MemSQL Start[c]UP 3.0 Round 1 A】 Declined Finalists
    【MemSQL Start[c]UP 3.0 Round 1 E】Desk Disorder
    【MemSQL Start[c]UP 3.0 Round 1 C】 Pie Rules
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3307983.html
Copyright © 2020-2023  润新知