ABP天坑--UOW自动保存修改

2024-02-01 07:48
文章标签 保存 自动 修改 abp 天坑 uow

本文主要是介绍ABP天坑--UOW自动保存修改,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ABP项目也做了挺久了,实际上也没碰上太多的问题,但这两天被ABP的自动保存修改(Automatically Saving Changes)这个天坑给恶心坏了

因为项目设计上的问题,原先为了方便加上环境限制,没有文件服务器来进行文件持久化服务,这样多个系统之间如何共享文件就成了个问题,所以当初设计上采取了个偷懒的方式,直接将文件保存到MySql中,所有系统要用这些文件时,都去数据库中读取……

上面描述了问题产生的原因,现在项目已经上线,且运行了一段时间,发现文件存在数据库中导致数据库增长速度很快,而且未来迁移也不方便,所以考虑在原有直接存储到数据库中的方式,增加其他存储方式(注意是增加,不是全部替换),于是很简单的,直接给相应数据表增加一个字段标志存储方式(StorageMode),而原先存储文件数据的字段(Data)则用于存储其他方式持久化文件后对应的定位标志(比如文件路径等)

为了方便未来扩展出其他存储方式,所以我定义了如下存储接口

    /// <summary>/// 定义文件保存和获取的方式/// </summary>public interface IStorage{/// <summary>/// 文件保存,并返回保存后的编码结果/// </summary>/// <param name="fileType"></param>/// <param name="data"></param>/// <param name="fileName">要保存的文件名,如果不设置则随机命名</param>/// <returns></returns>byte[] Save(FileType fileType, byte[] data, string fileName = null);/// <summary>/// 根据请求编码获取对应的文件数据/// </summary>/// <param name="fileType"></param>/// <param name="input"></param>/// <returns></returns>byte[] Get(FileType fileType, byte[] input);/// <summary>/// 获取文件数据对应的文件名,如不支持则返回null/// </summary>/// <param name="fileType"></param>/// <param name="input"></param>/// <returns></returns>string GetFileName(FileType fileType, byte[] input);/// <summary>/// 删除文件数据/// </summary>/// <param name="fileType"></param>/// <param name="input"></param>/// <returns></returns>bool Remove(FileType fileType, byte[] input);}

其中FileType是按业务进行划分的文件类型,然后我依次定义了InDatabaseStorage(数据库存储)以及LocalDiskStorage(本地磁盘存储)两种实现,当然这部分在这里就不细写了,毕竟不是本文的关键……

下来到问题产生的重点了,为了统一文件的管理,以及符合ABP的设计风格,所以我们在Core层定义了FileRefManager这样一个Manager类来统一封装处理文件的管理,也就是在这里,我们完整的封装了如何根据存储方式来获取对应的IStorage,然后又如何在存储时进行转化,最后在获取时,为了尽可能少的修改其它代码,我们采用了一个取巧的方式,将文件通过对应途径获取数据流后,赋值回Data字段并予以返回,这样原先通过Data字段来获取文件流的其它代码就不用进行修改

想法是美好的,事实是残酷的,测试时,当我将某种FileType设置为存储到本地磁盘时,读取出来居然报“路径存在非法字符”,反复DEBUG,存进去没错,但读取就是错,这什么鬼?难道DEBUG后程序还做了其它什么我不知道的事情?

徒劳一天,一无所获后,第二天终于有所突破,因为可以确定,在保存成功时,不管是本地磁盘,还是数据库里的byte长度,都是正确的,而且不管保存后多久,只要我不通过程序查询,直接在数据库中查询,Data字段始终正确,而一旦我在程序中查询了,随后就可以立刻发现:数据库中的Data字段变了,又变成了以数据库存储时,存储的文件本身!!!而正是这个现象,脑中突然灵光一闪,当初看ABP资料时,貌似有看到过ABP会自动保存,赶紧去ABP官网一查,果然在UOW对应的说明中有如此一段,既然找到了问题,那解决问题相对就简单了,解决的途径也有好几种可以采纳

a)禁用UOW,但此方法可行性不高,因为按照ABP说明,UOW是否启用是按最外层调用方决定的,而UOW在ABP中其扩散范围并不仅仅只在Core层中

b)Data字段保持不变,返回时另外增加一个FactData字段,但这样需要将所有涉及文件存储的地方均进行代码修改,改动量太大,有些得不偿失

c)在返回文件实体时,既然不能对原数据实体进行修改,那么为何不干脆直接深Copy一个新的数据实体,然后在新实体上进行Data修正,最终返回新实体呢?此方案最终尝试果然可行,而且这样也无需修改其它涉及文件存储的代码

虽然问题解决了,但最终对于ABP自动保存这种设计思路还是觉得有些不可思议,就算认为我对实体做的任何修改,都可能应该进行持久化,但你总得有个途径让我告知系统不要自动保存吧,而禁用UOW这个方案又存在那么大的限制……


2018-06-11补充:

根据@protossyk 同学的评论,现在增加新的方案:

d)ABP自所以能自动保存,主要依赖的就是EF的实体跟踪,所以可以通过指定AsNoTracking来解决自动保存问题,写法示例如下

repository.GetAll().AsNoTracking().FirstOrDefaultAsync()


这篇关于ABP天坑--UOW自动保存修改的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/666576

相关文章

Python脚本实现自动删除C盘临时文件夹

《Python脚本实现自动删除C盘临时文件夹》在日常使用电脑的过程中,临时文件夹往往会积累大量的无用数据,占用宝贵的磁盘空间,下面我们就来看看Python如何通过脚本实现自动删除C盘临时文件夹吧... 目录一、准备工作二、python脚本编写三、脚本解析四、运行脚本五、案例演示六、注意事项七、总结在日常使用

SpringBoot项目启动后自动加载系统配置的多种实现方式

《SpringBoot项目启动后自动加载系统配置的多种实现方式》:本文主要介绍SpringBoot项目启动后自动加载系统配置的多种实现方式,并通过代码示例讲解的非常详细,对大家的学习或工作有一定的... 目录1. 使用 CommandLineRunner实现方式:2. 使用 ApplicationRunne

python修改字符串值的三种方法

《python修改字符串值的三种方法》本文主要介绍了python修改字符串值的三种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录第一种方法:第二种方法:第三种方法:在python中,字符串对象是不可变类型,所以我们没办法直接

Mysql8.0修改配置文件my.ini的坑及解决

《Mysql8.0修改配置文件my.ini的坑及解决》使用记事本直接编辑my.ini文件保存后,可能会导致MySQL无法启动,因为MySQL会以ANSI编码读取该文件,解决方法是使用Notepad++... 目录Myhttp://www.chinasem.cnsql8.0修改配置文件my.ini的坑出现的问题

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

python实现自动登录12306自动抢票功能

《python实现自动登录12306自动抢票功能》随着互联网技术的发展,越来越多的人选择通过网络平台购票,特别是在中国,12306作为官方火车票预订平台,承担了巨大的访问量,对于热门线路或者节假日出行... 目录一、遇到的问题?二、改进三、进阶–展望总结一、遇到的问题?1.url-正确的表头:就是首先ur

Spring使用@Retryable实现自动重试机制

《Spring使用@Retryable实现自动重试机制》在微服务架构中,服务之间的调用可能会因为一些暂时性的错误而失败,例如网络波动、数据库连接超时或第三方服务不可用等,在本文中,我们将介绍如何在Sp... 目录引言1. 什么是 @Retryable?2. 如何在 Spring 中使用 @Retryable

使用 Python 和 LabelMe 实现图片验证码的自动标注功能

《使用Python和LabelMe实现图片验证码的自动标注功能》文章介绍了如何使用Python和LabelMe自动标注图片验证码,主要步骤包括图像预处理、OCR识别和生成标注文件,通过结合Pa... 目录使用 python 和 LabelMe 实现图片验证码的自动标注环境准备必备工具安装依赖实现自动标注核心

QT实现TCP客户端自动连接

《QT实现TCP客户端自动连接》这篇文章主要为大家详细介绍了QT中一个TCP客户端自动连接的测试模型,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录版本 1:没有取消按钮 测试效果测试代码版本 2:有取消按钮测试效果测试代码版本 1:没有取消按钮 测试效果缺陷:无法手动停

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机