ef 值转换与值比较器

前言

简单介绍一下,值转换器和值比较器。

正文

为什么有值转换器这东西呢?

那就是这个东西一直必须存在。

比如说,我们的c# enum 对应数据库的什么呢? 是int还是string呢?

一般情况下,我们没有去写enum,保存数据库里面了一个int对吧。

那么到底谁干了这件事呢? 显然ef 是有默认的值转换器的对吧,这点是肯定的。

问题又来了,既然是有默认的值转换器,那么我的需求是不用默认的呢?

比如说:

public enum TestEnum {     First,     Second,     Third,     Fourth } 

我想存string 怎么办呢? 为什么存string哈,姑且就说为了方便数仓清洗这一个理由,总有业务需求的嘛。

那么就需要这么做:

modelBuilder.Entity<Rider>() .Property(e=> e.TestEnum) .HasConversion( 	v=> v.ToString(), 	v => (TestEnum)Enum.Parse(typeof(TestEnum), v)); 

这样就可以转换成string了。

还有一个问题,那就是比如说对象映射,同一个类型的对象,会是同一中映射,比如都映射成string或者decimal,但是多个地方使用,那怎么办呢?

public class CurrencyConverter : ValueConverter<Currency, decimal> {     public CurrencyConverter()         : base(             v => v.Amount,             v => new Currency(v))     {     } } 
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) {     configurationBuilder         .Properties<Currency>()         .HaveConversion<CurrencyConverter>(); } 

嗯,还有一个问题,那就是比如说对象映射,同一个类型的对象,会是同一中映射,比如都映射成string或者decimal,但是只有一个类中多次使用呢?

如果是这样重新创建一个类,似乎不太优雅,封装性不够呀,其实我用谈一些什么封装啊啥的,就最简单一点就是不该知道的不要知道,这样大家都省心。

protected override void OnModelCreating(ModelBuilder modelBuilder) {     var converter = new ValueConverter<EquineBeast, string>(         v => v.ToString(),         v => (EquineBeast)Enum.Parse(typeof(EquineBeast), v));      modelBuilder         .Entity<Rider>()         .Property(e => e.Mount)         .HasConversion(converter); } 

这样在内部创建ValueConverter 就可以了。

那么我们来看一些内部默认的怎么写的:

var converter = new BoolToZeroOneConverter<int>();  modelBuilder 	.Entity<Rider>() 	.Property(e => e.TestBool) 	.HasConversion(converter); 

看下BoolToZeroOneConverter怎么写的哈:

ef 值转换与值比较器

就是不同类型的转换哈,很多判断,就不看了。

当然还有非常多知识,但是用不到的知识,暂时就不用去学,生活很美好,不是吗?

然后一个值比较器,这个是啥子东西呢?

我们都知道ef的一个功能就是,当我们修改我们查询的值,那么就会帮我们生成语句。

首先,最实现最傻的方式,全部更新一遍,但是显然这效率感人吧。

那么优化下,就是字段更新的,才生成更新语句。

这个思路似乎可行,那么就出现了值比较器。

modelBuilder.Entity<Rider>() 	.Property(e=> e.TestList) 	.HasConversion( 		v=> JsonSerializer.Serialize(v, (JsonSerializerOptions)null), 		v => JsonSerializer.Deserialize<List<string>>(v, (JsonSerializerOptions)null), 		new ValueComparer<List<string>>( 			(c1, c2)=>c1.SequenceEqual(c2), 			c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())), 			// c tolist 的话就是复制一份 			c => c.ToList() 			)); 

为什么这里list要写这种比较呢?

那肯定是有默认的呗,默认的就是两者是否是同一个对象,如果默认情况下,引用类型赋值指向的是同一个地方,
那么你猜猜是否相同呢?

答案肯定是相同的,那么可以自定义。

ValueComparer 构造函数接受三个表达式:

  1. 用于检查相等性的表达式
  2. 用于生成哈希代码的表达式
  3. 用于截取值的快照的表达式

第一个和第二个肯定要必须存在的,比较是否相同嘛,我们知道hash和equal都是一起的,至于为什么后面equal章节会写的。

然后为什么有一个截取表达式,这个是因为其实c => c.ToList()是c进行一个快照,好为了跟后面对比,如果直接是c => c,那么无论后面增删改查都是对同一个对象比较。

大致描述了一下ef中比较重要的两个东西,下一节介绍一下ef 的关系,因为有些人刚开始学的时候不知道什么是属于,什么是拥有,这两者到底什么区别呢?

发表评论

评论已关闭。

相关文章