Smark.Data实体成员数据验证
Smark.Data支持通过Atteribute的方式来描述一个实体对象在数据保存前进行数据的有效验证,使用人员也可以通过扩展自己的Attribute实现新的验证方式。下面介绍一下这个验机制的实现和扩展。
在Smark.Data中所有实体必须继承DataObject,这个对象主要包装了一些简单的实体操作(详细代码可以到: http://smark.codeplex.com/ 获取)。先看一下DataObject数据添加的代码:
private void NewData(IConnectinContext cc, ObjectMapper om)
{
Insert insert = new Insert(om.Table);
object value = null;
if (om.ID != null)
{
if (om.ID.Value != null)
{
if (!om.ID.Value.AfterByUpdate)
{
om.ID.Value.Executing(cc, this, om.ID,om.Table);
insert.AddField(om.ID.ColumnName, om.ID.Handler.Get(this));
}
}
else
{
insert.AddField(om.ID.ColumnName, om.ID.Handler.Get(this));
}
}
foreach (PropertyMapper pm in om.Properties)
{
if (!EntityState._FieldState.ContainsKey(pm.Handler.Property.Name))
{
if (pm.Value != null && !pm.Value.AfterByUpdate)
{
pm.Value.Executing(cc, this, pm, om.Table);
}
}
value = pm.Handler.Get(this);
foreach (Validates.ValidaterAttribute val in pm.Validaters)
{
val.Validating(value, this, pm, cc);
}
if (EntityState._FieldState.ContainsKey(pm.Handler.Property.Name))
{
if (pm.Cast != null)
{
value = pm.Cast.ToColumn(value, pm.Handler.Property.PropertyType, this);
}
insert.AddField(pm.ColumnName, value);
}
}
insert.Execute(cc);
if (om.ID != null && om.ID.Value != null && om.ID.Value.AfterByUpdate)
om.ID.Value.Executed(cc, this, om.ID,om.Table);
}
红色部分代码部分描述,如果当属性存在验证描述的情况,就执行相关验证;实际情况下有可能一个属性配置多个验证的,如:不能为空,范围值等等。
首先定义一个验证基础类来描述需要干什么。
[AttributeUsage(AttributeTargets.Property)]
public abstract class ValidaterAttribute : Attribute
{
public void Validating(object value, object source,Mappings.PropertyMapper pm,IConnectinContext cc )
{
if (!OnValidating(value, source, pm,cc))
throw new ValidaterException(Message);
}
protected abstract bool OnValidating(object value, object source, Mappings.PropertyMapper pm, IConnectinContext cc);
public string Message
{
get;
set;
}
}
既然明确了要干什么,那下面就好扩展了。
不为空
[AttributeUsage(AttributeTargets.Property)]
public class NotNull : ValidaterAttribute
{
public NotNull(string message)
{
Message = message;
}
protected override bool OnValidating(object value, object source, Mappings.PropertyMapper pm, IConnectinContext cc)
{
return value != null && !string.IsNullOrEmpty(value.ToString());
}
}
长度限制
[AttributeUsage(AttributeTargets.Property)]
public class Length : ValidaterAttribute
{
public Length(string min, string max, string message)
{
if (!string.IsNullOrEmpty(min))
MinLength = int.Parse(min);
if (!string.IsNullOrEmpty(max))
MaxLength = int.Parse(max);
Message = message;
}
public int? MinLength
{
get;
set;
}
public int? MaxLength
{
get;
set;
}
protected override bool OnValidating(object value, object source, Mappings.PropertyMapper pm, IConnectinContext cc)
{
if (value != null && !string.IsNullOrEmpty(value.ToString()))
{
string data = Convert.ToString(value);
if (MinLength != null && MinLength > data.Length)
{
return false;
}
if (MaxLength != null && data.Length > MaxLength)
{
return false;
}
}
return true;
}
}
正则
[AttributeUsage(AttributeTargets.Property)]
public class Match : ValidaterAttribute
{
public Match(string regex, string message)
{
Regex = regex;
Message = message;
}
public string Regex
{
get;
set;
}
protected override bool OnValidating(object value, object source, Mappings.PropertyMapper pm, IConnectinContext cc)
{
if (value != null && !string.IsNullOrEmpty(value.ToString()))
{
string data = Convert.ToString(value);
if (System.Text.RegularExpressions.Regex.Match(
data, Regex, RegexOptions.IgnoreCase).Length == 0)
{
return false;
}
}
return true;
}
}
[AttributeUsage(AttributeTargets.Property)]
public class EMail : Match
{
public EMail(string msg) : base(@"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$", msg) { }
}
[AttributeUsage(AttributeTargets.Property)]
public class CardID : Match
{
public CardID(string msg) : base(@"^(\d{15}$|^\d{18}$|^\d{17}(\d|X|x))$/", msg) { }
}
当然还可以通过查询数据库进行验证
[AttributeUsage(AttributeTargets.Property)]
public class Unique : ValidaterAttribute
{
public Unique(string err)
{
Message = err;
}
protected override bool OnValidating(object value, object source, Mappings.PropertyMapper pm, IConnectinContext cc)
{
if (value == null)
return true;
if (string.IsNullOrEmpty((string)value))
return true;
string sql = "select {0} from {1} where {0}=@p1";
Command cmd = new Command(string.Format(sql, pm.ColumnName, pm.OM.Table));
cmd.AddParameter("p1", value);
object result = cc.ExecuteScalar(cmd);
return result == null || result == DBNull.Value;
}
}
对于使用也很简单
/// <summary>
/// 用户名称
/// </summary>
[Column]
[NotNull("用户名不能为空!")]
[Length("5", "16", "用户名长度必须5-16个字符!")]
[Unique("该用户名已经给其他用户使用!")]
string UserName { get; set; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2006-09-15 SQL Artisan处理规则结构描述
2005-09-15 一个数据访问层的概要设计