创建更好的实体以及映射继承和聚合

一、使用可空类型定义更好的实体        
    当我们需要从数据库中读取数据时,常常需要进行DBNull或null检验,为了避免这种吃屎的感觉,我们可以考虑使用可空类型以避免空值检验。
     那么,如何定义可空类型呢?值得注意的是,只有值类型能够被定义为可空类型,原因是引用类型本身就已经是可空类型了。ok,现在就可以扯一下可空类型的定义方式了:
     1. 通过泛型类型Nullabel<T>显示定义,其中T是相应的数据类型
     2. 在数据类型后面加上“?”
     那么,可空类型如何进行检验呢?实际上可以使用空结合运算符“??”来进行检验。
     举个例子:int? x=y??0
     描述:当y非空时,x=y;当y为null时,x=0;
【示例】

现在我在数据库表中建了3个可空字段,其中两个使用了可空类型,一个没有,现在来看其是否会报错,报错的类型是什么?

using System;
using System.Linq;
using System.Data.Linq;

namespace 演示针对LINQtoSQL实体类的可空类型
{
    class Program
    {
        static void Main(string[] args)
        {
            NewDataContext context = new NewDataContext();
            Table<OrderDetail> orderDetails = context.GetTable<OrderDetail>();

            context.Log = Console.Out;
            Array.ForEach(orderDetails.ToArray(), item => Console.WriteLine(item));
            Console.ReadLine();
        }
    }
}
using System.Data.Linq;

namespace 演示针对LINQtoSQL实体类的可空类型
{
    public class NewDataContext:DataContext
    {
        private static readonly string connectionString = "Data Source=.;Initial Catalog=db_Customer;Integrated Security=true";

        public NewDataContext():base(connectionString)
        {
            
        }
    }
}
using System;
using System.Linq;
using System.Text;
using System.Data.Linq.Mapping;
using System.Reflection;

namespace 演示针对LINQtoSQL实体类的可空类型
{
    [Table(Name ="tb_OrderDetail")]
    public class OrderDetail
    {
        [Column(IsPrimaryKey =true)]
        public string OrderID { get; set; }
        [Column()]
        public string ProductID { get; set; }
        [Column(CanBeNull =true)]
        public Nullable<decimal> UnitPrice { get; set; } 
        [Column(CanBeNull =true)]
        public int? Quantity { get; set; }
        [Column(CanBeNull =true)]
        public Nullable<double> Discount { get; set; }
        /// <summary>
        /// 转储实体
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            PropertyInfo[] props = this.GetType().GetProperties();
            StringBuilder builder = new StringBuilder();

            Array.ForEach(props.ToArray(), prop =>
                 builder.AppendFormat("{0}:{1}", prop.Name,
                     prop.GetValue(this, null) == null ? "<Empty>\n" : prop.GetValue(this, null).ToString()+"\n"));
            return builder.ToString();
        }
    }
}


二、为LINQ to SQL映射继承层次结构
     LINQ to SQL支持单表映射方式。假设有一个基类和若干个子类。单表映射即是说,一个表拥有这个父类和所有子类的全部持久化属性的并集,且无重复。那么,问题来了,表中的属性如何区分呢?即某个属性属于哪一个类呢?因此我们需要使用某种标记即一些键来帮助我们。对于未被某个特定类所使用的列,需要为该列赋null值。单表映射好处在于,当我们获取数据时不用执行联接或多表扫描。

    举个例子来说,加入我们定义一个Person类,它有唯一标识符PersonID,以及属性KindKey(人员类型)、Name(姓名),之后再定义一个Student类,有属性Sex、Age、Dept,最后再定义一个Teacher类,有属性Sex、TeacherID等。单表映射将含有这些列。
单表映射
PersonIDintunchecked(表示是否允许空值,不允许)
KindKeynvarchar(20)unchecked
Namenvarchar(20)unchecked  除了基类中的列之外,其他的均为null。
Sexnchar(1)checked(允许)
Ageintchecked     原因在于,对于数据行所表示的不同的类,由于某些行可能有也可能没有意义,这样做提高灵活性
Deptnvarchar(20)checked   基类除了TableAttribute之外,还有一个InheritanceMappingAttribute指示数据行所能表示的全部可能类型
Gradenvarchar(20)checked  它的命名参数code映射到基类中的鉴别器代码值上
TeacherIDintchecked   鉴别器用于指示当前数据行所表示的对象类型
Professionnvarchar(10)checked

【示例】通过单表和鉴别器来映射继承层次结构,鉴别器将告诉LINQ需要创建哪种类型的人
using System;
using System.Linq;
using System.Text;
using System.Data.Linq.Mapping;
using System.Reflection;

namespace 为LINQtoSQL映射继承层次结构
{
    [Table(Name ="tb_S")]
    //命名参数code映射到基类中的鉴别器([Column(IsDiscriminator =true)])代码值上
    //鉴别器用于指示当前数据行所表示的对象类型
    [InheritanceMapping(Code ="P",Type =typeof(Person),IsDefault =true)]
    [InheritanceMapping(Code ="S",Type =typeof(Student))]
    [InheritanceMapping(Code ="C",Type =typeof(Company))]
    public class Person
    {
        [Column(IsPrimaryKey =true)]
        public int PersonID { get; set; }
        //鉴别器
        [Column(IsDiscriminator =true)]
        public string KindKey { get; set; }
        [Column()]
        public string Name { get; set; }
        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            PropertyInfo[] props = this.GetType().GetProperties();
            builder.AppendFormat("Type:{0}\n", this.GetType().Name);

            Array.ForEach(props.ToArray(), prop =>
                 builder.AppendFormat("{0}:{1}", prop.Name,
                     prop.GetValue(this, null) == null ? "<empty>\n" :
                     prop.GetValue(this, null).ToString() + "\n"));
            return builder.ToString();
        }
    }
}
using System.Data.Linq.Mapping;

namespace 为LINQtoSQL映射继承层次结构
{
    public class Student:Person
    {
        [Column(CanBeNull =true)]
        public string Sex { get; set; }
        [Column(CanBeNull =true)]
        public int? Age { get; set; }
        [Column(CanBeNull =true)]
        public string Dept { get; set; }
    }
}
using System.Data.Linq.Mapping;

namespace 为LINQtoSQL映射继承层次结构
{
    public class Company:Person
    {
        [Column()]
        public int? CompanyID { get; set; }
        [Column()]
        public string CompanyKind { get; set; } 
    }
}
using System;
using System.Data.Linq;
using System.Data.Linq.Mapping;

namespace 为LINQtoSQL映射继承层次结构
{
    [Database(Name="db_Test")]
    public class NewDataContext:DataContext
    {
        private static readonly string connectionString = "Data Source=.;Initial Catalog=db_Test;Integrated Security=true";

        public NewDataContext():base(connectionString)
        {
            this.Log = Console.Out;
        }
        public Table<Student> GetStudents()
        {
            return this.GetTable<Student>();
        }
        public Table<Company> GetCompanies()
        {
            return this.GetTable<Company>();
        }
    }
}
using System;
using System.Linq;
using System.Data.Linq;

namespace 为LINQtoSQL映射继承层次结构
{
    class Program
    {
        static void Main(string[] args)
        {
            NewDataContext context = new NewDataContext();
            Table<Person> people = context.GetTable<Person>();
            Array.ForEach(people.Where(
                person => person.GetType() == typeof(Student)).ToArray(), r => Console.WriteLine(r));
            Console.ReadLine();
        }
    }
}



分析:上述这张数据库表,它的每一行数据都表示多个类中的一个,而这些是通过继承关系关联到一起的。然后需要进一步涉及该表中有一个字段,这个字段的值指示改行所表示的对象的类型。

三、将EntitySet类添加为属性
      关联表示的是,类A引用了类B,但并不会控制其生命周期。在C#中,任何使用内部类型的属性都可以称为是一个关联。由于C#有回收机制,因此没有什么东西是独立的,即任何东西只要不是继承那么就是一个关联。由于C#能够创建类的实例,因此我们可以将含有类成员的那些类看作是复合而构成的聚合体。

      EntitySet<T>是一个泛型类型,其中T是根据需要加载的实体类的类型。EntitySet用于表示一个复合体,其中,一个类拥有一个或多个下级类。例如,客户拥有他们自己的订单,因此可以定义一个属性,其类型为EntitySet<Order>。访问这个EntitySet属性时,LINQ就会从这个EntitySet中加载数据。
【示例】
using System;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections;

namespace 将EntitySet类添加为属性
{
    [Table(Name ="tb_Customer")]
    public class Customer
    {
        [Column(IsPrimaryKey =true)]
        public string CustomerID { get; set; }
        [Column()]
        public string CompanyName { get; set; }
        [Column()]
        public string ContactName { get; set; }
        [Column()]
        public string ContactTitle { get; set; }
        [Column()]
        public string Address { get; set; }
        [Column()]
        public string City { get; set; }
        [Column()]
        public string Region { get; set; }
        [Column()]
        public string PostalCode { get; set; }
        [Column()]
        public string Country { get; set; }
        [Column()]
        public string Phone { get; set; }
        [Column()]
        public string Fax { get; set; }
        private EntitySet<Order> orders;

        [Association(Storage ="orders",OtherKey ="CustomerID")]
        public EntitySet<Order> Orders
        {
            get { return orders; }
            set { orders.Assign(value); }
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            PropertyInfo[] props = this.GetType().GetProperties();
            Array.ForEach(props.ToArray(), prop =>
            {
                object obj = prop.GetValue(this, null);
                if (obj is IList)
                    (obj as IList).AppendEntitySet(builder);
                else
                {
                    builder.AppendFormat("{0}:{1}", prop.Name, prop.GetValue(this,null) == null ? "<empty>\n" : 
                        prop.GetValue(this, null).ToString() + "\n");
                }
            });
            return builder.ToString();
        }
    }
}
using System.Collections;
using System.Text;

namespace 将EntitySet类添加为属性
{
    public static class ExtendList
    {
        public static void AppendEntitySet(this IList entity, StringBuilder builder)
        {
            foreach (var obj in entity)
            {
                builder.AppendFormat("{0}\n", obj.ToString());
            }
        }
    }
}

using System;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Text;
using System.Reflection;

namespace 将EntitySet类添加为属性
{
    [Table(Name ="tb_Order")]
    public class Order
    {
        [Column(IsPrimaryKey =true)]
        public string OrderID { get; set; }
        [Column()]
        public string CustomerID { get; set; }
        [Column()]
        public string EmployeeID { get; set; }
        [Column(CanBeNull =true)]
        public DateTime? OrderDate { get; set; }
        [Column(CanBeNull =true)]
        public DateTime? RequiredDate { get; set; }
        public override string ToString()
        {
            var builder = new StringBuilder();
            PropertyInfo[] props = this.GetType().GetProperties();
            Array.ForEach(props.ToArray(), prop =>
            {
                builder.AppendFormat("\t{0}:{1}", prop.Name,
                    prop.GetValue(this, null) == null ? "<Empty>\n" :
                    prop.GetValue(this, null).ToString() + "\n");
            });
            return builder.ToString();
        }
    }
}
using System;
using System.Data.Linq;

namespace 将EntitySet类添加为属性
{
    public class NewDataContext:DataContext
    {
        private static readonly string connectionString = "Data Source=.;Initial Catalog=db_Customer;Integrated Security=true";

        public NewDataContext():base(connectionString)
        {
            this.Log = Console.Out;
        }

        public Table<Customer> GetCustomers()
        {
            return this.GetTable<Customer>();
        }
    }
}
using System;
using System.Data.Linq;
using System.Linq;

namespace 将EntitySet类添加为属性
{
    class Program
    {
        static void Main(string[] args)
        {
            NewDataContext context = new NewDataContext();
            Table<Customer> customers = context.GetCustomers();

            Array.ForEach(customers.ToArray(), c =>
            {
                Console.WriteLine(c);
            });
            Console.ReadKey();
        }
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值