One Sided Associations
This article is relevant to entity models that utilize the deprecated Visual Studio integration of Telerik Data Access. The current documentation of the Data Access framework is available here.
Normally, in your business object layer, you have one-to-many or many-to-many relations between the objects. However, there are certain scenarios where you will have only one sided relations. For example, consider the Product - Category relation. If you create a domain model, you have an one-to-many association. That means, the Product entity will have a reference to the Category, and the Category entity will have a collection of Products (IList<Product>). One sided association means that only one navigation end will exist, but not both of them. For example, the Product entity will have a reference to the Category, however the Category entity will not have an opposite relation. The opposite scenario is also valid. The Category entity will have a reference to the Product (via the IList<Product> property), but the Product entity will not know about the Category class. The last one is also known as a one sided collection association.
One Sided Association
The following example demonstrates how to create one sided association between the Person and Address classes. Sample FluentMetadataSource implementation could be found at the end of the topic. The Person class has a reference to the Address. However, the opposite relation does not exist - the Address class does not have a reference to the Person class. In regular one-to-many associations, the Person class will have a reference to Address and the Address class will have a collection of Person objects.
Configuring one sided associations is absolutely the same as the configuration of normal (one-to-many or many-to-many) associations. The main difference is that you have to specify only one navigation end (only at the side of the Person class because the opposite relation does not exist). In the code-snippet below mapping configurations for the Address and the Person objects are created first. By using the HasAssociation and the ToColumn methods, a new association (on the side of the Person class) is created. The HasAssociation method specifies the reference property that is mapped - in this case this is the HomeAddress property. Finally, the ToColumn method specifies the column name that this navigation property is mapped to. Or in other words, the ToColumn method specifies the foreign key column in the People table.
Note that when you have to create one sided associations, the WithOpposite methods are not used.
personConfiguration.HasAssociation( p => p.HomeAddress ).ToColumn( "AddressId" );
personConfiguration.HasAssociation(Function(p) p.HomeAddress).ToColumn("AddressId")
One Sided Collection Association
Creating one sided collection association is similar to the one sided associations. The following example demonstrates how to create one sided collection association between the VendorContact and Vendor classes. Sample FluentMetadataSource implementation could be found at the end of the topic. The situation is similar to the previous example - there is only one navigation end. However, in this demo, the Vendor class has a collection of VendorContact objects (IList<VendorContact>), and the opposite relation does not exist.
In the code-snippet below, mapping configurations for the Vendor and VendorContact classes are created first. By using the HasAssociation and the ToColumn methods, a new association (on the side of the Vendor class) is created. The HasAssociation method defines the mapping for a collection property - in this case this is the VendorContacts property. Finally, the ToColumn method specifies the column name that this navigation property is mapped to. Or in other words, the ToColumn method specifies the foreign key column in the VendorContacts table.
Note, that when you define an one sided collection association, the ToColumn method will create (add) a column in the other table. In this example, the ToColumn method will add a new column in the VendorContacts table. This is the way the Fluent Mapping API works.
vendorConfiguration.HasAssociation( p => p.VendorContacts ).ToColumn( "VendorId" );
vendorConfiguration.HasAssociation(Of VendorContact)(Function(p) p.VendorContacts). _
ToColumn("VendorId")
Person
public class Person
{
public int Id {get;set;}
public string Name {get;set;}
public int AddressId {get;set;}
public Address HomeAddress {get;set;}
}
Public Class Person
Private _id As Integer
Public Property Id() As Integer
Get
Return _id
End Get
Set(ByVal value As Integer)
_id = value
End Set
End Property
Private _name As String
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Private _addressId As Integer
Public Property AddressId() As Integer
Get
Return _addressId
End Get
Set(ByVal value As Integer)
_addressId = value
End Set
End Property
Private _homeAddress As Address
Public Property HomeAddress() As Address
Get
Return _homeAddress
End Get
Set(ByVal value As Address)
_homeAddress = value
End Set
End Property
End Class
Address
public class Address
{
public int Id {get;set;}
public string Description {get;set;}
}
Public Class Address
Private _id As Integer
Public Property Id() As Integer
Get
Return _id
End Get
Set(ByVal value As Integer)
_id = value
End Set
End Property
Private _description As String
Public Property Description() As String
Get
Return _description
End Get
Set(ByVal value As String)
_description = value
End Set
End Property
End Class
Vendor
public class Vendor
{
public Vendor()
{
this.VendorContacts = new List<VendorContact>();
}
public int Id { get; set; }
public string Name { get; set; }
public IList<VendorContact> VendorContacts { get; set; }
}
Public Class Vendor
Public Sub New()
VendorContacts = New List(Of VendorContact)
End Sub
Private _id As Integer
Public Property Id As Integer
Get
Return _id
End Get
Set(value As Integer)
_id = value
End Set
End Property
Private _name As String
Public Property Name As String
Get
Return _name
End Get
Set(value As String)
_name = value
End Set
End Property
Private _vendorContacts As IList(Of VendorContact)
Public Property VendorContacts As IList(Of VendorContact)
Get
Return _vendorContacts
End Get
Set(value As IList(Of VendorContact))
_vendorContacts = value
End Set
End Property
End Class
VendorContact
public class VendorContact
{
public int Id { get; set; }
public string ContactType { get; set; }
}
Public Class VendorContact
Private _id As Integer
Public Property Id As Integer
Get
Return _id
End Get
Set(value As Integer)
_id = value
End Set
End Property
Private _contactType As String
Public Property ContactType As String
Get
Return _contactType
End Get
Set(value As String)
_contactType = value
End Set
End Property
End Class
Sample FluentMetadataSource Implementation - One Sided Association
public class FluentModelMetadataSource : FluentMetadataSource
{
protected override IList<MappingConfiguration> PrepareMapping()
{
List<MappingConfiguration> configurations = new List<MappingConfiguration>();
MappingConfiguration<Person> personConfiguration = new MappingConfiguration<Person>();
personConfiguration.MapType( p => new
{
p.Id,
p.AddressId,
p.Name
} ).ToTable( "People" );
personConfiguration.HasProperty( p => p.Id ).IsIdentity();
MappingConfiguration<Address> addressConfiguration = new MappingConfiguration<Address>();
addressConfiguration.MapType( a => new
{
a.Id,
a.Description
} ).ToTable( "Addresses" );
addressConfiguration.HasProperty( a => a.Id ).IsIdentity();
personConfiguration.HasAssociation( p => p.HomeAddress ).ToColumn( "AddressId" );
configurations.Add( personConfiguration );
configurations.Add( addressConfiguration );
return configurations;
}
}
Public Class FluentModelMetadataSource
Inherits FluentMetadataSource
Protected Overrides Function PrepareMapping() As _
System.Collections.Generic.IList(Of Telerik.OpenAccess.Metadata.Fluent.MappingConfiguration)
Dim configurations As List(Of MappingConfiguration) = New List(Of MappingConfiguration)()
Dim personConfiguration As New MappingConfiguration(Of Person)()
personConfiguration.MapType(Function(p) New With {
Key p.Id, Key p.AddressId,
Key p.Name}).ToTable("People")
personConfiguration.HasProperty(Function(p) p.Id).IsIdentity()
personConfiguration.FieldNamingRules.AddPrefix = "_"
Dim addressConfiguration As New MappingConfiguration(Of Address)()
addressConfiguration.MapType(Function(a) New With {
Key a.Id, Key a.Description}).ToTable("Addresses")
addressConfiguration.HasProperty(Function(a) a.Id).IsIdentity()
addressConfiguration.FieldNamingRules.AddPrefix = "_"
personConfiguration.HasAssociation(Function(p) p.HomeAddress).ToColumn("AddressId")
configurations.Add(personConfiguration)
configurations.Add(addressConfiguration)
Return configurations
End Function
End Class
Sample FluentMetadataSource Implementation - One Sided Collection Association
public class FluentModelMetadataSource : FluentMetadataSource
{
protected override IList<MappingConfiguration> PrepareMapping()
{
List<MappingConfiguration> configurations = new List<MappingConfiguration>();
MappingConfiguration<Vendor> vendorConfiguration = new MappingConfiguration<Vendor>();
vendorConfiguration.MapType( p => new
{
VendordId = p.Id,
Name = p.Name
} ).ToTable( "Vendors" );
vendorConfiguration.HasProperty( p => p.Id ).IsIdentity();
MappingConfiguration<VendorContact> vendorContactConfiguration = new MappingConfiguration<VendorContact>();
vendorContactConfiguration.MapType( a => new
{
VendorContactId = a.Id,
Type = a.ContactType
} ).ToTable( "VendorContacts" );
vendorContactConfiguration.HasProperty( a => a.Id ).IsIdentity();
vendorConfiguration.HasAssociation( p => p.VendorContacts ).ToColumn( "VendorId" );
configurations.Add( vendorConfiguration );
configurations.Add( vendorContactConfiguration );
return configurations;
}
}
Public Class FluentModelMetadataSource
Inherits FluentMetadataSource
Protected Overrides Function PrepareMapping() As IList(Of MappingConfiguration)
Dim configurations As New List(Of MappingConfiguration)()
Dim vendorConfiguration As New MappingConfiguration(Of Vendor)()
vendorConfiguration.MapType(Function(p) New With {
Key .VendordId = p.Id,
Key .Name = p.Name}).ToTable("Vendors")
vendorConfiguration.HasProperty(Function(p) p.Id).IsIdentity()
vendorConfiguration.FieldNamingRules.AddPrefix = "_"
Dim vendorContactConfiguration As New MappingConfiguration(Of VendorContact)()
vendorContactConfiguration.MapType(Function(a) New With {
Key .VendorContactId = a.Id,
Key .Type = a.ContactType}).ToTable("VendorContacts")
vendorContactConfiguration.HasProperty(Function(a) a.Id).IsIdentity()
vendorContactConfiguration.FieldNamingRules.AddPrefix = "_"
vendorConfiguration.HasAssociation(Of VendorContact)(Function(p) p.VendorContacts).ToColumn("VendorId")
configurations.Add(vendorConfiguration)
configurations.Add(vendorContactConfiguration)
Return configurations
End Function
End Class