关于EF实体类的一点思考
在EF中修改一条记录时,一般是先查出该条记录,然后再通过TryUpdateModel或其他方式更新对应的属性。但我很讨厌这种要更新一条记录时,还要先去把记录查询出来的做法。我喜欢像sql语句那样的直接更新需要更新的字段。
以前一般都是先写好数据库,再通过代码生成器生成实体类、DbContext对象等。这里没用EF的DBFirst的自动生成是因为它无法生成我想要的实体对象。举个例子,我希望的实体类大概是这样:
public class User { public HashSet<string> PropertiesHasChanged = new HashSet<string>(); private string _name; public string Name { get { return _name; } set { _name = value; PropertiesHasChanged.Add("Name"); } } }
这样,我就可以直接将一个实体进行附加,然后很方便的设置需要更改的字段。
当然,你也可以先让所有属性都为可空类型,然后根据属性值是否为null进行判断,但这有一个缺点,假如我就想更新数据库中某记录的字段值为null呢?
如果你使用了Automapper等DTO,你也可以反射出要修改的属性字段,不过这不是本文要论述的地方。
当然,上述代码还有一个更好点的写法:
public class User { public HashSet<string> PropertiesHasChanged = new HashSet<string>(); private string _name; public string Name { get { return _name; } set { _name = value; // PropertiesHasChanged.Add("Name"); AddPropertityName(); } } //通过CallerMemberName自动获取属性名称 private void AddPropertityName([System.Runtime.CompilerServices.CallerMemberName]string propertyName = null) { if(!string.IsNullOrEmpty(propertyName)) PropertiesHasChanged.Add(propertyName); } }
插一段题外话:
在.Net 4.5中引入了三个Attribute:CallerMemberName、CallerFilePath和CallerLineNumber 。在编译器的配合下(什么叫在编译器的配合下?通过ILSpy(打开url后注意这里:Download: latest release | latest CI build (master),点击后一个a标签,下载解压后即可使用)反编译上述代码的dll,我们可以发现,Name属性中set部分的代码变成了_name = value;AddPropertityName(“Name”);),分别可以获取到调用函数(准确讲应该是成员)名称,调用文件及调用行号。示例:
) { _log4Net.ErrorFormat("文件:{0} 行号:{1} 方法名:{2},消息:{3}", sourceFilePath, sourceLineNumber, memberName, message); } //摘抄自https://www.cnblogs.com/zeroes/p/6031651.html
但现在我想Codefirst了,也即实体类的代码都要一行一行的敲,意味着除非特殊情况,几乎所有的属性我都只能这样写:public string Name { get; set; }
那么,在这种情况下,有没有什么好的方式让我也能实现最初的目标呢?
首先想到的是WPF中的MVVM,这个不就是属性发生更改后就自动通知么?正好和我的需求吻合嘛。先看看WPF中一般是怎么做的呢?
public class User : INotifyPropertyChanged { private string _name; public string Name { get { return _name; } set { _name = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName]string propertyName = "") { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } }
但我想要的是 { get; set; }的这种写法啊,不想要上面那种还要多写一串代码的方式啊。继续沿着WPF的思路,我们找到了PropertyChanged.Fody。先看看PropertyChanged.Fody的用法:
1.首先通过nuget在项目里引入PropertyChanged.Fody;
2.在项目里添加一FodyWeavers.xml文件,文件内容为:
<?xml version="1.0" encoding="utf-8" ?> <Weavers> <PropertyChanged/> </Weavers>
3.使用方式:
(1)github地址:https://github.com/Fody/PropertyChanged
(2)实现INotifyPropertyChanged接口,也即去掉上面代码中set内的“OnPropertyChanged();”部分,生成后,dll中set部分的代码就会自动变成:set { if(!string.Equals(_name, value, StringComparison.Ordinal)) { _name=value; OnPropertyChanged("Name"); } }
(3)给类添加“[PropertyChanged.AddINotifyPropertyChangedInterface]”特性,编译器会自动将该类继承INotifyPropertyChanged,并实现相关操作。
4.其他使用要点:(摘自:https://www.bbsmax.com/A/o75NWb0xdW/)
- 如果有某个属性不想实现通知事件,就在相应属性上加个[DoNotNotify]
- 假如该User类由这3个属性组成:FirstName, LastName, FullName,其中FullName是前两个属性的组合,那么假如前两个属性中任何一个变化都要通知都FullName变化,就给FirstName和LastName上加个[AlsoNotifyFor("FullName")],同理,如果FullName变了也让子属性变化,那就要在FullName上加上[DependsOn("FirstName","LastName")]
- [DoNotSetChanged]表示当FullName 的Set改变时,不通知到子属性
- [DoNotCheckEquality]:这个是说跳过相等的检查,即不要if(!string.Equals(_name, value, StringComparison.Ordinal))的判断,可用于类或者属性上。
5.更详细的请看:https://blog.csdn.net/x333vxhl/article/details/54969013、https://github.com/Fody/PropertyChanged/wiki等
如果感兴趣,可以继续研究下AOP面向切面编程,如Postsharp(需要下载安装,但代码发布后会自动添加一个dll,即服务器上不用安装)、Mono.Cecil:
https://www.cnblogs.com/pokemon/p/5479509.html(基于Mono.Cecil的静态注入)
https://blog.csdn.net/linxinfa/article/details/51803200(Mono.Cecil简介与示例)
https://blog.csdn.net/lee576/article/details/38780889(使用Mono.Cecil对MSIL进行注入)
https://www.jianshu.com/p/a5276aadccdd(使用Mono.Cecil实现IL代码注入)
https://www.cnblogs.com/tianqing/p/7610560.html(巧用Mono.Cecil反射加载类型和方法信息)
https://www.cnblogs.com/chejiangyi/p/5819129.html(.Net Aop(静态织入)框架 BSF.Aop)
https://www.cnblogs.com/WinHEC/p/Postsharp_5_X_Cracked.html( Postsharp 破解工具(通杀版,持续更新))
https://www.cnblogs.com/wuhuacong/p/6518748.html(在.NET项目中使用PostSharp,使用MemoryCache实现缓存的处理)
https://www.cnblogs.com/DragonStart/p/7744202.html(C# AOP 面向切面编程之 调用拦截)
http://www.cnblogs.com/farb/p/ABPAdvancedTheoryContent.html#AOPinDotNet(C#高级知识点&(ABP框架理论学习高级篇)——白金版)(值得阅读)
http://gad.qq.com/article/detail/27977(使用MSIL采用Emit方式实现C#的代码生成与注入)
关于EF实体类的一点思考的更多相关文章
- EF实体类配置总结
实体类配置总结 Entity Framework 6 Code First 实践系列(1):实体类配置总结 2014-03-25 12:58 by TJerry, 719 阅读, 6 评论, 收藏, ...
- 从PowerDesigner表字段的Name到EF实体类属性的Display Name(根据PowerDesigner生成EF实体类中文注释和验证元数据)
第一步:将PowerDesigner表字段的中文Name填入Comment中:工具-Execute Commands-Edit/Run Script... '********************* ...
- EF + WCF学习笔记——EF实体类序列化
项目中如果 EF + WCF 结合使用,模式应该是EF负责读取数据库,传递数据对象给WCF,WCF再将这些对象传送给客户端.因为WCF传送的对象需要序列化,而EF默认生成的对象并没有序列化,很可能会出 ...
- ASP.NET没有魔法——ASP.NET MVC 与数据库之EF实体类与数据库结构
大家都知道在关系型数据库中每张表的每个字段都会有自己的属性,如:数据类型.长度.是否为空.主外键.索引以及表与表之间的关系.但对于C#编写的类来说,它的属性只有一个数据类型和类与类之间的关系,但是在M ...
- ASP.NET开发实战——(十三)ASP.NET MVC 与数据库之EF实体类与数据库结构
大家都知道在关系型数据库中每张表的每个字段都会有自己的属性,如:数据类型.长度.是否为空.主外键.索引以及表与表之间的关系.但对于C#编写的类来说,它的属性只有一个数据类型和类与类之间的关系,但是在M ...
- 实际项目中遇到EF实体类的操作问题及操作方法
之前一直做ASP,都是直接写数据库操作语句,但是现在使用linq或者EF了,具体数据库操作不会了,遇到几个问题,然后经过查找资料解决了,记录一下. 一.遇到序列化问题 遇到循环引用问题,我的项目是一个 ...
- EF实体类指定部分属性不映射数据库标记
命名空间 ;using System.ComponentModel.DataAnnotations.Schema; 实体部分 public partial class Student { [NotMa ...
- EF 实体类的制定属性不生成数据库字段
添加一个标签即可 [NotMapped] 没什么营养,就是防忘记
- EF实体类的枚举属性映射设计方法
public class FoundationInfo { [Column("id")] public int ID { get; set; } public InvestType ...
随机推荐
- selenium中动作链的使用
一.问题 我们有时候在使用selenium的时候,会遇到悬停后点击元素的操作,因此需要一个动作链来完成这个功能. 二.解决 从selenium的包中导入actionchains函数,利用xpath找到 ...
- Java输入输出流详解
通过数据流.序列化和文件系统提供系统输入和输出. Java把这些不同来源和目标的数据都统一抽象为数据流.Java语言的输入输出功能是十分强大而灵活的,美中不足的是看上去输入输出的代码并不是很简洁,因为 ...
- mysql的一些操作命令
1.查看mysql数据库 SHOW DATABASES;(;号一定要加) 2.创建root用户密码 mysqladmin -u root password "new_password&quo ...
- w3wp.exe(IIS ) CPU 占用 100% 的常见原因
引起 w3wp.exe(IIS ) Cpu 占用 100% 的常见原因如下: 1. Web 访问量大,从而服务器压力大而引起的 2. 动态页面(.aspx)的程序逻辑复杂程度 3. 页面程序中有死循环 ...
- bzoj4555(多项式求逆解法)
//和以前写的fft不太一样,可能是因为要取模?? #include<iostream> #include<cstring> #include<cmath> #in ...
- Linux Ubuntu部署web环境及项目tomcat+jdk+mysql
1,下载文件 在官网下载好 tomcat.jdk.mysql的linux压缩包 后缀名为.tar.gz 并通过xftp上传到服务器 或者直接通过linux命令 下在wget文件的下载地址 例如: wg ...
- AJPFX:什么是外汇交易
外汇交易是对货币对的一种买卖,是以一个国家货币与另外一个国家货币进行交换,即您在买入一国货币的同时,您也卖出了另一国的货币.所以在外汇市场上,人们的交易对象就是“货币对“,比如欧元/美元,美元/日元, ...
- 我自己的sublime3环境
概述 我本来一直用的别人自带的破解版sublime3,自带插件. 前几天看<程序员修炼之道>,其中谈到了最好精通一种编辑器,我觉得说的很有道理,于是重新下了最新版的sublime3,一步步 ...
- Javascript百学不厌 - 尾递归
虽然偶尔也用过,但是从来没具体来整理过 普通递归: function fac(n) { ) ; ); } fac() 这是个阶乘.但是占用内存,因为: fac(5) (5*fac(4)) (5*(4* ...
- 使用speex动态链接库过程中遇到问题及解决方法
本以为speex的应用程序很容易就能跑起来,可是,实际操作中才发现,这里面暴露 的问题还真不少.看来以后不能眼高手低了,知行合一,这个一定要牢记在心中. speex安装成功后,可以一直无法调用动态链接 ...