zoukankan      html  css  js  c++  java
  • 如何为EntityFramework添加Unique功能?

    直到目前为止,EntityFramework似乎没有UniqueAttribute这个属性,因而也就无法为数据模型表某个特定字段指定是Unique。那么怎么办呢?我们就DIY一次吧!

    首先自己写一个特性,该特性只能被用于property上,由于只是一个标记特性而以,因此类体为空——

    [C#]

     [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
        public class UniqueKeyAttribute : Attribute
        {
    
        }

    [VB.NET]

    <AttributeUsage(AttributeTargets.[Property], AllowMultiple := False, Inherited := True)> _
    Public Class UniqueKeyAttribute
        Inherits Attribute
    
    End Class

    然后自己实现IDatabaseInitializer接口。那是因为EntityFramework的DataBase有一个静态方法叫做SetInitialize<T>,其中“T”是预备生成的模型类(继承DbContext),而这个方法需要一个实现该接口的类用于初始化数据库。该类实现如下:
    [C#]

     public class MyDbGenerator<T> : IDatabaseInitializer<T> where T : DbContext
        {
            public void InitializeDatabase(T context)
            {
                   context.Database.Delete();
                    context.Database.Create();
    
                    //获取全部父类的公开属性
                    var fatherPropertyNames = typeof(DbContext).GetProperties().Select(pi => pi.Name).ToList();
    
                    //先剔除由父类继承的公共属性
                    foreach (PropertyInfo item in typeof(T).GetProperties().Where(p => fatherPropertyNames.IndexOf(p.Name) < 0).Select(p => p))
                    {
                        //获取子类DbSet<T>中的那个"T"
                        Type entityModelType = item.PropertyType.GetGenericArguments()[0];
    
                        //反射“T”,并且获取已经加上“Unique”的自定义属性字段名称
    var allfieldNames = from prop in entityModelType.GetProperties()
                                            where prop.GetCustomAttributes(typeof(UniqueKeyAttribute), true).Count() > 0
                                            select prop.Name;
    
                        //逐个开始用SQL命令生成唯一字段
    foreach (string s in allfieldNames)
                        {
                            context.Database.ExecuteSqlCommand("alter table " + entityModelType.Name + " add unique(" + s + ")");
                        }
                    }
                   
                }
        }

    [VB.NET]

    Public Class MyDbGenerator(Of T As DbContext)
        Implements IDatabaseInitializer(Of T)
        Public Sub InitializeDatabase(context As T)
            context.Database.Delete()
            context.Database.Create()
    
            '获取全部父类的公开属性                
            Dim fatherPropertyNames = GetType(DbContext).GetProperties().[Select](Function(pi) pi.Name).ToList()
    
            '先剔除由父类继承的公共属性                
            For Each item As PropertyInfo In GetType(T).GetProperties().Where(Function(p) fatherPropertyNames.IndexOf(p.Name) < 0).[Select](Function(p) p)
                '获取子类DbSet<T>中的那个"T"                   
                Dim entityModelType As Type = item.PropertyType.GetGenericArguments()(0)
    
                '反射“T”,并且获取已经加上“Unique”的自定义属性字段名称                    
                Dim allfieldNames = From prop In entityModelType.GetProperties() Where prop.GetCustomAttributes(GetType(UniqueKeyAttribute), True).Count() > 0prop.Name
    
                '逐个开始用SQL命令生成唯一字段                    
                For Each s As String In allfieldNames
                    context.Database.ExecuteSqlCommand("alter table " + entityModelType.Name & " add unique(" & s & ")")
                Next
            Next
        End Sub
    End Class

    下面给出测试:
    [C#]

     public class Category
        {
            [Key]
            public int Id { get; set; }
            [UniqueKey]
            public int IdentifyCode { get; set; }
            public string Name { get; set; }
        }
    
        public class DbG : DbContext
        {
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
            }
            public DbSet<Category> Categories { get; set; }
        }
    
        public class MainTest
        {
            static void Main(string[] args)
            {
                Database.SetInitializer<DbG>(new MyDbGenerator<DbG>());
    
                using (DbG g = new DbG())
                {
                    g.Categories.Add(new Category { Id = 1, Name = "Category" });
                    g.SaveChanges();
                    Console.WriteLine("OK");
                }
            }
        }

    [VB.NET]

    copy to clipboard | view source | convert again 
    
    Public Class Category
        <Key> _
        Public Property Id() As Integer
            Get
                Return m_Id
            End Get
            Set
                m_Id = Value
            End Set
        End Property
        Private m_Id As Integer
        <UniqueKey> _
        Public Property IdentifyCode() As Integer
            Get
                Return m_IdentifyCode
            End Get
            Set
                m_IdentifyCode = Value
            End Set
        End Property
        Private m_IdentifyCode As Integer
        Public Property Name() As String
            Get
                Return m_Name
            End Get
            Set
                m_Name = Value
            End Set
        End Property
        Private m_Name As String
    End Class
    
    Public Class DbG
        Inherits DbContext
        Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
            modelBuilder.Conventions.Remove(Of PluralizingTableNameConvention)()
        End Sub
        Public Property Categories() As DbSet(Of Category)
            Get
                Return m_Categories
            End Get
            Set
                m_Categories = Value
            End Set
        End Property
        Private m_Categories As DbSet(Of Category)
    End Class
    
    Public Class MainTest
        Private Shared Sub Main(args As String())
            Database.SetInitializer(Of DbG)(New MyDbGenerator(Of DbG)())
    
            Using g As New DbG()
                g.Categories.Add(New Category() With { _
                    Key .Id = 1, _
                    Key .Name = "Category" _
                })
                g.SaveChanges()
                Console.WriteLine("OK")
            End Using
        End Sub
    End Class

    注意:此处的“OnModelCreating”方法必须被重写。因为默认情况下Code-First生成的数据表名总是“实体模型名”(复数)形式,而我的代码目前只考虑了(直接根据模型名)生成表(也就是Add unique这部分)。因此必须取消表的“自动复数化”形式。除了我的这个方法以外,其实还可以采用在模型类上冠以“Table("表名称")”的形式。

    测试代码是成功的,不过有时会出现表无法删除的情况,望大伙儿可以指教一二,谢谢!

    如果有其它想法或者意见,也请及时反馈,谢谢!

  • 相关阅读:
    解决javaScript在不同时区new Date()显示值不同问题
    页面返回上一页浏览位置
    如何disabled禁用所有表单input输入框元素
    js根据json数组多个字段排序
    No identifier specified for entity
    Android resource compilation failed
    android 系统dialog的应用
    android消息处理源码分析
    Linux下常用命令
    ContentProvider和ContentResolver的使用
  • 原文地址:https://www.cnblogs.com/ServiceboyNew/p/2579519.html
Copyright © 2011-2022 走看看