Data Access has been discontinued. Please refer to this page for more information.

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