你知道EF中POCO关系映射吗?

关系映射是建立表与表之间关系最重要的环节,如果说属性映射是内部环境,那么关系映射就是外部依赖。我们知道映射都是在上下文中的OnModelCreating方法中配置的,如果在学习阶段这样使用没有问题,但是在实际的项目开发中,且不说上下文看起来非常臃肿,最重要的是难以维护,所以我们都是要将其分层解耦。

1、One-to-Many Relationship (一对多)

这是一个控制台项目案例。我将POCO类都放在了Entity文件夹中;将每一个POCO的映射放在Map文件夹中。

关系映射项目图解.png

由于大部分POCO类都有其共性,所以定义BaseEntity类并使其他类都继承自该类。

  • BaseEntity
using System;

namespace EntityFramework_CreateDbContext.Entity
{
   /// <summary>
   /// POCP基类(一般pocp的类都有相同属性,我们一般将其抽象为一个基类)
   /// </summary>
    public abstract class BaseEntity
    {
        public int Id { get; set; }
        public DateTime CreateTime { get; set; }
        public DateTime ModifiedTime { get; set; }
    }
}
  • Customer
using System.Collections.Generic;

namespace EntityFramework_CreateDbContext.Entity
{
    /// <summary>
    /// 客户
    /// </summary>
    public class Customer:BaseEntity
    {
        public string Name { get; set; }
        public string Email { get; set; }
        public virtual ICollection<Order> Orders { get; set; }
    }
}
  • order
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EntityFramework_CreateDbContext.Entity
{
    /// <summary>
    /// 订单
    /// </summary>
   public class Order:BaseEntity
    {
        public byte Quanatity { get; set; }
        public int Price { get; set; }
        public int CustomerId { get; set; }
        public virtual Customer  Customer{ get; set; }
    }
}

我们将POCO类放在Entity文件夹中,将每一个POCO的映射放在Map文件夹中,那么如何建立每一个POCO类的映射呢?在EF6.x中有EntityTypeConfigation<T>泛型,该类存在于System.Data.Entity.ModelConfiguation命名空间下,我们只需要在此类派生中构造函数配置映射即可。

  • CustomerMap
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class CustomerMap:EntityTypeConfiguration<Customer>
    {
        public CustomerMap()
        {
            //设置 生成表
            ToTable("Customers");

            //设置主键
            HasKey(t => t.Id);
            
            //设置生成 字段的类型、长度、不为空
            Property(t => t.Name).HasColumnType("VARCHAR").HasMaxLength(50).IsRequired();
            
            //设置生成 字段的类型、长度、不为空
            Property(t => t.Email).HasColumnType("VARCHAR").HasMaxLength(50).IsRequired();

            //设置生成 字段
            Property(t => t.CreateTime);
            
            //设置生成 字段
            Property(t => t.ModifiedTime);

            HasMany(t => t.Orders).WithRequired(w => w.Customer)
                .HasForeignKey(k => k.CustomerId);
        }
    }
}
  • OrderMap
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class OrderMap:EntityTypeConfiguration<Order>
    {
        public OrderMap()
        {
            ToTable("Orders");

            HasKey(t => t.Id);

            Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(t => t.Quanatity);
            Property(t => t.Price);
            Property(t => t.CustomerId);
            Property(t => t.CreateTime);
            Property(t => t.ModifiedTime);

            //外键关系
            HasRequired(t=>t.Customer).WithMany(c=>c.Orders)
                .HasForeignKey(t=>t.CustomerId).WillCascadeOnDelete(false);
        }
    }
}

然后将映射Map类添加(注册)到Configuration配置中。

  • EfDbContext
using System;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using System.Linq;
using System.Reflection;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext
{
    public class EfDbContext:DbContext
    {
        public EfDbContext():base("server=.;database=createDbContext;uid=sa;pwd=123123")
        {
            Database.SetInitializer(new CreateDatabaseIfNotExists<EfDbContext>());
        }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //在程序集中查找,命名空间不为空、并且父类不是null、并且父类是泛型、并且父类类型是EntityTypeConfiguration<>
            var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
                .Where(type => !string.IsNullOrEmpty(type.Namespace))
                .Where(type => type.BaseType != null && type.BaseType.IsGenericType
                                                     && type.BaseType.GetGenericTypeDefinition() ==
                                                     typeof(EntityTypeConfiguration<>));
            //遍历该程序集,通过反射的方式获取到类,并将类注册到上下文对象中
            foreach (var type in typesToRegister)
            {
                dynamic configurationInstance = Activator.CreateInstance(type);
                modelBuilder.Configurations.Add(configurationInstance);//将Map映射类注册到配置中
            }

            base.OnModelCreating(modelBuilder);
        }

        public DbSet<Customer> Customers { get; set; }

        public DbSet<Order> Orders { get; set; }
    }
}

此时,我们再来看上下文类,非常干净,分门别类,不臃肿且方便维护。
接下来分析二者关系的配置,前面在订单表(Order)中配置二者的关系,一个订单必须对应一个客户,所以其关系为HasRequired,同时一个客户会下多个订单,此时则用WithMany,同时订单中的CustomerId为Customer的外键,以此来进行约束。这样的配置为逆向角度。我们也可以正向角度在Order中配置。HasMany(p => p.Orders).WithRequired(w => w.Customer).HasForeignKey(k => k.CustomerId);

最终生成的数据库结构如下:


一对多关系生成数据库中表

2、Many-to-Many Relationship (多对多)

如果两个表之间的任何记录都与另一个表的若干行记录有关,因为关系系统无法表达这两者的关系,所以就需要第三个表来维护这两个表的关系,此表则称为关联表或者链接表。多对多关系就是这样的场景,需要第三个表来关联或维护两个表的关系。

案例场景:
一个学生可以学习多门课程,一门课程也可以被多名学生学习。

  • Student
using System.Collections.Generic;

namespace EntityFramework_CreateDbContext.Entity
{
    /// <summary>
    /// 学生
    /// </summary>
   public class Student:BaseEntity
    {
        public string Name { get; set; }
        public byte Age { get; set; }
        public virtual ICollection<Course> Courses { get; set; }
    }
}
  • Course
using System.Collections.Generic;

namespace EntityFramework_CreateDbContext.Entity
{
    /// <summary>
    /// 课程
    /// </summary>
    public class Course : BaseEntity
    {
        /// <summary>
        /// 课程名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 课程时长
        /// </summary>
        public int MaximumStrength { get; set; }
        public virtual ICollection<Student> Students { get; set; }
    }
}
  • StudentMap
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class StudentMap : EntityTypeConfiguration<Student>
    {
        public StudentMap()
        {
            //table
            ToTable("Students");

            //key
            HasKey(t => t.Id);

            //property
            Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(t => t.Name).HasColumnType("VARCHAR").HasMaxLength(50);
            Property(t => t.Age);
            Property(t => t.CreateTime);
            Property(t => t.ModifiedTime);

            //relationship
            HasMany(t => t.Courses).WithMany(c => c.Students)
                .Map(t => t.ToTable("StudentCourses")
                    .MapLeftKey("StudentId")
                    .MapRightKey("CourseId"));

        }
    }
}

上述学生映射类片段表明:一个学生可以参加多门课程,一门课程可以有很多学生。为了实现学生和课程的多对多关系,我们自定义第三个表(StudentCourses表),MapLeftKey和MapRightKey定义了键的名称,其中左键作为定义关系的键。若不自定义键名称,则默认自动使用类型和加上“_”在加上id作为键的名称。

  • CourseMap
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
   public class CourseMap:EntityTypeConfiguration<Course>
    {
        public CourseMap()
        {
            //table
            ToTable("Courses");

            //property
            Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(t => t.Name).HasColumnType("VARCHAR").HasMaxLength(50);
            Property(t => t.MaximumStrength);
            Property(t => t.CreateTime);
            Property(t => t.ModifiedTime);
        }
    }
}

最终生成的数据库结构如下:

隐式 多对多

刚才上面的是映射多对多关系且第三给奥自动生成。有时候我们需要显示定义第三个表来维护Student和Courses的关系,所以对多对多关系,还有另一种映射方式,即显示定义第三个表。

  • StudentCourse
namespace EntityFramework_CreateDbContext.Entity
{
    public class StudentCourse : BaseEntity
    {
        public int StudentId { get; set; }
        public virtual Student Student { get; set; }

        public int CoursesId { get; set; }

        public virtual Course Course { get; set; }
    }
}
  • Student
using System.Collections.Generic;

namespace EntityFramework_CreateDbContext.Entity
{
    /// <summary>
    /// 学生
    /// </summary>
   public class Student:BaseEntity
    {
        public string Name { get; set; }
        public byte Age { get; set; }
        public virtual ICollection<StudentCourse> StudentCourses { get; set; }
    }
}
  • Course
using System.Collections.Generic;

namespace EntityFramework_CreateDbContext.Entity
{
    /// <summary>
    /// 课程
    /// </summary>
    public class Course : BaseEntity
    {
        /// <summary>
        /// 课程名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 课程时长
        /// </summary>
        public int MaximumStrength { get; set; }
        public virtual ICollection<StudentCourse> StudentCourses { get; set; }
    }
}
  • CourseMap
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
   public class CourseMap:EntityTypeConfiguration<Course>
    {
        public CourseMap()
        {
            //table
            ToTable("Courses");

            //property
            Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(t => t.Name).HasColumnType("VARCHAR").HasMaxLength(50);
            Property(t => t.MaximumStrength);
            Property(t => t.CreateTime);
            Property(t => t.ModifiedTime);

            HasMany(t => t.StudentCourses)
                .WithRequired(t => t.Course)
                .HasForeignKey(k => k.CoursesId);
        }
    }
}
  • StudentMap
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class StudentMap : EntityTypeConfiguration<Student>
    {
        public StudentMap()
        {
            //table
            ToTable("Students");

            //key
            HasKey(t => t.Id);

            //property
            Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(t => t.Name).HasColumnType("VARCHAR").HasMaxLength(50);
            Property(t => t.Age);
            Property(t => t.CreateTime);
            Property(t => t.ModifiedTime);

            //relationship
            HasMany(t => t.StudentCourses)
                .WithRequired(t => t.Student)
                .HasForeignKey(k => k.StudentId);

        }
    }
}

最终生成的数据库结构如下:

显示 多对多

3、One-to-One Relationship (一对一)

案例场景:
一个学生可能有联系方式,也可能没有,一个联系方式必须对应一个学生。

  • StudentInfo
namespace EntityFramework_CreateDbContext.Entity
{
    public class StudentInfo
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public virtual StudentContact StudentContact{ get; set; }
    }
}
  • StudentContact
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EntityFramework_CreateDbContext.Entity
{
    public class StudentContact
    {
        public long Id { get; set; }
        public string ContactNumber { get; set; }
        public virtual Student Student { get; set; }
    }
}

(1)HasOptional then WithRequired

学生映射和联系方式映射:

  • StudentInfoMap
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class StudentInfoMap:EntityTypeConfiguration<StudentInfo>
    {
        public StudentInfoMap()
        {
            ToTable("StudentInfos");

            HasKey(t => t.Id);

            Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

            HasOptional(t => t.StudentContact)//一个学生可能有联系方式,也有可能没有
                .WithRequired(k => k.StudentInfo);//一个联系方式必定对应一个学生
        }
    }
}
  • StudentContactMap
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class StudentContactMap : EntityTypeConfiguration<StudentContact>
    {
        public StudentContactMap()
        {
            ToTable("StudentContacts");

            HasKey(t => t.Id);
            Property(x => x.Id)
                .HasColumnName("StudentInfoId")
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
        }
    }
}

最终生成的数据库结构如下:

HasOptional then WithRequired

从上图分析:在学生信息表中,主键Id为自增长;而在学生联系表中StudentId即自定义的属性Id,并为其起别名,此列既是主键又是外键。

(2)HasOptional then WithOptionalPrincipal

此时,我们将学生和联系方式映射类修改如下:

  • StudentInfoMap
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class StudentInfoMap:EntityTypeConfiguration<StudentInfo>
    {
        public StudentInfoMap()
        {
            ToTable("StudentInfos");

            HasKey(t => t.Id);

            Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            
            HasOptional(t => t.StudentContact)//一个学生可能有联系方式,也有可能没有
                .WithOptionalPrincipal(k => k.StudentInfo);//一个联系方式必定对应一个学生
        }
    }
}
  • StudentContactMap
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class StudentContactMap : EntityTypeConfiguration<StudentContact>
    {
        public StudentContactMap()
        {
            ToTable("StudentContacts");

            HasKey(t => t.Id);
            Property(x => x.Id)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);//设置联系人表中的id为自动增长
        }
    }
}

最终生成的数据库结构如下:

image.png

从上图分析:在学生信息表中,主键Id为自增长;在联系表中,Id为主键且自增长,Student_Id自动创建并且在学生模型和联系方式模型中没有导航属性,Student_Id 可空且是 Student 表中 Id 的外键。此方式创建的关联外键更符合我们经常创建的方式。

(3)HasOptional then WithOptionalDependent

我们再将学生和学生联系方式映射类配置如下:

  • StudentInfoMap
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class StudentInfoMap:EntityTypeConfiguration<StudentInfo>
    {
        public StudentInfoMap()
        {
            ToTable("StudentInfos");

            HasKey(t => t.Id);

            Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            
            HasOptional(t => t.StudentContact)//一个学生可能有联系方式,也有可能没有
                .WithOptionalDependent(k => k.StudentInfo);//一个联系方式必定对应一个学生
        }
    }
}
  • StudentContactMap
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class StudentContactMap : EntityTypeConfiguration<StudentContact>
    {
        public StudentContactMap()
        {
            ToTable("StudentContacts");

            HasKey(t => t.Id);
            Property(x => x.Id)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);//设置联系人表中的id为自动增长
        }
    }
}

最终生成的数据库结构如下:

image.png
image.png

从上图分析:在联系表中,Id为主键且自增长;在学生信息表中,主键Id为自增长,StudentContact_Id自动创建并且在学生模型和联系方式模型中没有导航属性,StudentContact_Id 可空且是 StudentContact 表中 Id 的外键。
由此我们知道,选择 WithOptionalPrincipal 使得该实体作为主体,意味着它包含关系的主键。选择 WithOptionalDependent 使得该实体作为依赖体,意味着它将具有关系的外键。

(4)HasRequired then WithOptional

上述我们一直是从学生表映射类中入手来配置和学生联系方式表的关系,如果想要从学生联系方式映射中入手呢?当然也是可以的,此时我们将学生映射和学生联系方式映射类配置如下:

  • StudentInfoMap
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class StudentInfoMap:EntityTypeConfiguration<StudentInfo>
    {
        public StudentInfoMap()
        {
            ToTable("StudentInfos");

            HasKey(t => t.Id);

            Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        }
    }
}
  • StudentContactMap
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class StudentContactMap : EntityTypeConfiguration<StudentContact>
    {
        public StudentContactMap()
        {
            ToTable("StudentContacts");

            HasKey(t => t.Id);
            Property(x => x.Id)
                .HasColumnName("StudentId")
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);//设置联系人表中的id为自动增长

            HasRequired(t => t.StudentInfo)//一个联系方式必定对应一个学生
                .WithOptional(k => k.StudentContact);//一个学生可能有联系方式,也有可能没有
        }
    }
}

这种情况的结果就和第一种利用 HasOptional 和 WithRequired 来配置一对一关系一样,只是配置角度不一样而已。

(5)HasRequired then WithOptional

依然是利用 HasRequired 和 WithOptional 从学生联系方式映射类中入手,学生映射类不变,如此同样可以得到和第二种一样的结果,代码如下:

  • StudentInfoMap
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class StudentInfoMap:EntityTypeConfiguration<StudentInfo>
    {
        public StudentInfoMap()
        {
            ToTable("StudentInfos");

            HasKey(t => t.Id);

            Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        }
    }
}
  • StudentContactMap
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using EntityFramework_CreateDbContext.Entity;

namespace EntityFramework_CreateDbContext.Map
{
    public class StudentContactMap : EntityTypeConfiguration<StudentContact>
    {
        public StudentContactMap()
        {
            ToTable("StudentContacts");

            HasKey(t => t.Id);
            Property(x => x.Id)
                .HasColumnName("StudentId")
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);//设置联系人表中的id为自动增长

            HasRequired(t => t.StudentInfo) //一个联系方式必定对应一个学生
                .WithOptional(k => k.StudentContact) //一个学生可能有联系方式,也有可能没有
                .Map(x => x.MapKey("Student_Id"));
        }
    }
}

参考书籍

  • 你必须掌握的Entity Framework 6.x与Core 2.0
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容

  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,457评论 0 4
  • 上篇文章我们通过注解对映射了单个实体类,但是具体项目中往往实体类之间又是相互关联的,本篇文章就是从实体类之间存在的...
    Single_YAM阅读 906评论 0 2
  • Single-table策略:这是继承映射中的缺省策略,在不特别指明的情况下,系统默认就是采用这种映射策略进行映射...
    _郑_阅读 595评论 0 0
  • 一. Java基础部分.................................................
    wy_sure阅读 3,805评论 0 11
  • 有人说,人一生最大的资本是骨子里的教养。那什么是教养呢?梁晓声曾这样概括“文化”二字:“植根于内心的修养,...
    林野轻风阅读 216评论 0 2