栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

EF.Core学习分享

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

EF.Core学习分享

转自Entity Framework Core Documentation And Tutorials | Learn Entity Framework Core 一.Home 1.efcore是什么?

微软的最新版本的实体框架。它是轻量级的、可扩展的,支持跨平台开发。
而且使用简单,性能超过先前版本的实体框架。

它是一个对象-关系映射框架(ORM)。
ORM是一种技术使开发者能够以面向对象语言的方式来工作,并以关系数据的方式来存储。

2.为什么使用ORM?

大多数的开发框架包含一些库,这些库通过数据结构这样的结果集来访问关系数据库。如以下:
using(var conn = new SqlConnection(connectionString))
using(var cmd = new SqlCommand("select * from Products", conn))
{
    var dt = new DataTable();
    using(var da = new SqlDataAdapter(cmd))
    {
        da.Fill(dt);
    }
}
DataTable里面的数据可以通过数字或字符串下标来访问,但必须从object类型转化为正确的类型。
foreach(DataRow row in dt.Rows)
{
    int productId = Convert.ToInt32(row[0]);
    string productName = row["ProductName"].ToString();
}
这种后期绑定获取“弱类型”的数据访问方式易于错误。问题通常发生于拼错列的名字,或者发现列的名字已经被数据端改变,或者sql语句的字段顺序的变化在代码端没有相应的变化。同样的,数据类型也可能错误。代码依然能编译通过,但运行时就会错误。因此,专业开发者更倾向于使用强数据类型来工作。

3.强数据类型


当使用强数据类型操作数据,是以这些面向对象的域模型的预定义类的属性的方式:
public class Product
{
    int ProductId { get; set; }
    string ProductName { get; set; }
}
int productId = myProduct.ProductId;
string productName = myProduct.ProductName;

一个域对象从数据库的获取和映射依然需要来做。一个可选的方式是自己写代码来管理。
但是,当域模型增长,代码量的需求也增长,接着会需要越来越多的开发时间来来维护。这个会增加完成整个应用程序完工的时间。

ORMs是预先写好的代码库来为你工作。完整特性的ORMs也做了很多事情。他们能:

*.映射域模型和数据库对象
*.创建数据库和维护数据库和模型的一致性
*.生成SQL语句并对数据库加以执行
*.管理事务
*.保持跟踪你以获取的对象


二.DbContext


1.ef.core DbContext表示和数据库的一次会话,并提供了一个API和数据库通讯,它拥有以下的能力:
*.数据库链接
*.数据库操作诸如查询和持久化
*.变化跟踪
*.模型建立
*.数据映射
*.对象缓存
*.事务管理

2.数据库链接
DbContext负责操作和管理连接数据库

3.数据操作
DbContext提供以下直接的数据操作方法:

1)增加数据
通过DbContext添加实体的关键方法:
 

Add(TEntity entity)
Add(object entity)
AddRange(IEnumerable entities)
AddRange(params object[] entities)

// with type parameter
var author = new Author{ FirstName = "William", LastName = "Shakespeare" };
context.Add(author);
context.SaveChanges();

// without type parameter
var author = new Author{ FirstName = "William", LastName = "Shakespeare" };
context.Add(author);
context.SaveChanges();

object author = new Author{ FirstName = "William", LastName = "Shakespeare" };
context.Add(author);
context.SaveChanges(); 

增加多个记录:
 

var context = new SampleContext();
var author = new Author { FirstName = "Stephen", LastName = "King" };
var books = new List {
    new Book { Title = "It", Author = author },
    new Book { Title = "Carrie", Author = author },
    new Book { Title = "Misery", Author = author }
};
context.AddRange(books);
context.SaveChanges();

var context = new SampleContext();
var author = new Author { FirstName = "William", LastName = "Shakespeare" };
var book = new Book { Title = "Adventures of Huckleberry Finn" };
context.AddRange(author, book);
context.SaveChanges();

2)修改数据

var author = context.Authors.First(a => a.AuthorId == 1);
author.FirstName = "Bill";
context.SaveChanges();

当实体从dbContext查询出来,便由变化跟踪者记录着(这个实体的字段的值的变化),当调用SaveChange时,并触发语句(只修改变化的字段)。

exec sp_executesql N'SET NOCOUNT ON;
UPDATe [Authors] SET [FirstName] = @p0
WHERe [AuthorId] = @p1;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 nvarchar(4000)',@p1=1,@p0=N'Bill'

实体的改变可能发生在Controller或service里面,dbContext要聪明的感知变化,并更新。

public void Save(Author author)
{
    context.Entry(author).State = EntityState.Modified;
    context.SaveChanges();
}

以上会更新所有的字段。

Update方法和UpdateRange方法:

public void Save(Author author)
{
    context.Update(author);
    context.SaveChanges();
}


会更新所有各个字段。

Attach:

var context = new TestContext();
var author = new Author {
    AuthorId = 1,
    FirstName = "William",
    LastName = "Shakespeare"
};
author.Books.Add(new Book {BookId = 1, Title = "Othello" });

context.Attach(author);
context.Entry(author).Property("FirstName").IsModified = true;
context.SaveChanges();

只有FirstName字段被标识为修改,所以更新语句只更新FirstName这个字段。

TrackGraph :

var author = new Author {
    AuthorId = 1,
    FirstName = "William",
    LastName = "Shakespeare"
};
author.Books.Add(new Book { AuthorId = 1, BookId = 1, Title = "Hamlet", Isbn = "1234" });
author.Books.Add(new Book { AuthorId = 1, BookId = 2, Title = "Othello", Isbn = "4321" });
author.Books.Add(new Book { AuthorId = 1, BookId = 3, Title = "MacBeth", Isbn = "5678" });

var context = new TestContext();
context.ChangeTracker.TrackGraph(author, e => {
    if((e.Entry.Entity as Author) != null)
    {
        e.Entry.State = EntityState.Unchanged;
    }
    else
    {
        e.Entry.State = EntityState.Modified;
    }
});
context.SaveChanges();

这个例子对应的SQL语句如下:

exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Books] SET [AuthorId] = @p0, [Isbn] = @p1, [Title] = @p2
WHERe [BookId] = @p3;
SELECT @@ROWCOUNT;
UPDATE [Books] SET [AuthorId] = @p4, [Isbn] = @p5, [Title] = @p6
WHERe [BookId] = @p7;
SELECT @@ROWCOUNT;
UPDATE [Books] SET [AuthorId] = @p8, [Isbn] = @p9, [Title] = @p10
WHERe [BookId] = @p11;
SELECT @@ROWCOUNT;
',N'@p3 int,@p0 int,@p1 nvarchar(4000),@p2 nvarchar(150),@p7 int,@p4 int,@p5 nvarchar(4000),
@p6 nvarchar(150),@p11 int,@p8 int,@p9 nvarchar(4000),@p10 nvarchar(150)',
@p3=1,@p0=1,@p1=N'1234',@p2=N'Hamlet',
@p7=2,@p4=1,@p5=N'4321',@p6=N'Othello',
@p113,@p8=1,@p9=N'5678',@p10=N'MacBeth'
var author = new Author {
    AuthorId = 1,
    FirstName = "William",
    LastName = "Shakespeare"
};
author.Books.Add(new Book { BookId = 1, Isbn = "1234" });
author.Books.Add(new Book { BookId = 2, Isbn = "4321" });
author.Books.Add(new Book { BookId = 3, Isbn = "5678" });

var context = new TestContext();
context.ChangeTracker.TrackGraph(author, e => {
    e.Entry.State = EntityState.Unchanged; //starts tracking
    if((e.Entry.Entity as Book) != null)
    {
        context.Entry(e.Entry.Entity as Book).Property("Isbn").IsModified = true;
    }
});

这个例子对应的SQL语句如下:

exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Books] SET [Isbn] = @p0
WHERe [BookId] = @p1;
SELECT @@ROWCOUNT;
UPDATE [Books] SET [Isbn] = @p2
WHERe [BookId] = @p3;
SELECT @@ROWCOUNT;
UPDATE [Books] SET [Isbn] = @p4
WHERe [BookId] = @p5;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 nvarchar(4000),@p3 int,@p2 nvarchar(4000),@p5 int,@p4 nvarchar(4000)',
@p1=1,@p0=N'1234',
@p3=2,@p2=N'4321',
@p5=3,@p4=N'5678'


3)删除数据

context.Remove(context.Authors.Single(a => a.AuthorId == 1));
context.SaveChanges();
exec sp_executesql N'SET NOCOUNT ON;
DELETE FROM [Authors]
WHERe [AuthorId] = @p0;
SELECt @@ROWCOUNT;
',N'@p0 int',@p0=1

以上的结果是执行两条语句:一条先获取记录,一条删除

var context = new SampleContext();
var author = new Author { AuthorId = 1 };
context.Remove(author);
context.SaveChanges();

而这个的结果是一条语句。

var context = new SampleContext();
var author = new Author { AuthorId = 1 };
context.Entry(author).State = EntityState.Deleted;
context.SaveChanges();

关联数据的删除:

public class Author
{
   public int AuthorId { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public ICollection Books { get; set; }
}

public class Book
{
   public int BookId { get; set; }
   public string Title { get; set; }
}


var context = new SampleContext();
var author = context.Authors.Single(a => a.AuthorId == 1);
var books = context.Books.Where(b => EF.Property(b, "AuthorId") == 1);//EF.core提供的一种叫做影子属性的东西来删除数据
foreach (var book in books)
{
    author.Books.Remove(book);
}
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Books] SET [AuthorId] = @p0
WHERe [BookId] = @p1;
SELECT @@ROWCOUNT;
UPDATE [Books] SET [AuthorId] = @p2
WHERe [BookId] = @p3;
SELECT @@ROWCOUNT;
UPDATE [Books] SET [AuthorId] = @p4
WHERe [BookId] = @p5;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 int,@p3 int,@p2 int,@p5 int,@p4 int',@p1=1,@p0=NULL,@p3=2,@p2=NULL,@p5=3,@p4=NULL

exec sp_executesql N'SET NOCOUNT ON;
DELETE FROM [Authors]
WHERe [AuthorId] = @p6;
SELECt @@ROWCOUNT;
',N'@p6 int',@p6=1

但是这种删除仅仅是把AuthId设置为null

三.Fluent API 配置


1.写在一起的的配置:

public class SampleContext : DbContext
{
    // Specify DbSet properties etc

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // add your own configuration here
        // series of statements
        modelBuilder.Entity().Property(t => t.OrderDate).IsRequired();
        modelBuilder.Entity().Property(t => t.OrderDate).HasColumnType("Date");
        modelBuilder.Entity().Property(t => t.OrderDate).HasDefaultValueSql("GetDate()");

        // fluent api chained calls
        modelBuilder.Entity()
            .Property(t => t.OrderDate)
                .IsRequired()
                .HasColumnType("Date")
                .HasDefaultValueSql("GetDate()");
            
    }
}


2:独立类的配置

public class OrderConfiguration : IEntityTypeConfiguration
{
    public void Configure(EntityTypeBuilder builder)
    {
    builder.HasKey(o => o.OrderNumber);
    builder.Property(t => t.OrderDate)
            .IsRequired()
            .HasColumnType("Date")
            .HasDefaultValueSql("GetDate())"
    }
}


应用只需要如下写:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyConfiguration(new OrderConfiguration());
}

四、数据注释属性Data Annotations Attributes

Table    
Column    
ForeignKey    
DatabaseGenerated    
NotMapped    
InverseProperty    
ComplexType    

Key    
Timestamp    
ConcurrencyCheck    
Required    
MaxLength    
StringLength

五、链接字符串
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer("server=.;database=myDb;trusted_connection=true;");
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext(options => {
        options.UseSqlServer("server=.;database=myDb;trusted_connection=true;"));
    });
}

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MyConnection": "server=.;database=myDb;trusted_connection=true;"
  }
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext(options => {
        options.UseSqlServer(Configuration.GetConnectionString("MyConnection"));
    });
}
六、继承
public class Contract
{
    public int ContractId { get; set; }
    public DateTime StartDate { get; set; }
    public int Months { get; set;}
    public decimal Charge { get; set; }
}

public class MobileContract : Contract
{
    public string MobileNumber { get; set; }
}

public class TvContract : Contract
{
    public PackageType PackageType { get; set; }
}

public class BroadBandContract : Contract
{
    public int DownloadSpeed { get; set; }
}

public enum PackageType
{
    S, M, L, XL
}

1)Table Per Hierarchy (TPH)
这种方式是当前EFcore的仅有的实现方式

public class SampleContext : DbContext
{
    public DbSet Contracts { get; set; }
    public DbSet MobileContracts { get; set; }
    public DbSet TvContracts { get; set; }
    public DbSet BroadBandContracts { get; set; }
}


可以直接访问:

var mobileContracts = context.MobileContracts.ToList();


public class SampleContext : DbContext
{
    public DbSet Contracts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity();
        modelBuilder.Entity();
        modelBuilder.Entity();
    }
}

转换访问:

var tvContracts = context.Contracts.OfType().ToList();

public class SampleContext : DbContext
{
    public DbSet MobileContracts { get; set; }
    public DbSet TvContracts { get; set; }
    public DbSet BroadbandContracts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity().ToTable("Contracts");
    }
}
    
public abstract class Contract
{
    public int ContractId { get; set; }
    public DateTime StartDate { get; set; }
    public int Months { get; set;}
    public decimal Charge { get; set; }
}

public class MobileContract : Contract
{
    public string MobileNumber { get; set; }
}

public class TvContract : Contract
{
    public PackageType PackageType { get; set; }
}

public class BroadbandContract : Contract
{
    public int DownloadSpeed { get; set; }
}

public enum PackageType
{
    S, M, L, XL
}

没有DbSet的写法:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
            .ToTable("Contracts")
            .HasDiscriminator("ContractType")
            .HasValue(1)
            .HasValue(2)
            .HasValue(3);
}


2)Table Per Type (TPT)


3)Table Per Concrete Type (TPC)

七、并发管理

1.后进有效
以最后更新的为准

2.悲观者
对访问的对象先加锁

3.乐观者
可能会异常产生。EFCore采取的是这种方式。

(比如:有两个用户修改同一个记录,第一个用户添加一个未设置的电话号码,第二个用户修改这条记录的地址,两者同时获取了这条记录,是一样的。假设第一个用户先提交了,电话被设置。但是第二个用户获取的记录的电话是空字段,后者提交后,电话被置为空了。这样就不符合预期了。)

为了使这种不合预期长生异常可以如下操作:

1)可以通过特性设置并发属性:

public class Author
{
    public int AuthorId { get; set; }
    public string FirstName { get; set; }
    [ConcurrencyCheck]
    public string LastName { get; set; }
    public ICollection Books { get; set; }
}

public class SampleContext : DbContext
{
    public DbSet Authors { get; set; }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
         modelBuilder.Entity()
            .Property(a => a.LastName).IsConcurrencyToken();
    } 
}


2)增加一个RowVersion属性

public class Author
{
    public int AuthorId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public ICollection Books { get; set; }
    [TimeStamp]
    public byte[] RowVersion { get; set; }
}

public class SampleContext : DbContext
{
    public DbSet Authors { get; set; }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
         modelBuilder.Entity()
            .Property(a => a.RowVersion).IsRowVersion();
    } 
}
public class Author
{
    public int AuthorId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public ICollection Books { get; set; }
    public byte[] RowVersion { get; set; }
}

八、数据迁移

1.创建
[Command Line]
dotnet ef migrations add

[Package Manager console]
add-migration

2.删除
[Command Line]
dotnet ef migrations remove

[Package Manager Console]
remove-migration

3.应用
Applying A Migration 
[Command line]
dotnet ef database update

[Package Manager Console]
update-database

4、反转
[Command line]
dotnet ef database update Create

[Package Manager Console]
update-database Create

5、应用一次迁移到远程数据库
[Command Line]
dotnet ef migrations script

[Package Manager Console]
script-migration using the -to and -from options.
 
 6.执行自定义SQL

public partial class CreateDatabase : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.Sql("Some custom SQL statement");

        migrationBuilder.CreateTable(
            name: "Authors",
            columns: table => new
            {
                AuthorId = table.Column(nullable: false)
                    .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                FirstName = table.Column(nullable: true),
                LastName = table.Column(nullable: true)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Authors", x => x.AuthorId);
            });
 


7.对应多个提供给者

public partial class CreateDatabase : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {

        if(ActiveProvider == "Microsoft.EntityFrameworkCore.SqlServer")
        {
            // do something SQL Server - specific
        }
        if(ActiveProvider == "Microsoft.EntityFrameworkCore.Sqlite")
        {
            // do something SqLite - specific
        }

        migrationBuilder.CreateTable(
            name: "Authors",
            columns: table => new
            {
                AuthorId = table.Column(nullable: false)
                    .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                FirstName = table.Column(nullable: true),
                LastName = table.Column(nullable: true)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Authors", x => x.AuthorId);
            });
            


8.设置迁移的超时时间
 

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;

namespace EFCoreSample.Model
{
    public class SampleContextFactory : IDesignTimeDbContextFactory
    {
        public SampleContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder();
            optionsBuilder.UseSqlServer(@"Server=.;Database=db;Trusted_Connection=True;", opts => opts.CommandTimeout((int)TimeSpan.FromMinutes(10).TotalSeconds));

            return new SampleContext(optionsBuilder.Options);
        }
    }
}


Make sure that your existing DbContext has a constructor that takes a DbContextOptions object as a parameter:(确保你已有的DbContext构造函数有一个DbContextOptions参数)

public AdventureContext(DbContextOptions options) : base(options){}

九、执行原始SQL语句

public class Book
{
    public int BookId { get; set; }
    public string Title { get; set; }
    public Author Author { get; set; }
    public int AuthorId{ get; set; }
    public string Isbn { get; set; }
}

...

public class SampleContext : DbContext
{
    public DbSet Books { get; set; }
}
...
using (var context = new SampleContext())
{
    var books = context.Books.FromSqlRaw("SELECt BookId, Title, AuthorId, Isbn FROM Books").ToList();
}


带参数的查询:

// Format string
var author = db.Authors.FromSqlRaw("SELECt * From Authors Where AuthorId = {0}", id).FirstOrDefault();

// String interpolation
var author = db.Authors.FromSqlInterpolated($"SELECt * From Authors Where AuthorId = {id}").FirstOrDefault();

var p1 = new SqliteParameter("@Id", id);
var author = db.Authors.FromSqlRaw($"SELECt * From Authors Where AuthorId = @Id", p1).FirstOrDefault();

var p1 = new SqlParameter("@Id", id);
var author = db.Authors.FromSqlRaw($"SELECt * From Authors Where AuthorId = @Id", p1).FirstOrDefault();

存储过程:

using (var context = new SampleContext())
{
    var books = context.Books
        .FromSqlRaw("EXEC GetAllBooks")
        .ToList();
}

using (var context = new SampleContext())
{
    var authorId = new SqlParameter("@AuthorId", 1);
    var books = context.Books
        .FromSqlRaw("EXEC GetBooksByAuthor @AuthorId" , authorId)
        .ToList();
}

非实体类型的投影:

using(var context = new SampleContext())
{
    var books = context.Books.FromSqlRaw("SELECt BookId, Title FROM Books").ToList();
}


这个在ef.core2.1之前是不允许的,但是可以通过投影:
using(var context = new SampleContext())

{
    var books = context.Books
        .FromSql("SELECt * FROM Books")
        .Select(b => new {
            BookId = b.BookId,
            Title = b.Title 
            }).ToList();
}
ExecuteSqlCommand:
using(var context = new SampleContext())
{
    var commandText = "INSERT Categories (CategoryName) VALUES (@CategoryName)";
    var name = new SqlParameter("@CategoryName", "Test");
    context.Database.ExecuteSqlCommand(commandText, name);
}


Note: You will need to add using Microsoft.Data.SqlClient; to make the SqlParameter type available to your code.
存储规程:

using(var context = new SampleContext())
{
    var name = new SqlParameter("@CategoryName", "Test");
    context.Database.ExecuteSqlCommand("EXEC AddCategory @CategoryName", name);
}

通过返回connection给ADO.net使用:
 

using (var context = new SampleContext())
using (var command = context.Database.GetDbConnection().CreateCommand())
{
    command.CommandText = "SELECT * From Table1";
    context.Database.OpenConnection();
    using (var result = command.ExecuteReader())
    {
        // do something with result
    }
}

十、Query Types查询类型


2.1以后:Mapping to DbQuery
 

public class Customer
{
    public int CustomerId { get; set; }
    public string Name { get; set; }
    public ICollection Orders { get; set; } = new HashSet();
}

public class Order
{
    public int OrderId { get; set; }
    public DateTime DateCreated { get; set; }
    public int CustomerId { get; set; }
    public Customer Customer { get; set; }
    public ICollection OrderItems { get; set; } = new HashSet();
}

public class OrderItem
{
    public int OrderItemId { get; set; }
    public string Item { get; set; }
    public decimal Price { get; set; }
}
create view OrderHeaders as
    select      c.Name as CustomerName, 
                o.DateCreated, 
                sum(oi.Price) as TotalPrice, 
                count(oi.Price) as TotalItems
    from        OrderItems  oi 
                inner join Orders o on oi.OrderId = o.OrderId
                inner join Customers c on o.CustomerId = c.CustomerId
    group by oi.OrderId, c.Name, o.DateCreated

public class OrderHeader
{
    public string CustomerName { get; set; }
    public DateTime DateCreated { get; set; }
    public int TotalItems { get; set; }
    public decimal TotalPrice { get; set; }
}

public class SampleContext : DbContext
{
    public DbSet Orders { get; set; }
    public DbSet OrderItems { get; set; }
    public DbSet Customers { get; set; }

    public DbQuery OrderHeaders { get; set; }

    ...
}

var orderHeaders = db.OrderHeaders.ToList();

var orderHeaders = db.OrderHeaders.Where(x => x.TotalItems > 15).ToList();

[SampleContext.cs]
public partial class SampleContext : DbContext
{
    public DbSet Orders { get; set; }
    public DbSet OrderItems { get; set; }
    public DbSet Customers { get; set; }

    ...
}
[SampleContextDbQuery.cs]
public partial class SampleContext : DbContext
{
    public DbQuery OrderHeaders { get; set; }
    public DbQuery OrderTotals { get; set; }
    ...
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Query().ToView("OrderHeaders");
}

select      c.Name as CustomerName, 
            c.CustomerId,
            o.DateCreated, 
            sum(oi.Price) as TotalPrice, 
            count(oi.Price) as TotalItems
from        OrderItems  oi 
            inner join Orders o on oi.OrderId = o.OrderId
            inner join Customers c on o.CustomerId = c.CustomerId
group by oi.OrderId, c.Name, o.DateCreated

public class OrderHeader
{
    public string CustomerName { get; set; }
    public DateTime DateCreated { get; set; }
    public int TotalItems { get; set; }
    public decimal TotalPrice { get; set; }
    public Customer Customer { get; set; }
}

var orderHeaders = db.Query().Include(o => o.Customer).ToList();

var orderHeaders = db.OrderHeaders.FromSql(
                    @"select c.Name as CustomerName, o.DateCreated, sum(oi.Price) as TotalPrice, 
                    count(oi.Price) as TotalItems
                    from  OrderItems  oi 
                    inner join Orders o on oi.OrderId = o.OrderId
                    inner join Customers c on o.CustomerId = c.CustomerId
                    group by oi.OrderId, c.Name, o.DateCreated");

十一、延迟加载

1.Proxies
1)
[Package Manager Console]
install-package Microsoft.EntityFrameworkCore.Proxies
[Dotnet CLI]
add package Microsoft.EntityFrameworkCore.Proxies
2).

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseLazyLoadingProxies();
}


3)

public class Author
{
    public int AuthorId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public virtual List Books { get; set; } = new List();
}

public class Book
{
    public int BookId { get; set; }
    public string Title { get; set; }
    public int AuthorId { get; set; }
    public virtual Author Author { get; set; }
}

2.ILazyLoader 

using Microsoft.EntityFrameworkCore.Infrastructure;

public class Author
{
    private readonly ILazyLoader _lazyLoader;

    public Author()
    {
    }

    public Author(ILazyLoader lazyLoader)
    {
        _lazyLoader = lazyLoader;
    }

    private List _books;
    public int AuthorId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List Books
    {
        get => _lazyLoader.Load(this, ref _books);
        set => _books = value;
    }
}

using(var db = new BookContext())
{
    var authors = db.Authors;
    foreach(var author in authors)
    {
        Console.WriteLine($"Name: {author.FirstName} {author.LastName}");
        foreach(var book in author.Books) // lazy loading initiated
        {
            Console.WriteLine($"t{book.Title}");
        }
    }
}

var authors = db.Authors.Include(a => a.Books); //一次加载,解决n+1次查询问题
foreach(var author in authors)
{
    Console.WriteLine($"Name: {author.FirstName} {author.LastName}");
    foreach(var book in author.Books)
    {
        Console.WriteLine($"t{book.Title}");
    }
}

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号