前言

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

正文

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

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

比如说,我们的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的一个功能就是,当我们修改我们查询的值,那么就会帮我们生成语句。

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

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

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

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 的关系,因为有些人刚开始学的时候不知道什么是属于,什么是拥有,这两者到底什么区别呢?

ef 值转换与值比较器的更多相关文章

  1. EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态

    本文目录 查看实体当前.原始和数据库值:DbEntityEntry 查看实体的某个属性值:GetValue<TValue>方法 拷贝DbPropertyValues到实体:ToObject ...

  2. javascript 中关于对象转换数字值的一些特点

    下面是摘至<Javascript 高级程序设计第三版>里的一段话 是关于对象转换数字值的一些规则 "在应用于对象时,先调用对象的valueOf()方法以取得一个可供操作的值.然后 ...

  3. ios 把毫秒值转换成日期 NSDate

    ios 把毫秒值转换成日期 (比较好用) 1343359790000 这是毫秒值------最佳解决方案-------------------- long long time=134335979000 ...

  4. Web API-如何将Controller的返回值转换成HTTP response消息

    https://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization https://co ...

  5. c++ 弧度值与角度值的转换

    Rad_to_deg --- 弧度_到_角度 的 比率Rad_to_deg = 45.0 / atan(1.0): 弧度值到角度值的转换 用 角度 = 弧度值* Rad_to_deg 角度值到弧度值的 ...

  6. 分享:根据svg节点对象类型和路径值转换坐标值

    功能用处: 对svg文件的路径节点填充时会使用(相邻两个坐标区域内的四边形的填充颜色不重复). 需要对svg文件中的Path节点或者 Polyline 节点做颜色填充.并且相邻的两个区域之间的颜色不允 ...

  7. sql 在将 nvarchar 值 转换成数据类型 int 时失败。

    假设有存储过程:proc_test2 create proc proc_test2 @Id int begin as declare @sql varchar(max) @sql = 'select ...

  8. 不再迷惑,无值和NULL值的转换

    在关系型数据库的世界中,无值和NULL值的区别是什么?一直被这个问题困扰着,甚至在写TSQL脚本时,心有戚戚焉,害怕因为自己的一知半解,挖了坑,贻害后来人,于是,本着上下求索,不达通幽不罢休的决心(开 ...

  9. json字符串转换成json对象,json对象转换成字符串,值转换成字符串,字符串转成值

    一.json相关概念 json,全称为javascript object notation,是一种轻量级的数据交互格式.采用完全独立于语言的文本格式,是一种理想的数据交换格式. 同时,json是jav ...

  10. c++ 值转换

    1.double,float 四舍五入,保留小数位数. void MainWindow::on_pushButton_clicked() { double number=3.141592; ); qD ...

随机推荐

  1. 4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明

    4. Spring Cloud Ribbon 实现"负载均衡"的详细配置说明 @ 目录 4. Spring Cloud Ribbon 实现"负载均衡"的详细配置 ...

  2. 面试官:来谈谈Vue3的provide和inject实现多级传递的原理

    前言 没有看过provide和inject函数源码的小伙伴可能觉得他们实现数据多级传递非常神秘,其实他的源码非常简单,这篇文章欧阳来讲讲provide和inject函数是如何实现数据多级传递的.ps: ...

  3. 【Amadeus原创】修改docker里面网站的port端口映射

    切记:以下顺序千万不能颠倒!否则不生效! 1. 查看需要修改的容器,记住container id docker ps -a 2. 停止容器 docker stop xxx 3. 修改容器的端口映射配置 ...

  4. 百度地图各种控件:地图平移缩放控件NavigationControl、地图类型控件MapTypeControl

    注:代码复制即可用,标色代码为主要代码 百度地图提供了如下控件: 1.Control:控件的抽象基类,所有控件均继承此类的方法.属性.通过此类您可实现自定义控件. 2.NavigationContro ...

  5. Delon ACL

    Delon ACL delon ACL Alain acl 路由守卫 使用 ACLService 核心是 ACLService,See:https://github.com/ng-alain/delo ...

  6. Spring完全注解开发

    注解的好处:如果管理很多的Bean,要求这些Bean都配置在applocationContext.xml文件中.用了注解之后,就不需要在xml文件中配置了,Spring提供了几个辅助类会自动扫描和装配 ...

  7. Error: Application Server not specified

    在IDEA中tomcat不能运行,点开Edit Configuration发现如下图情况:tomcat图标猫上有个红叉,且下面有警告提示:Error: Application Server not s ...

  8. spring boot 配置多个DispatcherServlet

    传统的web项目,只需要在web.xml里配置多个即可,并且支持多个url-pattern 在spring boot中,我们默认无需配置,系统会自动装配一个,感兴趣的可以看下源码 org.spring ...

  9. Qt音视频开发04-保存音频文件(pcm/wav/aac)

    一.前言 音频的保存相对来说比视频的要简单,具有通用性,不需要经过ffmpeg的编码,ffmpeg解码出来后一般会转换成pcm原始的数据用来播放,所以对数据直接写文件即可,但是这种格式是无法用播放器直 ...

  10. Qt编写地图综合应用4-仪表盘

    一.前言 仪表盘在很多汽车和物联网相关的系统中很常用,最直观的其实就是汽车仪表盘,这个以前主要是机械的仪表,现在逐步改成了智能的带屏带操作系统的仪表,这样美观性和拓展性功能性大大增强了,上了操作系统的 ...