第十讲 IQueryable和IEnumerable、Reflection基础、Attribute基础

namespace MyPreContentTeach
{
    public class IQueryableAndIEnumerable
    {
        public void Test1()
        {
            EFDBEntities db = new EFDBEntities();
           // string sql = "select StudentName,Age,StudentId  from Students";
            //        public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source,
            //                                                                                                      Expression<Func<TSource, bool>> predicate);
            var stuList1 = db.Students.Where(s => s.Age > 20);
            var stuList2 = stuList1.Where(s => s.Gender == "男");
            // Console.WriteLine(stuList2.ToString());
            //            SELECT
            //     [Extent1].[StudentId] AS[StudentId],
            //    [Extent1].[StudentName] AS[StudentName],
            //    [Extent1].[Gender] AS[Gender],
            //    [Extent1].[Birthday] AS[Birthday],
            //    [Extent1].[StudentIdNo] AS[StudentIdNo],
            //    [Extent1].[Age] AS[Age],
            //    [Extent1].[PhoneNumber] AS[PhoneNumber],
            //    [Extent1].[StudentAddress] AS[StudentAddress],
            //    [Extent1].[ClassId]
            //        AS[ClassId]
            //FROM[dbo].[Students]
            //        AS[Extent1]
            //WHERE([Extent1].[Age] > 20) AND('男' = [Extent1].[Gender])
            foreach (var item in stuList2)
            {
                Console.WriteLine(item.StudentName);
            }
            //执行发现:在数据库中只有一条SQL语句,并且是两个条件的合并。
            //好处:      实现延迟加载。我们对数据库的操作,不应该把所有的查询到,然后在内存筛选,而应该把我们所有的查询综合到一起,然后组合成一条SQL语句去执行。
        }
        public void Test2()
        {
            EFDBEntities db = new EFDBEntities();
            var stuList1 = db.Students.Where(s => s.Age > 20).AsEnumerable();//结果是IEnumerable类型
            var stuList2 = stuList1.Where(s => s.Gender == "男");
            //查看stuList1.Where的定义
            // public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,
            //                                                                                                Func<TSource, bool> predicate);
            //参数接收的是一个Func<>表达式,就是一个委托,委托一旦调用,会立即执行,并将结果保存到内存中
            //也就是意味着,我们只会看到s => s.Age > 20这个表达式所对应的SQL语句,而看不到后面的条件,后面的是内存筛选。
            foreach (var item in stuList2)
            {
                Console.WriteLine(item.StudentName);
            }
            //            SELECT
            //    [Extent1].[StudentId] AS[StudentId],
            //    [Extent1].[StudentName] AS[StudentName],
            //    [Extent1].[Gender] AS[Gender],
            //    [Extent1].[Birthday] AS[Birthday],
            //    [Extent1].[StudentIdNo] AS[StudentIdNo],
            //    [Extent1].[Age] AS[Age],
            //    [Extent1].[PhoneNumber] AS[PhoneNumber],
            //    [Extent1].[StudentAddress] AS[StudentAddress],
            //    [Extent1].[ClassId]
            //        AS[ClassId]
            //FROM[dbo].[Students]
            //        AS[Extent1]
            //WHERE[Extent1].[Age] > 20
            //执行发现:在数据库中确实只有一条SQL语句,而且是前面的。
            //问题:我们在查询数据库的时候,不能直接用这种形式,否则会造成内存严重浪费!而需要将表达式组合好,然后一起提交。
        }
    }
}
 
 
 
 
namespace MyPreContentTeach.ORM
{
    public class SysAdmin
    {
        public int LoginId { get; set; }
        public string LoginPwd { get; set; }
        public string AdminName { get; set; }
    }
}
 
 
 
namespace MyPreContentTeach.ORM
{
    public class AttributeStudy
    {
        public void GetAllAttributesFromModel<T>(T model)
        {
            //  Type type = model.GetType();
            //typeof关键字和GetType()有什么不同?都能获取对应的类型
            //typeof(具体的类名,比如Student,或类型名称,DateTime)不能使用变量
            //Type type1 = typeof(string);
            PropertyInfo[] properties = model.GetType().GetProperties();
            foreach (var item in properties)
            {
                //获取当前属性中所有自定义的“特性”
                var cusAttributes = item.GetCustomAttributes();
                foreach (var attribute in cusAttributes)
                {
                    Console.WriteLine("属性名称:"+item.Name);
                    Console.WriteLine("特性名称:"+attribute.GetType().Name);
                    Console.WriteLine("=====================");
                }
            }
        }
    }
}
 
 
namespace MyPreContentTeach.ORM
{
    public class PropertityStudy
    {
        public void GetAllPropertiesFromModel<T>(T model)
        {
            Type type = model.GetType();
            //    public PropertyInfo[] GetProperties()
            //Type:其实就是指一个特定类的所有的程序信息,当我输出的时候,是以字符串方式,所以会看到这个类型的《完全限定名》
            Console.WriteLine("实体类型:" + type); //MyPreContentTeach.Student
            Console.WriteLine("实体名称:" + type.Name);
            Console.WriteLine("=======================");
            PropertyInfo[] properties = type.GetProperties();
            //PropertyInfo 不仅包含了属性的基本信息,还可以对属性进行操作...
            foreach (var item in properties)
            {
                Console.WriteLine("属性姓名:" + item.Name);
                Console.WriteLine("属性类型:" + item.PropertyType);
                Console.WriteLine("属性   值:" + item.GetValue(model, null));
                Console.WriteLine("************************************");
            }
        }
        //我们在操作数据库的时候,我们通常是传递一个对象,然后把对象解析成SQL语句(ADO.NET实现原理)
        //我们希望就扔给你一个Model,至于说SQL语句,你能不能不让我写呢?EF做到了!因为ORM框架替你完成!
        //想一下:SQL语句生成的依据?
        //只要看看SQL语句里面有什么?insert into 表名称 (字段名称...) values(对应字段值...)
        //基础课程就告诉我们,写实体类的时候,要和数据表做到“映射”(实体名称=表名称,实体属性名=表字段名)
        //通过前面的测试:你随便给我一个实体,我能够得到实体名称、所有的属性名、属性值
        //最后:我们根据一个封装好的实体,生成一条SQL语句还是非常容易的!
        //编写一个生成insert类型SQL语句的方法
        public void CreateInsertSQL<T>(T model)
        {
            //【1】获取实体所有的属性信息数组
            PropertyInfo[] properties = model.GetType().GetProperties();
            //insert into 表名称 (字段名称...) values(对应字段值...)
            //常用的SQL语句,其实是带参数的SQL语句
            //insert into 表名称 (字段名称...) values(@字段名称...) 
            StringBuilder sqlFields = new StringBuilder($"insert into {model.GetType().Name} (");
            StringBuilder sqlValues = new StringBuilder(" values (");
            List<SqlParameter> paramList = new List<SqlParameter>();
            //获取标识列、扩展属性
            List<string> idList = GetPropertiesByAttribute(properties, "IdentityAttribute");//硬编码!不提倡(可以使用枚举)
            List<string> noTableList = GetPropertiesByAttribute(properties, "NonTableAttribute");
            foreach (var item in properties)
            {
                if (idList.Contains(item.Name) || noTableList.Contains(item.Name)) continue;
                sqlFields.Append(item.Name + ",");
                sqlValues.Append($"@{item.Name},");
                //将属性值封装到参数对象(需要考虑null的问题)
                paramList.Add(new SqlParameter($"@{item.Name }", item.GetValue(model, null)));
            }
            string fields = sqlFields.ToString().TrimEnd(',') + ")";//去掉最后的逗号
            string values = sqlValues.ToString().TrimEnd(',') + ")";
            string sql = fields + values;
            Console.WriteLine(sql);
            //以上是假想我们添加一个对象的时候,把所有的属性都添加进去,但是实际中?有的属性是不能添加的
            //比如,标识列、扩展属性、属性值是null的也要去掉
            //问题?如何找到我们不需要的属性?我们可以使用特性Attribute
            //如何理解Attribute?
            //特性可以被添加到类、属性、方法等很多地方!如何创建一个特性类呢?只要添加一个类,并且让它继承Attr类就行。
            //特性其实非常常见:MVC属性的验证,是不是有特性?WebService的时候,方法是不是也有WebMethod特性、[httpPost]
            //特性:是一种特殊的类,这种类是用[]标记到对应的位置,好处?
            //好处:它不仅是一个标记,还可以有标记值!我们使用特性,可以轻松的将一个类、方法、属性进行扩展!而这种扩展,对原有封装,没有任何破坏!
            //AOP:特性其其实就是一种AOP的反映!
        }
        //继续思考:如果某一个属性没有被特性过滤,但是有null值或其他默认值,我们应该怎么样处理?
        public List<string> GetPropertiesByAttribute(PropertyInfo[] properties, string attributeName)
        {
            List<string> columList = new List<string>();
            foreach (var item in properties)
            {
                //首先过滤一下我们不需要的属性?使用特性过滤(标识列、扩展属性)
                var cusAttributes = item.GetCustomAttributes();
                foreach (var attribute in cusAttributes)
                {
                    string attrName = attribute.GetType().Name;
                
                    if (attrName.Equals(attributeName))
                    {
                        columList.Add(item.Name);
                    }
                }             
            }
            return columList;
        }
    }
}
 
 
namespace MyPreContentTeach.ORM
{
    [Serializable]
    public class Student
    {
        [PrimaryKey]
        [Identity]
        public int StudentId { get; set; }
        public string StudentName { get; set; }
        public DateTime Birthday { get; set; }
        public string Gender { get; set; }
        public string StudentIdNo { get; set; }
        public int Age { get; set; }
        public string StuImage { get; set; }
        public string PhoneNumber { get; set; }
        public string StudentAddress { get; set; }
        public string CardNo { get; set; }
        public int ClassId { get; set; }
        //扩展属性
        [NonTable]
        public string ClassName { get; set; }
    }
    /// <summary>
    /// 标识列特性
    /// </summary>
    public class IdentityAttribute : Attribute
    {
        public bool IsIdentity { get; } = true;
    }
    /// <summary>
    /// 扩展属性
    /// </summary>
    public class NonTableAttribute : Attribute
    {
        public bool IsNotField { get; } = true;
    }
    /// <summary>
    /// 主键属性
    /// </summary>
    public class PrimaryKeyAttribute : Attribute
    {
        public bool IsPKey { get; } = true;
    }
    //根据需要添加其他的特性...
}
 
 
 
namespace MyPreContentTeach.ORM
{
    class Program
    {
        static void Main(string[] args)
        {
            IQueryableAndIEnumerable TestClass1 = new IQueryableAndIEnumerable();
            //TestClass1.Test1();
            TestClass1.Test2();
            #region  属性和特性
            //封装对象
            Student student = new Student()
            {
                StudentName = "喜科堂VIP高级学员",
                Gender = "女",
                Birthday = Convert.ToDateTime("1997-10-10"),
                StudentIdNo = "120223199710101513",
                PhoneNumber = "022-99888890",
                StudentAddress = "该用户地址不详",
                CardNo = "1000003",
                ClassId = 1,
                Age = DateTime.Now.Year - Convert.ToDateTime("1997-10-10").Year,
                StuImage = ""
            };
            PropertityStudy propertityStudy = new PropertityStudy();
            propertityStudy.GetAllPropertiesFromModel(student);
            Console.WriteLine("++++++++++++++++++++++++++++");
            propertityStudy.GetAllPropertiesFromModel(new SysAdmin
            {
                LoginId = 10000,
                LoginPwd = "123456",
                AdminName = "LLR"
            });
            Console.WriteLine("++++++++++++++++++++++++++++");
            propertityStudy.CreateInsertSQL(student);
            Console.WriteLine("++++++++++++++++++++++++++++");
            AttributeStudy attributeStudy = new AttributeStudy();
            attributeStudy.GetAllAttributesFromModel(student);
            Console.Read();
        }
        #endregion
    }
}
 
 
 
 
 
posted @ 2019-04-08 18:12  瀚海行舟  阅读(230)  评论(0编辑  收藏  举报