实现UniqueAttribute唯一性约束-优化版

我之前就写过一篇《实现UniqueAttribute唯一性约束》,虽然实现了通过调用IsValid方法可以进行唯一性验证,但有一个缺点,那就是耦合度过高,原因是里面的DB上下文对象是直接写在里面的,如下:

public override Boolean IsValid(Object value)
        {
            bool validResult = false;
            //TEMSContext 是我项目中的DB上下文类,这里是直接指定的,与TEMSContext 紧耦合,若需要实体与访问分离就会有问题!
            using (TEMSContext context = new TEMSContext())
            {
               string sqlCmd=string.Format("select count(1) from [{0}] where [{1}]=@p0",tableName,filedName);
               context.Database.Connection.Open();
               var cmd=context.Database.Connection.CreateCommand();
               cmd.CommandText = sqlCmd;
               var p0 = cmd.CreateParameter();
               p0.ParameterName = "@p0";
               p0.Value = value;
               cmd.Parameters.Add(p0);
               int result=Convert.ToInt32(cmd.ExecuteScalar());
                validResult=(result<=0);
            }
            return validResult;
        }

现在为了解决这个问题,我目前采用的是通过属性注入DB上下文类型,然后再采取反射动态创建实例,这样就降低了依赖,完整代码如下:

using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;

namespace Zwj.TEMS.Common
{
    /// <summary>
    /// 唯一性标识
    /// </summary>
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public class UniqueAttribute : ValidationAttribute
    {
        protected string tableName;
        protected string filedName;

        public Type ContextType { private get; set; }

        public UniqueAttribute(string tableName, string filedName)
        {
            this.tableName = tableName;
            this.filedName = filedName;
        }

        public override Boolean IsValid(Object value)
        {
            //如果是系统调用,就不会传入ContextType类型,所以此处就直接返回通过
            if (this.ContextType == null)
            {
                return true;
            }

            bool validResult = false;
           using (DbContext context = ContextType.Assembly.CreateInstance(ContextType.FullName) as DbContext)
            {
                string sqlCmd = string.Format("select count(1) from [{0}] where [{1}]=@p0", tableName, filedName);
                context.Database.Connection.Open();
                var cmd = context.Database.Connection.CreateCommand();
                cmd.CommandText = sqlCmd;
                var p0 = cmd.CreateParameter();
                p0.ParameterName = "@p0";
                p0.Value = value;
                cmd.Parameters.Add(p0);
                int result = Convert.ToInt32(cmd.ExecuteScalar());
                validResult = (result <= 0);
                context.Database.Connection.Close();
            }
            return validResult;
        }
    }
}

这样虽然降低了对实际DB上下文的依赖,但新问题又出来了,就是如果通过手动来验证该特性(如下代码)就没有问题,但如是想让EF框架在RUD时能自动验证,则会出现问题,因为没有传入ContextType,所以也就无法进行验证,我想这也是微软之所以没有实现UniqueAttribute唯一性约束的原因吧,不知道哪位高手能指点一下,非常感谢!

以下是手动来验证该特性:

        public void ValidateEntity(object entity)
        {
            var t = entity.GetType();
            var properties = t.GetProperties();
            foreach (var p in properties)
            {
                UniqueAttribute[] attrs;
                if (p.TryGetAttribute<UniqueAttribute>(out attrs))
                {
                    attrs[0].ContextType=typeof(TEMSContext);
                    bool result = attrs[0].IsValid(p.GetValue(entity, null));
                    Assert.IsTrue(result, "验证不唯一,存在重复值!");
                }
            }
        }

  

 

posted @ 2015-04-07 12:11  梦在旅途  阅读(865)  评论(0编辑  收藏  举报