在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/54969013https://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实体类的一点思考的更多相关文章

  1. EF实体类配置总结

    实体类配置总结 Entity Framework 6 Code First 实践系列(1):实体类配置总结 2014-03-25 12:58 by TJerry, 719 阅读, 6 评论, 收藏,  ...

  2. 从PowerDesigner表字段的Name到EF实体类属性的Display Name(根据PowerDesigner生成EF实体类中文注释和验证元数据)

    第一步:将PowerDesigner表字段的中文Name填入Comment中:工具-Execute Commands-Edit/Run Script... '********************* ...

  3. EF + WCF学习笔记——EF实体类序列化

    项目中如果 EF + WCF 结合使用,模式应该是EF负责读取数据库,传递数据对象给WCF,WCF再将这些对象传送给客户端.因为WCF传送的对象需要序列化,而EF默认生成的对象并没有序列化,很可能会出 ...

  4. ASP.NET没有魔法——ASP.NET MVC 与数据库之EF实体类与数据库结构

    大家都知道在关系型数据库中每张表的每个字段都会有自己的属性,如:数据类型.长度.是否为空.主外键.索引以及表与表之间的关系.但对于C#编写的类来说,它的属性只有一个数据类型和类与类之间的关系,但是在M ...

  5. ASP.NET开发实战——(十三)ASP.NET MVC 与数据库之EF实体类与数据库结构

    大家都知道在关系型数据库中每张表的每个字段都会有自己的属性,如:数据类型.长度.是否为空.主外键.索引以及表与表之间的关系.但对于C#编写的类来说,它的属性只有一个数据类型和类与类之间的关系,但是在M ...

  6. 实际项目中遇到EF实体类的操作问题及操作方法

    之前一直做ASP,都是直接写数据库操作语句,但是现在使用linq或者EF了,具体数据库操作不会了,遇到几个问题,然后经过查找资料解决了,记录一下. 一.遇到序列化问题 遇到循环引用问题,我的项目是一个 ...

  7. EF实体类指定部分属性不映射数据库标记

    命名空间 ;using System.ComponentModel.DataAnnotations.Schema; 实体部分 public partial class Student { [NotMa ...

  8. EF 实体类的制定属性不生成数据库字段

    添加一个标签即可 [NotMapped] 没什么营养,就是防忘记

  9. EF实体类的枚举属性映射设计方法

    public class FoundationInfo { [Column("id")] public int ID { get; set; } public InvestType ...

随机推荐

  1. selenium中动作链的使用

    一.问题 我们有时候在使用selenium的时候,会遇到悬停后点击元素的操作,因此需要一个动作链来完成这个功能. 二.解决 从selenium的包中导入actionchains函数,利用xpath找到 ...

  2. Java输入输出流详解

    通过数据流.序列化和文件系统提供系统输入和输出. Java把这些不同来源和目标的数据都统一抽象为数据流.Java语言的输入输出功能是十分强大而灵活的,美中不足的是看上去输入输出的代码并不是很简洁,因为 ...

  3. mysql的一些操作命令

    1.查看mysql数据库 SHOW DATABASES;(;号一定要加) 2.创建root用户密码 mysqladmin -u root password "new_password&quo ...

  4. w3wp.exe(IIS ) CPU 占用 100% 的常见原因

    引起 w3wp.exe(IIS ) Cpu 占用 100% 的常见原因如下: 1. Web 访问量大,从而服务器压力大而引起的 2. 动态页面(.aspx)的程序逻辑复杂程度 3. 页面程序中有死循环 ...

  5. bzoj4555(多项式求逆解法)

    //和以前写的fft不太一样,可能是因为要取模?? #include<iostream> #include<cstring> #include<cmath> #in ...

  6. Linux Ubuntu部署web环境及项目tomcat+jdk+mysql

    1,下载文件 在官网下载好 tomcat.jdk.mysql的linux压缩包 后缀名为.tar.gz 并通过xftp上传到服务器 或者直接通过linux命令 下在wget文件的下载地址 例如: wg ...

  7. AJPFX:什么是外汇交易

    外汇交易是对货币对的一种买卖,是以一个国家货币与另外一个国家货币进行交换,即您在买入一国货币的同时,您也卖出了另一国的货币.所以在外汇市场上,人们的交易对象就是“货币对“,比如欧元/美元,美元/日元, ...

  8. 我自己的sublime3环境

    概述 我本来一直用的别人自带的破解版sublime3,自带插件. 前几天看<程序员修炼之道>,其中谈到了最好精通一种编辑器,我觉得说的很有道理,于是重新下了最新版的sublime3,一步步 ...

  9. Javascript百学不厌 - 尾递归

    虽然偶尔也用过,但是从来没具体来整理过 普通递归: function fac(n) { ) ; ); } fac() 这是个阶乘.但是占用内存,因为: fac(5) (5*fac(4)) (5*(4* ...

  10. 使用speex动态链接库过程中遇到问题及解决方法

    本以为speex的应用程序很容易就能跑起来,可是,实际操作中才发现,这里面暴露 的问题还真不少.看来以后不能眼高手低了,知行合一,这个一定要牢记在心中. speex安装成功后,可以一直无法调用动态链接 ...