Практическое руководство. Сопоставление связей базы данных
Отношения данных, которые всегда останутся неизменными, можно закодировать в виде ссылок в классе сущностей. В учебной базе данных Northwind, всегда существует связь между заказчиками и их заказами, т.к. обычно заказчики размещают заказы.
LINQ to SQL определяет AssociationAttribute атрибут для представления таких связей. Этот атрибут используется совместно с типами EntitySet<TEntity> и EntityRef<TEntity> для представления в базе данных связи по внешнему ключу. Дополнительные сведения см. в разделе "Атрибут ассоциации" сопоставления на основе атрибутов.
Примечание.
В значениях свойства Storage для атрибутов AssociationAttribute и ColumnAttribute учитывается регистр. Например, следует убедиться в том, что регистр символов в значении, использованном в атрибуте свойства AssociationAttribute.Storage, соответствует регистру символов в соответствующих именах свойств в остальном коде. Это относится ко всем языкам программирования .NET, даже тем, которые обычно не учитывает регистр, включая Visual Basic. Дополнительные сведения о свойстве Storage см. в разделе DataAttribute.Storage.
Большинство связей имеют тип «один ко многим», как и в примере, представленном далее в этом разделе. Отношения "один-к-одному" и "один-ко-многим" можно представить следующим образом.
Один к одному. Этот тип связей представляется включением элементов EntitySet<TEntity> с обеих сторон.
Например, рассмотрим
Customer
-SecurityCode
связь, созданную таким образом, чтобы код безопасности клиента не был найден вCustomer
таблице и может быть доступ только авторизованным лицам.Многие ко многим: в отношениях "многие ко многим" первичный ключ таблицы ссылок (также называемой таблицей соединения ) часто формируется составом внешних ключей из двух других таблиц.
Например, рассмотрим связь "многие ко многим", сформированную
Employee
-Project
с помощью таблицы ссылок.EmployeeProject
LINQ to SQL требует, чтобы такая связь моделировалась с помощью трех классов:Employee
,Project
иEmployeeProject
. В этом случае изменение отношения междуEmployee
иProject
может потребовать обновления первичного ключа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