EF(二)--EF模型的配置

EF 的安装

  1. 基础阶段用控制台项目。使用NuGet 安装EntityFramework。会自动在App.config中增加两个entityFramework 相关配置段;

  2. 在 web.config 中配置连接字符串

    <add name="conn1" connectionString="Data Source=.;Initial Catalog=test1;UserID=sa;Password=123" providerName="System.Data.SqlClient" />
    

    易错点:不能忘了写providerName="System.Data.SqlClient"增加两个entityFramework 相关配置段;

EF 简单DataAnnotations 实体配置

  1. 数据库中建表T_Perons,有Id(主键,自动增长)、Name、CreateDateTime字段。

  2. 创建Person类[Table(“T_Persons”)]因为类名和表名不一样,所以要使用Table标注

        [Table("T_Persons")]
        public class Person
        {
            public long ID { get; set; }
            public string Name { get; set; }
            public DateTime CreateTime { get; set; }
        }
    

    因为EF约定主键字段名是Id,所以不用再特殊指定Id是主键,如果非要指定就指定[Key]。因为字段名字和属性名字一致,所以不用再特殊指定属性和字段名的对应关系,如果需要特殊指定,则要用[Column(“Name”)]

    (*)必填字段标注[Required]、字段长度[MaxLength(5)]、可空字段用int?、如果字段在数据库有默认值,则要在属性上标注[DatabaseGenerated]注意实体类都要写成public,否则后面可能会有麻烦。

  3. 创建DbContext类(模型类、实体类)

        public class MyDBContext: DbContext
        {
            //表示使用连接字符串中名字为conn1 的去连接数据库
            public MyDBContext() : base("name=strcon")
            {
    
            }
            //通过对Persons 集合的操作就可以完成对T_Persons的操作
            public DbSet<Person> Persons { get; set; }
        }
    
  4. 测试

            protected void Button1_Click(object sender, EventArgs e)
            {
                MyDBContext context = new MyDBContext();
                Person p=new Person();
                p.Name =TextBox1.Text;
                p.CreateTime = DateTime.Now;
                context.Persons.Add(p);
                context.SaveChanges();
            }
    

    注意:MyDbContext 对象是否需要using有争议,不using也没事。每次用的时候new MyDbContext就行,不用共享同一个实例,共享反而会有问题。SaveChanges()才会把修改更新到数据库中。

    EF的开发团队都说要using DbContext,很多人不using,只是想利用LazyLoad 而已,但是那样做是违反分层原则的。我的习惯还是using。

    异常的处理:如果数据有错误可能在SaveChanges()的时候出现异常,一般仔细查看异常信息或者一直深入一层层的钻InnerException 就能发现错误信息。

    举例:创建一个Person对象,不给Name、CreateDateTime赋值就保存。

EF 模型的两种配置方式

EF 中的模型类的配置有DataAnnotations、FluentAPI 两种。

上面这种在模型类上[Table(“T_Persons”)]、[Column(“Name”)]这种方式就叫DataAnnotations这种方式比较方便,但是耦合度太高,一般的类最好是POCO(Plain Old C# Object,没有继承什么特殊的父类,没有标注什么特殊的Attribute,没有定义什么特殊的方法,就是一堆普通的属性);不符合大项目开发的要求。微软推荐使用FluentAPI
的使用方式,因此后面主要用FluentAPI 的使用方式。

FluentAPI 配置T_Persons 的方式

  1. 数据库中建表T_Perons,有Id(主键,自动增长)、Name、CreateDateTime 字段。

  2. 创建 Person 类。模型类就是普通C#类

        public class Person
        {
            public long ID { get; set; }
            public string Name { get; set; }
            public DateTime CreateTime { get; set; }
        }
    
  3. 创建一个 PersonConfig 类,放到ModelConfig 文件夹下(PersonConfig、EntityConfig这样的名字都不是必须的)

        public class PersonConfig : EntityTypeConfiguration<Person>
        {
            public PersonConfig()
            {
                this.ToTable("T_Person");
            }
        }
    
  4. 创建 DbContext 类

        public class MyDBContext:DbContext
        {
            public MyDBContext() : base("name=strcon")
            {
            }
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
                modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly());
            }
            public DbSet<Person> Persons { get; set; }
        }
    

    下面这句话:

    modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly());

    代表从这句话所在的程序集加载所有的继承自EntityTypeConfiguration 为模型配置类。还有很多加载配置文件的做法(把配置写到OnModelCreating中或者把加载的代码写死到OnModelCreating 中),但是这种做法是最符合大项目规范的做法。

    和以前唯一的不同就是:模型不需要标注Attribute;编写一个XXXConfig类配置映射关系;DbContext 中override OnModelCreating;

  5. 测试

            protected void Button1_Click(object sender, EventArgs e)
            {
                MyDBContext context = new MyDBContext();
                Person p = new Person();
                p.Name = TextBox1.Text;
                p.CreateTime = DateTime.Now;
                context.Persons.Add(p);
                context.SaveChanges();
            }
    

EF 的基本增删改查

获取DbSet除了可以ctx.Persons之外,还可以ctx.Set()。

  1. 增加,一个点:如果Id是自动增长的,创建的对象显然不用指定Id的值,并且在SaveChanges ()后会自动给对象的Id属性赋值为新增行的Id字段的值。

  2. 删除。先查询出来要删除的数据,然后Remove。这种方式问题最少,虽然性能略低,但是删除操作一般不频繁,不用考虑性能。后续在“状态管理”中会讲其他实现方法。

                MyDBContext context = new MyDBContext();
                if (e.CommandName=="BtnDelete")
                {
                    int id = Convert.ToInt32(e.CommandArgument);
                    var p = context.Persons.Where(per => per.ID == id).SingleOrDefault();
                    if (p!=null)
                    {
                        context.Persons.Remove(p);
                    }
                   int i= context.SaveChanges();
                    if (i>0)
                    {
                        Repeater1.DataSource = context.Persons.ToList();
                        Repeater1.DataBind();
                    }
                }
    

    怎么批量删除,比如删除Id>3 的?查询出来一个个Remove。性能坑爹。如果操作不频繁或者数据量不大不用考虑性能,如果需要考虑性能就直接执行sql 语句

  3. 修改:先查询出来要修改的数据,然后修改,然后SaveChanges()

    MyDbContext ctx = new MyDbContext();
    var ps = ctx.Persons.Where(p => p.Id > 3);
    foreach(var p in ps)
    {
        p.CreateDateTime = p.CreateDateTime.AddDays(3);
        p.Name = "haha";
    }
    ctx.SaveChanges();
    

    性能问题?同上。

  4. 查。因为DbSet 实现了IQueryable 接口,而IQueryable 接口继承了IEnumerable
    接口,所以可以使用所有的linq、lambda 操作。给表增加一个Age 字段,然后举例orderby、groupby、where
    操作、分页等。一样一样的。

  5. 查询 order by 的一个细节

    EF调用Skip之前必须调用OrderBy:如下调用var items = ctx.Persons.Skip(3).Take(5); 会报错“The method ‘OrderBy’ must be called before the method ‘Skip’.)”,要改成:var items = ctx.Persons.OrderBy(p=>p.CreateDateTime).Skip(3).Take(5);

    这也是一个好习惯,因为以前就发生过(写原始sql):分页查询的时候没有指定排序规则,以为默认是按照Id 排序,其实有的时候不是,就造成数据混乱。写原始SQL 的时候也要注意一定要指定排序规则。

  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT-wanghanghang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值