本文已参与「新人创作礼」活动,一起开启掘金创作之路。
如题,Model中一字段值为其他字段计算后所得,不会存储到数据库中,但是一需求:以此字段为条件进行查询数据
具体问题
在实体类中我有一个售出日期字段、售出月份字段,后面又添加了一个售出年份字段,只有售出日期是从表单中获取值,另外的直接从售出日期中获取。部分代码如下
/// <summary>
/// 售出日期
/// </summary>
[Column]
[Required]
public DateTime SaleDate { get; set; }
/// <summary>
/// 售出月份
/// </summary>
[NotMapped]//生成表中字段
public string Month => SaleDate.Month.ToString();
刚开始想法是,把Month
字段也存到数据库表中,但是售出日期变动后,此Month
字段也要跟着更新,这里还需要修改多处代码,后期没有任何优化空间了。解决问题还是要从根源上解决,而不是为了解决问题不折手段....
解决办法(并非我想要的)
换条思路,能不能不要Month
了,直接截取售出日期,进行查询,理论上是可行的,用sql语句也能很方便实现。
注:为了测试,特意找有一些数据的数据库表,这样才能看到效果,未采用查询本文开头对应表(无数据),下面例子也是,特此说明下。
上图为SqlServer数据库,其他数据库应该也有类似DATEPART
、MONTH
函数,具体自行搜索吧,本文重点不是这里,就不深入了
为方便大家获取关键代码,上图具体代码如下
/*方式一:使用DATEPART*/
select DATEPART(Month, CreateTime) as '月份', Count(1) as '条数' from T_OptionRecord GROUP BY DATEPART(MONTH, CreateTime)
/*方式二:使用函数MONTH*/
select DATEPART(mm,CreateTime) as '月份', Count(1) as '条数' from T_OptionRecord GROUP BY MONTH(CreateTime)
使用Linq 同样也能实现该需求,直接上图
图中代码如下
db.GetList<OperationLog>()
.GroupBy(x => x.CreateTime.Month)
.Select(x => new { Name = x.Key, Count = x.Count() })
.ToList();
其他解决办法(最终方法)
上面已经展示了三种解决办法,但是不是我想要的,我就要用Month
字段来作为查询条件!不然我写这个字段的意义在哪!不能仅仅展示使用吧。
要用该字段作为查询条件,数据库表必须要存储该字段
,否则会报错:Invalid column name 'Month'
静下心来,思考一下,Month
字段其实只有get访问器,没有set访问器,也就是只读(面向对象三大特性之 封装...)
其实他的值是SaleDate
的set访问器中自动赋值的(自动随之改变)
那么完全可以把赋值行为写到SaleDate
的set中
接下来就是想办法,如何写set(其实很简单,但是不容易)
先来回顾一下相关基础知识点吧
- 类中成员包括字段、属性、方法
- 字段:类中的变量,可以有private/protected/public等不同修饰符。说白了就是--->
存储数据的变量
- 属性:使用get/set包装的方法,本质是方法,是方法的简写。作用就是增强对字段的存取控制!
- 如果类中一个字段是private,那外部是不能访问的,但是可以通过属性的get访问器来读取他的值,也可以通过set访问器来更新(写)他的值
- 属性的get/set可以限制字段的一些功能,以达到某种目的!
- 属性是没有存储功能的(本质是函数/方法),数据都存储在字段中,
所以只有修改了字段的数据才能修改数据,改属性值没用!
- 属性其实就是对字段的封装,字段在类内部使用,属性安全性高一点,所以可以在外部使用!
- 属性和方法的区别:属性没有参数列表,方法必须有,哪怕是空的,也要写个空括号在那里!属性至少要有get/set其中一个访问器(不可读不可写的属性是没有意义的!)。
两者都可以判定字段中数据的合法性!即都可以对字段的值起限定作用!
综上,总结一下就是:字段是存储容器,属性是操作数据的方法(写、读)
铺垫有了,那就思考一下如何写吧,看看你们能不能写出来
我的代码实现如下:
/// <summary>
/// 售出日期
/// </summary>
private DateTime saleDate;//字段
/// <summary>
/// 售出日期
/// </summary>
[Column]
[Required]
public DateTime SaleDate//属性
{
get
{
return saleDate;
}
set
{
saleDate = value;//将值赋值给字段
Month = saleDate.Month.ToString();
}
}
/// <summary>
/// 售出日期
/// </summary>
[Column]
public string Month { get; set; }
经测试,完全可行,查询也没问题了
简单查询代码如下
var list = db.GetList<Vehicle>(x => x.Month == month);
最后总结
回想一下,其实我的最终方法并不是最优解,甚至不如上面sql和linq方法好,因为他有个最大的缺陷,就是如果数据已经存在了,而且量很大,突然增加一个字段,是没有值的,而且不符合 尽量不改动表结构
的原则,越到后面数据积累了越不要改动表!但是他也是一种实现的方式,这种方式可以深刻理解到字段和属性,set和get访问器等基础知识点的重要性!