一、使用可空类型定义更好的实体
当我们需要从数据库中读取数据时,常常需要进行DBNull或null检验,为了避免这种吃屎的感觉,我们可以考虑使用可空类型以避免空值检验。
那么,如何定义可空类型呢?值得注意的是,只有值类型能够被定义为可空类型,原因是引用类型本身就已经是可空类型了。ok,现在就可以扯一下可空类型的定义方式了:
1. 通过泛型类型Nullabel<T>显示定义,其中T是相应的数据类型
2. 在数据类型后面加上“?”
那么,可空类型如何进行检验呢?实际上可以使用空结合运算符“??”来进行检验。
举个例子:int? x=y??0
描述:当y非空时,x=y;当y为null时,x=0;
举个例子:int? x=y??0
描述:当y非空时,x=y;当y为null时,x=0;
【示例】
现在我在数据库表中建了3个可空字段,其中两个使用了可空类型,一个没有,现在来看其是否会报错,报错的类型是什么?
![](https://i-blog.csdnimg.cn/blog_migrate/0a4c702e06c8e00fda6cac3d7116f153.png)
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等。单表映射将含有这些列。
PersonID | int | unchecked(表示是否允许空值,不允许) |
KindKey | nvarchar(20) | unchecked |
Name | nvarchar(20) | unchecked 除了基类中的列之外,其他的均为null。 |
Sex | nchar(1) | checked(允许) |
Age | int | checked 原因在于,对于数据行所表示的不同的类,由于某些行可能有也可能没有意义,这样做提高灵活性 |
Dept | nvarchar(20) | checked 基类除了TableAttribute之外,还有一个InheritanceMappingAttribute指示数据行所能表示的全部可能类型 |
Grade | nvarchar(20) | checked 它的命名参数code映射到基类中的鉴别器代码值上 |
TeacherID | int | checked 鉴别器用于指示当前数据行所表示的对象类型 |
Profession | nvarchar(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();
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/c92fffd30cdd19a0b0586c1ebba86f5c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/abc01197c5fe70c15afeea44517d5afe.png)
分析:上述这张数据库表,它的每一行数据都表示多个类中的一个,而这些是通过继承关系关联到一起的。然后需要进一步涉及该表中有一个字段,这个字段的值指示改行所表示的对象的类型。
三、将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();
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/7dabe8047cf713be51407e2ef5a0e1f6.png)