首页 > 其他分享 >跟着杨中科学习(七)EFCore(五)

跟着杨中科学习(七)EFCore(五)

时间:2024-06-17 17:11:19浏览次数:18  
标签:builder 实体 ctx 中科 EFCore var 数据库 跟着

EFCore的异步

异步方法大部分是定义在Microsoft.EntityFrameworkCore这个命名空间下EntityFrameworkQueryableExtensions等类中的扩展方法,记得using。

如何异步遍历IQueryable

  • 使用ToListAsync()、ToArrayAsync()。但是注意结果集不要太大。
foreach (var a in await ctx. Articles. ToListAsync())
{
    Console. WriteLine(a. Title);
}
  • 使用await foreach(Book b inctx.Books.AsAsyncEnumerable())
await foreach (var a in ctx. Articles. AsAsyncEnumerable ())
{
	Console. WriteLine(a. Title);
}

EfCore执行非查询原生 SQL语句

使用dbCtx.Database. ExecuteSqllnterpolated ()
dbCtx.Database.ExecuteSqllnterpolatedAsync()方法来执
行原生的非查询SQL语句。

可以用来执行增删改

ctx.Database.ExecuteSqlInterpolatedAsync(@$"in
sert into T_Books(Title,PubTime,Price,AuthorName)
select Title, PubTime, Price,{aName} from T_Books
where Price > {price}");

FormattableString类型可以避免sql注入

还有一个ExecutesqlRow方法,类似于以前的sqlHelp

EFCore执行实体相关的原生查询sql语句

如果要执行的原生SQL是一个查询语句,并且查询的结
果也能对应一个实体,就可以调用对应实体的DbSet的
FromSqllnterpolated()方法来执行一个查询SQL语句,同样
使用字符串内插来传递参数。

只能执行单表查询

IQueryable<Book> books =
ctx.Books.FromSqlInterpolated(@$"select * from T_Books
where DatePart(year,PubTime)>{year}order by newid()");
  • SQL 查询必须返回实体类型对应数据库表的所有列;
  • 结果集中的列名必须与属性映射到的列名称匹配。
  • 只能单表查询,不能使用Join语句进行关联查询。但
    是可以在查询后面使用Include()来进行关联数据的获
    取。

EFCore执行纯原生的查询语句

直接通过EFCore连接ADO.NET,获得数据库连接对象

dbCxt.Database.GetDbConnection()获得ADO.NET Core的数据库连接对象。

DbConnection conn = ctx.Database.GetDbConnection();
if (conn.State != ConnectionState.Open)
{
    conn.Open();
}
using (var cmd = conn.CreateCommand())
{
    cmd.CommandText =@"xxx";
    var pl = cmd.CreateParameter();
    p1.ParameterName ="@year";
    pl.Value = year;
    cmd.Parameters.Add(p1);
    using (var reader = cmd.ExecuteReader());
}
using(MyDbContext ctx=new MyDbContext())
{
    DbConnection conn = ctx.Database.GetDbConnection();//拿到Context对应的底层的Connection
    if(conn. State != System. Data. ConnectionState. Open)
    {
        await conn. OpenAsync ();
    }
    using (var cmd = conn. CreateCommand ())
    {
        cmd. CommandText = "select Price, Count(*) from T_Articles group by Price";
        using fvar reader = await cmd. ExecuteReaderAsync ())
        {
            while (await reader. ReadAsync ())
            {
                double price =reader. GetDouble(0);
                int count =reader.GetInt32(1);
                Console. WriteLine($"{price}:{count}");
            }
        }
    }
}

推荐使用

Dapper等矿建执行原生复杂的sql语句。

如何知道实体数据变了

只要一个实体对象和Dbcontext发生关联,EFCore就会自动跟踪这个实体的值的变化。

在执行钱,会记录实体的快照,在执行结束后,会对比快照的变化

实体的状态

  • 已添加(Added):DbContext正在跟踪此实体,但数据库中尚不存在
    该实体。
  • 未改变(Unchanged):DbContext正在跟踪此实体,该实体存在于数据
    库中,其属性值和从数据库中读取到的值一致,未发生改变
  • 已修改(Modified):DbContext正在跟踪此实体,并存在于数据库中,
    并且其部分或全部属性值已修改。
  • 已删除(Deleted):DbContext正在跟踪此实体,并存在于数据库中,
    但在下次调用SaveChanges时要从数据库中删除对应数据。
  • 已分离(Detached):DbContext未跟踪该实体。

EFCore优化值AsNoTracking

不让EFCore进行自动跟踪

var items = ctx. Articles. AsNoTracking (). Take (3)T;
foreach (var e in items)
{
    Console. WriteLine(e. Message);
}

实体状态跟踪的妙用

不推荐使用,不利于维护

Book bl=new Book{Id=10};//跟踪通过Id定位
b1.Title = "yzk";
var entry1 = ctx.Entry(b1);
entryl.Property("Title").IsModified = true;
Console.WriteLine(entry1.DebugView.LongView);
ctx.SaveChanges();

数据的批量删除、更新、插入

addRange()后加Range表示循环批量执行sql语句。

全局查询筛选器

public void Configure (EntityTypeBuilder<Article> builder)
{
    builder. ToTable("T_Articles");
    builder. Property(a => a.Title). HasMaxLength(100). IsUnicode (). IsRequired() ;
    builder. Property(a => a. Message). IsUnicode (). IsRequired();
    builder. HasMany (a => a. Comments). WithOne(c => c. TheArticle). HasForeignKey(c =>c.TheArticleId).IsRequired();
    builder. HasQueryFilter(a=>a. IsDeleted=false;
}

忽略查询过滤器

ctx.Books.lgnoreQueryFilters().Where(b=>b.Title.Contains("o")).ToArray()

有性能陷阱

EFCore悲观并发控制

并发控制:避免多个用户同时操作资源造成并发冲突问题。举例:网上购买车票。

最好的解决方案:非数据库解决方案,也就是在程序逻辑方面解决

数据库层面的两种策略:悲观和乐观。

悲观:给车票上锁,只能我买完其他人才能买

悲观控制一般使用行锁或者表锁

EF Core没有封装悲观并发控制的使用,需要开发
人员编写原生SQL语句来使用悲观并发控制。不同数
据库的语法不一样。

Mysql

select * from T_Home where Id=1 for update
select ... for update 为锁,执行后会释放
using(MyDbContext ctx=new MyDbContext())
using(var tx=ctx.Database.BeginTransaction())
{
	var h = ctx. Houses.FromSqlInterpolated($"select * from T_Houses where
	Id=1 for update"). Single();
	ctx.SaveChange();//运行完释放
	tx.Commit();
}


乐观并发控制

乐观:并发令牌

Update T_Home set Owner is 新值 where Id=1 and Owner is 旧值

把被并发修改的属性使用IsConcurrencyToken()设置为并发令
牌。

builder.Property(h => h.Owner).IsConcurrencyToken();
using(MyDbContext ctx =new MyDbContext())
{
    var h=ctx.House.Single(h=>h.id==1);
    h.Owner=name;
    try
    {
        cty.SaveChanges();
    }
    catch(DbUpdateConcurrencyException ex)
    {
        //主线程捕获不到异步的异常,所以需要处理子线程的异常
        var entry = ex.Entries.First();
        var dbValues = await entry.GetDatabaseValuesAsync();
        string newOwner = dbValues.GetValue<string>(nameof(Hose.Owner));
        dbValues.GetValue<string>(nameof(House.Owner));
        Console.WriteLine($"并发冲突,被{newOwner}提前抢走了”);
    }
}

RowVersion

使用情景:一个实体内,有很多个字段都不可以并发修改。

  1. SQLServer数据库可以用一个byte[]类型的属性做并
    发令牌属性,然后使用IsRowVersion()把这个属性设置
    为RowVersion类型,这样这个属性对应的数据库列就
    会被设置为ROWVERSION类型。对于ROWVERSION类型
    的列,在每次插入或更新行时,数据库会自动为这一
    行的ROWVERSION类型的列其生成新值。
  2. 在SQLServer中,timestamp和rowversion是同一种
    类型的不同别名而已。

在实体类上增加RowVersion

class House
{
	public log Id {get;set;}
    public string Name {get;set;}
    public string Owner {get;set;}
    public byte[] RowVersion {get;set;}
}

配置实体类的配置项,设置并发属性

class HouseConfig : IEntityTypeConfiguration<House>
{
    public void Configure (EntityTypeBuilder<House> builder)
    {
        builder. ToTable("T_Houses");
        builder. Property (b => b. Name). IsRequired();
        builder. Property(b => b. RowVersion). IsRowVersion();
    }
   
}

更改代码和上面就一样了

EFCore表达式树

先跳过了

标签:builder,实体,ctx,中科,EFCore,var,数据库,跟着
From: https://www.cnblogs.com/guan-tou6/p/18252780

相关文章

  • 跟着杨中科学习(六)EFCore(四)
    自引用的组织结构树classOrgUnit{publiclongId{get;set;}publiclong?ParentId{get;set;}publicstringName{get;set;}publicOrgUnit?Parent{get;set;}publicList<OrgUnit>Children{get;set;}=newList<OrgUnit&g......
  • 【Nature子刊】最争气国人友好“灌水刊”,中科院3区升2区,录用仅1个月,2天见刊!
    本周投稿推荐SSCI• 中科院2区,6.0-7.0(录用友好)EI•各领域沾边均可(2天录用)CNKI•7天录用-检索(急录友好)SCI&EI•4区生物医学类,0.5-1.0(录用率99%)•1区工程类,6.0-7.0(进展超顺)•IEEE(TOP),7.5-8.0(实力强刊)期刊亮点中科院3区升2区,期刊质量持续攀升;收稿量庞大,接受......
  • 跟着杨中科学习(五)EFCore(三)
    通过代码查看EFCore自动生成的数据1.标准日志//依赖注入的使用方式publicstaticreadonlyILoggerFactoryMyLoggerFactory=LoggerFactory.Create(builder=>{builder.AddConsole();});optionsBuilder.UseLoggerFactory(MyLoggerFactory);//普通方式classMyDbCo......
  • 无线通信SCI期刊,中科院一区TOP,IF=12.9,专业性强,文章质量高
    一、期刊名称IEEEWirelessCommunications二、期刊简介概况期刊类型:SCI学科领域:无线通信影响因子:12.9中科院分区:1区TOP三、期刊征稿范围IEEE无线通信是为在通信和网络社区工作的个人设计的。它涵盖了与所有媒体(以及媒体组合)和所有协议层的个性化、位置独立通信相......
  • 计算机SCI期刊,中科院3区,IF=3.4,难度不大,无预警风险
    一、期刊名称AutomatedSoftwareEngineering二、期刊简介概况期刊类型:SCI学科领域:计算机科学影响因子:3.4中科院分区:3区三、期刊征稿范围自动化软件工程是一份档案,同行评审的期刊,发表研究,教程论文,调查和自动化软件工程技术的基础,技术,工具和应用方面的重要行业经验......
  • 能源SCI期刊,中科院1区TOP,IF=8.7,审稿速度快,对国人非常友好
    一、期刊名称RenewableEnergy二、期刊简介概况期刊类型:SCI学科领域:能源影响因子:8.7中科院分区:1区TOP三、期刊征稿范围《可再生能源》杂志旨在促进和传播有关可再生能源系统和组件的各种主题和技术的知识。该杂志旨在为研究人员,工程师,经济学家,制造商,非政府组织,协会......
  • 大学体育(二)(华中科技大学) 中国大学MOOC答案2024版100分完整版
    大学体育(二)(华中科技大学)中国大学MOOC答案2024版100分完整版有氧运动有氧运动单元测验1、世界卫生组织对18-64岁年龄组成年人的运动建议是:每周至少()分钟的中等强度有氧身体活动,或者每周至少()分钟的较高强度有氧身体活动,或中等和较高强度两种活动相当量的组合。A:150......
  • 跟着GPT学习Java线程中断机制
    Java中的线程中断是一个复杂但非常重要的概念,它允许一个线程告知另一个线程希望它停止正在做的事情。这个机制是协作式的,意味着被请求中断的线程需要自己检查中断状态,并且决定如何响应中断请求。下面我将系统地讲解Java中的线程中断知识点。 1.中断标志每个线程都有一个内部......
  • 跟着杨中科学习(四)EFCore(二)
    主键自增主键自动增长。优点:简单;缺点:数据库迁移以及分布式系统中比较麻烦;并发性能差。long、int等类型主键,默认是自增。因为是数据库生成的值,所以SaveChanges后会自动把主键的值更新到Id属性。试验一下。场景:插入帖子后,自动重定向帖子地址。自增字段的代码中不能......
  • 计算机SCI期刊,中科院2区,IF=6.9,收稿范围非常广泛
    一、期刊名称JournalofKingSaudUniversity—ComputerandInformationSciences二、期刊简介概况期刊类型:SCI学科领域:计算机科学影响因子:6.9中科院分区:2区三、期刊征稿范围《沙特国王大学计算机与信息科学杂志》是一本国际性的参考期刊,涵盖了计算机基础及其实......