Como mapear relacionamentos de banco de dados
Você pode codificar como referências de propriedade em sua classe de entidade todas as relações de dados que serão sempre as mesmas. No banco de dados de exemplo Northwind, por exemplo, como os clientes geralmente fazem os pedidos, há sempre uma relação no modelo entre os clientes e seus pedidos.
O LINQ to SQL define um atributo AssociationAttribute para ajudar a representar essas relações. Esse atributo é usado junto com os tipos EntitySet<TEntity> e EntityRef<TEntity> para representar o que seria um relacionamento de chave estrangeira em um banco de dados. Para obter mais informações, consulte a seção Atributo de Associação do Mapeamento baseado em atributo.
Observação
Os valores de propriedade de armazenamento AssociationAttribute e ColumnAttribute diferenciam maiúsculas de minúsculas. Por exemplo, verifique se os valores usados no atributo para a propriedade AssociationAttribute.Storage coincidem maiúsculas e minúsculas para os nomes de propriedades correspondentes usados em outro lugar no código. Isso se aplica a todas as linguagens de programação do .NET, mesmo as que normalmente não diferenciam maiúsculas de minúsculas, incluindo o Visual Basic. Para obter mais informações sobre a propriedade Storage, consulte DataAttribute.Storage.
A maioria da relações são um-para-muitos, como no exemplo mais adiante neste tópico. Você também pode representar relações um-para-um e muitos-para-muitos da seguinte maneira:
Um-para-um: representa esse tipo de relação incluindo EntitySet<TEntity> em ambos os lados.
Por exemplo, considere uma relação
Customer
-SecurityCode
, criada de modo que o código de segurança do cliente não seja encontrado na tabelaCustomer
e possa ser acessado somente por pessoas autorizadas.Muitos-para-muitos: em relações muitos-para-muitos, a chave primária da tabela de vínculo (também chamada de tabela de junção) é formada geralmente por uma composição de chaves estrangeiras das outras duas tabelas.
Por exemplo, considere uma relação muitos-para-muitos
Employee
-Project
formada com a tabela de vínculoEmployeeProject
. O LINQ to SQL requer que esse relacionamento seja modelado usando três classes:Employee
,Project
eEmployeeProject
. Nesse caso, alterar a relação entre umEmployee
e umProject
pode parecer exigir uma atualização da chave primáriaEmployeeProject
. No entanto, essa situação é melhor modelada como excluindo umEmployeeProject
existente e criando um novoEmployeeProject
.Observação
As relações em bancos de dados relacionais são normalmente modeladas como os valores de chave estrangeira que referenciam as chaves primárias em outras tabelas. Para navegar entre elas, você associa explicitamente as duas tabelas usando uma operação de junção relacional.
No entanto, objetos no LINQ to SQL fazem referência entre si usando as referências de propriedade ou coleções de referências que você navega usando a notação dot.
Exemplo 1
No exemplo de um-para-muitos a seguir, a classe Customer
tem uma propriedade que declara a relação entre os clientes e seus pedidos. A propriedade Orders
é do tipo EntitySet<TEntity>. Este tipo significa que essa relação é de um-para-muitos (um cliente para vários pedidos). A propriedade OtherKey é usada para descrever como essa associação é realizada, a saber, especificando o nome da propriedade na classe relacionada a ser comparada com essa. Nesse exemplo, a propriedade CustomerID
é comparada, assim como um join de banco de dados compararia esse valor de coluna.
Observação
Se estiver usando o Visual Studio, poderá usar o Object Relational Designer para criar uma associação entre classes.
[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
Exemplo 2
Você também pode reverter a situação. Em vez de usar a classe Customer
para descrever a associação entre clientes e pedidos, você pode usar a classe Order
. A classe Order
usa o tipo EntityRef<TEntity> para descrever a relação de volta para o cliente, como no exemplo de código a seguir.
Observação
A classe EntityRef<TEntity> dá suporte a carregamento adiado. Para obter mais informações, confira Carregamento adiado versus imediato.
[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