//转换方式一 //var blogIds = string.Join(",", ids); blogIds = string.Empty; foreach (var id in ids) { blogIds += $; } blogIds = blogIds.TrimEnd(); , CancellationToken.None);
但是利用$符号本质无非是简化了string.format的书写罢了,容易导致SQL注入的问题,但是利用参数化SQL对于WHERE....IN情况就是无法进行更新,对于删除亦是如此,上述未曾演示利用SqlParameter来进行更新,如果你这样做了,结果依然一样不好使:
var blogIds = string.Empty; foreach (var id in ids) { blogIds += $; } blogIds = blogIds.TrimEnd(); var parameters = new SqlParameter[] { ,System.Data.SqlDbType.NVarChar,400){ Value = blogIds } }; , CancellationToken.None, parameters);
上述是对于更新的主键为INT的情况,若是主键为字符串,此时这种情况更加突出,因为对于字符串形式需要这样的格式IN('A','B','C'),此时我们将上述id看作为字符串,我们进行如下转换:
+ , ids) + ;
然后去进行更新,参数正确,格式也正确,但是就是无法进行更新。最终统一得出的结论是:
进行批量更新或者删除的情况利用WHERE....IN参数化SQL无法进行更新或者删除,利用$或者string.format进行拼接却好使,但是会导致SQL注入。
上述演示EF Core版本为1.1.2,遇到这样的问题是在进行批量删除时,有人反问了批量删除不是有RemoveRange么,但是其中涉及到多表查询然后进行批量删除,就是期望达到一步到位的效果,最终没有办法,我采用LINQ的方法利用两步来进行批量删除,看到此文的你对于EF Core中利用SQL(WHERE....IN)命令来进行批量删除或者更新的情况见解是怎样,是否有遇到这样的问题,如果利用参数化SQL解决了问题的话望告知。
彩蛋 EntityFramework Core Shadow Property(狭隘属性)在EF Core系列中介绍过EF Core中几个新特性比如可选键作为除主键外的唯一约束,BackFileds,关于BackFieds未曾用到也差不多忘记了,本节我们介绍一下EF Core漏掉的狭隘属性。
狭隘属性不是实体类的一部分,所以不存在于实体类中但是存在于实体模型中,那么到底该如何使用狭隘属性呢?使用狭隘属性主要在以下两个场景。
(1)当不想对实体类作出更改,但是需要添加一些字段到实体模型中。
(2)明确知道该属性是上下文中的一部分,但是不希望暴露这些属性。
例如在Blog实体类中存在如何字段和导航属性。
public class Blog : IEntityBase { public int Id { get; set; } public string Name { get; set; } public string Url { get; set; } public byte Status { get; set; } public IEnumerable<Post> Posts { get; set; } }
常见场景:现在我们需要添加一个属性创建时间作为狭隘属性,此创建时间只有在实体添加状态时才有其值,其他状态值不发生改变且无需对外暴露,此时我们在映射中进行配置保持实体类洁净,如下:
Map(EntityTypeBuilder<Blog> b) { b.ToTable(); b.HasKey(k => k.Id); b.Property(p => p.Url); b.Property(p => p.Name); b.Property(p => p.Status).HasColumnType().IsRequired(); }
那么如何对CreatedTime进行设置值和获取值呢?Change Tracker API负责维护狭隘属性,当我们创建Blog时为其狭隘属性赋值,如下:
public async Task<bool> Create() { , Status = }; _efCoreContext.Entry(blog).Property().CurrentValue = DateTime.Now; if (await _efCoreContext.SaveChangesAsync(CancellationToken.None) > 0) { return true; } return false; }
由于对于大部分情况下都有其创建时间这一列,我们放在SaveChanges方法中并将其重写,如下:
SaveChanges() { var modifiedEntries = ChangeTracker .Entries().Where(x => x.State == EntityState.Added); foreach (var item in modifiedEntries) { item.Property().CurrentValue = DateTime.Now; } return base.SaveChanges(); } Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken)) { var modifiedEntries = ChangeTracker .Entries().Where(x => x.State == EntityState.Added); foreach (var item in modifiedEntries) { item.Property().CurrentValue = DateTime.Now; } .SaveChangesAsync(); }
此时创建Blog则改写为如下: