• Entity Framework DBContext 增删改查深度解析


           Entity Framework DBContext 增删改查深度解析

          有一段时间没有更新博客了,赶上今天外面下雨,而且没人约球,打算把最近对Entity Framework DBContext使用的心得梳理一下,早些时候在网上简单查过,对于最新版本的EF并没有类似的知识梳理类文章,希望对大家有所帮助。

    1. 不要Code first, 也不要DB first

    我为什么讨厌Code first和DB first呢?首先Code first是先写代码,数据库完全由代码生成,开发阶段尚可,一旦到了产品发布阶段,如果需要添加字段,我们总不能用 visual studio去生产环境上去更新数据库吧,听起来就很可怕。而且另外的一个问题自动是生成的数据库脚本也不可控,还不如自己提前设计好。DB first也好不了哪去,反向转过来的代码包含很多没有用的文件,而且数据库的更新还要重新走Model生成过程,简直无法理解为什么会有这样的设计。说了这么多,怎么解决呢?

    数据库和领域模型分开设计,按照对应关系映射字段,使用自定义链接字串,既不使用领域模型生成数据库,也不用数据库生成领域模型,示例代码如下,SQL Code 以 Destinations和TTable表为例:

    CREATE TABLE [DBO].[Destinations]
    (
        [DestinationId] [int] PRIMARY KEY NOT NULL,
        [Name] [nvarchar](max) NULL,
        [Country] [nvarchar](max) NULL,
        [Description] [nvarchar](max) NULL,
        [Photo] [varbinary](max) NULL
    )
    
    

    CREATE TABLE [TTT].[TTable]

    (

    [Id] [int] PRIMARY KEY NOT NULL,

    [Name] [nvarchar](max) NULL

    Model Class:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Model
    {
        public class Destination
        {
            public int DestinationId { get; set; }
            public string Name { get; set; }
            public string Country { get; set; }
            public string Description { get; set; }
            public byte[] Photo { get; set; }
            public List<Lodging> Lodgings { get; set; }
        }
    
        public class Lodging
        {
            public int LodgingId { get; set; }
            public string Name { get; set; }
            public string Owner { get; set; }
            public bool IsResort { get; set; }
            public Destination Destination { get; set; }
        }
    
        public class TTable
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    }

    Connect String:

      <connectionStrings>
        <add name="BAContext" connectionString="Data Source=(LocalDb)MSSQLLocalDB;Initial Catalog=DataAccess.BreakAwayContext;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
      </connectionStrings>

    DB Context:

    using System.Data.Entity;
    using System.Data.Entity.ModelConfiguration;
    using Model;
    
    namespace DataAccess
    {
        public class TTableConfiguration : EntityTypeConfiguration<TTable>
        {
            public TTableConfiguration()
            {
                this.ToTable("TTable", "TTT");
            }
        }
    
        public class BreakAwayContext : DbContext
        {
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Configurations.Add(new TTableConfiguration());
            }
    
            public BreakAwayContext(string connString) : base(connString)
            {
            }
            public DbSet<Destination> Destinations { get; set; }
            public DbSet<Lodging> Lodgings { get; set; }
            public DbSet<TTable> TTables { get; set; }
        }
    }

    2. 如果数据库的表的字段和领域模型的字段不对应,如何处理呢?比如本文的TTable表是在TTT  Schema下面的, 而其他表示设计在DBO下面,最方便的方式是使用fluent API, 具体代码如请参见 TTableConfiguration Class和 OnModelCreating()方法,可配置的粒度非常细,比如可以配置领域模型和数据库的哪个Schema的哪张表的哪一列对应,本文是将TTable 类的数据库表配置为了TTT  Schema下的TTable表,

        public class TTableConfiguration : EntityTypeConfiguration<TTable>
        {
            public TTableConfiguration()
            {
                this.ToTable("TTable", "TTT");
            }
        }

    3. 增删该查自带事物支持,具体代码如下,

            public static int Insert()
            {
                var destination = new Destination
                {
                    Country = "Chs",
                    Description = "Chs is the language package",
                    Name = "xsss"
                };
                using (var context = new BreakAwayContext(ConfigurationManager.ConnectionStrings["BAContext"].ConnectionString))
                {
                    var rt = context.Destinations.Add(destination);
                    context.SaveChanges();
                    return rt.DestinationId;
                }
            }
    
            public static void Update(Destination destIn)
            {
                using (var context = new BreakAwayContext(ConfigurationManager.ConnectionStrings["BAContext"].ConnectionString))
                {
                    var dest = context.Destinations.Where(a => a.DestinationId == destIn.DestinationId).Single();
                    dest.Name = destIn.Name;
                    context.SaveChanges();
                }
            }
    
            public static void Delete(int destId)
            {
                using (var context = new BreakAwayContext(ConfigurationManager.ConnectionStrings["BAContext"].ConnectionString))
                {
                    var destination = new Destination() { DestinationId = destId };
                    context.Destinations.Attach(destination);
                    context.Destinations.Remove(destination);
    
                    context.SaveChanges();
                }
            }
    
    
            public static Destination Query(int destId)
            {
                using (var context = new BreakAwayContext(ConfigurationManager.ConnectionStrings["BAContext"].ConnectionString))
                {
                    IQueryable<Destination> dest = context.Destinations.Where(a => a.DestinationId == destId);
    
                    return dest.Single();
                }
            }

    4. 如果需要多个操作同时成功或者失败,需要手动开启事务,具体代码如下,

            public static void TransactionOps()
            {
                using (var context = new BreakAwayContext(ConfigurationManager.ConnectionStrings["BAContext"].ConnectionString))
                {
                    using (var dbContextTransaction = context.Database.BeginTransaction())
                    {
                        try
                        {
                            var destination = new Destination
                            {
                                Country = "Chs",
                                Description = "Chs is the language package",
                                Name = "xs2s"
                            };
    
                            var destId = context.Destinations.Add(destination);
    
                            context.SaveChanges();
    
                            context.Destinations.Attach(destId);
                            context.Destinations.Remove(destId);
    
                            context.SaveChanges();
    
                            dbContextTransaction.Commit();
                        }
                        catch (System.Exception ex)
                        {
                            dbContextTransaction.Rollback();
                            System.Console.WriteLine(ex.ToString());
                        }
                    }
                }
            }

    5. 分页查询是网站设计的常用功能,一个简单的真分页查询方法如下如下所示,

            public static List<Destination> QueryPaging<TKey>(int pageIndex, int pageSize, Expression<Func<Destination, bool>> whereLambda, Expression<Func<Destination, TKey>> orderBy)
            {
                using (var context = new BreakAwayContext(ConfigurationManager.ConnectionStrings["BAContext"].ConnectionString))
                {
                    return context.Destinations.Where(whereLambda).OrderBy(orderBy).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
                }
            }

    总结

    本文对最新版本的Entity Framework进行增删改查操作给出了详尽的解释,并且给出了数据库和领域模型代码分开设计的完整解决方案,同时介绍了手动数据库表和领域模型映射,数据库事务实现,分页查询等常用功能,希望对大家有所帮助。

  • 相关阅读:
    String
    Map和Set
    js的栈与堆
    js的私有属性
    随便谈一谈原型
    前端页面优化提速
    nth-child和nth-of-type
    重复输出字符串
    闭包
    mongodb内嵌文档的查询
  • 原文地址:https://www.cnblogs.com/pugang/p/8909414.html
Copyright © 2020-2023  润新知