在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. spring深入学习(五)-----spring dao、事务管理

    访问数据库基本是所有java web项目必备的,不论是oracle.mysql,或者是nosql,肯定需要和数据库打交道.一开始学java的时候,肯定是以jdbc为基础,如下: private sta ...

  2. SignalR 服务器系统配置要求

    SignalR 所支持的服务器版本..NET Framework 版本.IIS和其他组件. SignalR操作系统要求 SignalR组件能够运行在下面的服务器和客户端操作系统.需要注意的是使用Web ...

  3. linux系统下载pycharm

    如何下载pycharm安装包? 你可以通过访问 https://www.jetbrains.com/pycharm/download/#section=linux 获取安装包,如果是新手建议使用社区版 ...

  4. GPU、CPU、FPGA

    一.计算核心增加 二者都由寄存器.控制器.逻辑单元构成,但比例很大不同,决定了CPU擅长指令处理,函数调用上:GPU在数据处理(算数运算/逻辑运算)强力很多. NIVIDA基于Maxwell构架的GP ...

  5. POJ2455 Secret Milking Machine

    Secret Milking Machine Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12324   Accepted ...

  6. ASP.NET Core 注入和获取 AppSettings 配置

    ASP.NET Core 项目中有个appsettings.json配置文件,用于存放一些配置信息,比如数据库连接字符串等,但访问的话,只能在 ASP.NET Core 项目中获取,如果我们在其他项目 ...

  7. IntelliJ IDEA 注册码(因为之前的地址被封杀了,所以换了个地址)

    附上IntelliJ IDEA 注册码(感谢提供注册码的大神):http://idea.qinxi1992.cn/(已封杀) http://idea.lanyus.com/(新地址) 注:以前直接复制 ...

  8. spring框架学习笔记2:配置详解

    简单写一个类做示例: package bean; public class User { private String name; private Integer age; public String ...

  9. JS应用实例5:全选、动态添加

    HTML代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <t ...

  10. Dispatch Queue 之 Invoke 当前队列