如何:映射数据库关系

可以在您的实体类中将始终相同的任何数据关系编码为属性引用。 例如,在 Northwind 示例数据库中,由于客户通常会下订单,因此在模型中客户与其订单之间始终存在关系。

LINQ to SQL 定义了 AssociationAttribute 属性来帮助表示此类关系。 此属性与 EntitySet<TEntity>EntityRef<TEntity> 类型一起使用,来表示将作为数据库中的外键关系的内容。 有关详细信息,请参阅基于属性的映射的“关联属性”部分。

备注

AssociationAttribute 和 ColumnAttribute Storage 属性值区分大小写。 例如,请确保 AssociationAttribute.Storage 属性 (Property) 的属性 (Attribute) 中使用的值与代码中其他位置使用的相应属性 (Property) 名称值的大小写相匹配。 这适用于所有 .NET 编程语言,即使是那些通常不区分大小写的编程语言,包括 Visual Basic。 有关 Storage 属性的更多信息,请参见 DataAttribute.Storage

大多数关系都是一对多关系,这一点在本主题后面部分的示例中会有所体现。 您还可以按如下方式来表示一对一和多对多关系:

  • 一对一:通过向双方添加 EntitySet<TEntity> 来表示此类关系。

    例如,假设有一个 Customer-SecurityCode 关系,创建此关系的目的是使得在 Customer 表中找不到客户的安全码,而只有得到授权的人才能访问此安全码。

  • 多对多:在多对多关系中,链接表(也称作联接表)的主键通常由来自其他两个表的外键组合而成。

    例如,假设有一个通过使用链接表 EmployeeProject 构成的 Employee-Project 多对多关系。 LINQ to SQL 要求使用以下三个类对这种关系进行建模:EmployeeProjectEmployeeProject。 在这种情况下,更改 EmployeeProject 之间的关系似乎需要更新主键 EmployeeProject。 但是,这种情况最好的模型化处理方法是删除现有 EmployeeProject,然后创建新的 EmployeeProject

    备注

    关系数据库中的关系通常模型化成引用其他表中主键的外键值。 若要在它们之间导航,应使用关系联接运算显式关联这两个表。

    另一方面,LINQ to SQL 中的对象通过使用属性引用或使用点表示法导航的引用集合来相互引用。

示例 1

在下面的一对多示例中,Customer 类具有一个声明客户与其订单之间的关系的属性。 Orders 属性为 EntitySet<TEntity> 类型。 此类型表明这种关系是一对多的(一个客户对多个订单)。 OtherKey 属性用来说明如何实现这种关联,即通过指定相关类中要与此属性比较的属性的名称。 在此示例中,比较的是 CustomerID 属性,比较过程就像数据库联接比较该列值一样。

备注

如果使用的是 Visual Studio,则可以使用对象关系设计器来创建类之间的关联。

[Table(Name = "Customers")]
public partial class Customer
{
    [Column(IsPrimaryKey = true)]
    public string CustomerID;
    // ...
    private EntitySet<Order> _Orders;
    [Association(Storage = "_Orders", OtherKey = "CustomerID")]
    public EntitySet<Order> Orders
    {
        get { return this._Orders; }
        set { this._Orders.Assign(value); }
    }
}
<Table(Name:="Customers")> _
Public Class Customer
    <Column(IsPrimaryKey:=True)> _
    Public CustomerID As String
    ' ...
    Private _Orders As EntitySet(Of Order)
    <Association(Storage:="_Orders", OtherKey:="CustomerID")> _
    Public Property Orders() As EntitySet(Of Order)
        Get
            Return Me._Orders
        End Get
        Set(ByVal value As EntitySet(Of Order))
            Me._Orders.Assign(value)
        End Set
    End Property
End Class

示例 2

这种情况也可以反过来处理。 您可以不使用 Customer 类来说明客户与订单之间的关联,而改用 Order 类。 Order 类使用 EntityRef<TEntity> 类型反向说明与客户的关系,如下面的代码示例所示。

备注

EntityRef<TEntity> 类支持延迟加载。 有关详细信息,请参阅 延迟加载与立即加载

[Table(Name = "Orders")]
public class Order
{
    [Column(IsPrimaryKey = true)]
    public int OrderID;
    [Column]
    public string CustomerID;
    private EntityRef<Customer> _Customer;
    [Association(Storage = "_Customer", ThisKey = "CustomerID")]
    public Customer Customer
    {
        get { return this._Customer.Entity; }
        set { this._Customer.Entity = value; }
    }
}
<Table(Name:="Orders")> _
Public Class Order
    <Column(IsPrimaryKey:=True)> _
    Public OrderID As Integer
    <Column()> _
    Public CustomerID As String
    Private _Customer As EntityRef(Of Customer)
    <Association(Storage:="Customer", ThisKey:="CustomerID")> _
    Public Property Customer() As Customer
        Get
            Return Me._Customer.Entity
        End Get
        Set(ByVal value As Customer)
            Me._Customer.Entity = value
        End Set
    End Property
End Class

另请参阅