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

One-to-Many 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.

This topic teaches you how to create one-to-many artificial associations, as follows:

You need to use/import the Telerik.OpenAccess.Metadata.Fluent.Artificial namespace.

Configuring One-To-Many Associations

This section demonstrates how to create one-to-many associations between artificial types. In the following example, two artificial types are declared - Product and Category. Several artificial properties are created. Finally, the pair methods HasArtificialAssociation/WithOppositeCollection and HasArtificialCollectionAssociation/WithOpposite are used for the creation of an one-to-many relationship between the Product and Category types. The HasArtificialAssociation method is used to specify that the Product type will have a reference to a Category object (this is specified via the categoryConfiguration.ConfiguredType parameter). The WithOppositeCollection method specifies the inverse property of the relation. In this case the inverse property will be named "Products". Similarly, you have to create the second association end. The HasArtificialCollectionAssociation method specifies that the Category type will have a reference to a collection of Product objects. Again, the WithOpposite method is used to specify the inverse property of the relation. Sample FluentMetadataSource implementation could be found at the end of the topic.

productConfiguration.
   HasArtificialAssociation( "Category", categoryConfiguration.ConfiguredType ).
   WithOppositeCollection( "Products" );
categoryConfiguration.
   HasArtificialCollectionAssociation( "Products", productConfiguration.ConfiguredType ).
   WithOpposite( "Category" );
productConfiguration.
    HasArtificialAssociation("Category", categoryConfiguration.ConfiguredType).
    WithOppositeCollection("Products")
categoryConfiguration.
    HasArtificialCollectionAssociation("Products", productConfiguration.ConfiguredType).
    WithOpposite("Category")

Specifying the ForeignKey Column

In the previous example Telerik Data Access will create a new foreign key column in the database with default name Id2.

However, you have the option to explicitly specify the foreign key column by using the ToColumn method:

productConfiguration.
   HasArtificialAssociation( "Category", categoryConfiguration.ConfiguredType ).
   WithOppositeCollection( "Products" ).
   ToColumn( "CategoryId" );
productConfiguration.
    HasArtificialAssociation("Category", categoryConfiguration.ConfiguredType).
    WithOppositeCollection("Products").
    ToColumn("CategoryId")

Configuring One-To-Many Self-Reference Associations

This section describes how to create one-to-many self-reference associations between artificial types. In the following example one artificial type is declared - Employee. For the purpose of this walkthrough some artificial properties are created. The creation of an one-to-many self-reference association is very similar to the creation of a regular one-to-many association. However, in this case the configured type is the same. The code below demonstrates the creation of a new one-to-many self-reference association. Sample FluentMetadataSource implementation could be found at the end of the topic.

employeeConfiguration.HasArtificialAssociation( "ReportsTo", employeeConfiguration.ConfiguredType )
   .WithOppositeCollection( "Employees" );
employeeConfiguration.HasArtificialCollectionAssociation( "Employees", employeeConfiguration.ConfiguredType )
   .WithOpposite( "ReportsTo" );
employeeConfiguration.
    HasArtificialAssociation("ReportsTo", employeeConfiguration.ConfiguredType).
    WithOppositeCollection("Employees")
employeeConfiguration.
    HasArtificialCollectionAssociation("Employees", employeeConfiguration.ConfiguredType).
    WithOpposite("ReportsTo")

Configuring One-To-Many Associations Between an Existing Type and an Artificial Type

The following example demonstrates how to configure one-to-many associations between a CLR type (the Person class) and an artificial type. Since the Person type is a real type, you have to use the generic MappingConfiguration<T> class. A new artificial type named Children with one artificial property (Name) is created. Next, a new one-to-many association is created between Person and Children. The process of creation of an one-to-many association in this case is absolutely the same as the creation of an one-to-many association between artificial types. The only difference is that you have to use the generic MappingConfiguration<T> class for the real type. Sample FluentMetadataSource implementation could be found at the end of the topic.

childrenConfiguration.
   HasArtificialAssociation( "Father", personConfiguration.ConfiguredType ).
   WithOpposite( "Children" );
childrenConfiguration.
    HasArtificialAssociation("Father", personConfiguration.ConfiguredType).
    WithOpposite("Children")

Creating One-To-Many Artificial Associations Between Existing Types

The following example demonstrates how to create a new one-to-many artificial association between the Product and Category classes. The process of creation of an one-to-many association in this case is absolutely the same as the creation of an one-to-many association between artificial types. The only difference is that you have to use the generic MappingConfiguration<T> class for the real types. Sample FluentMetadataSource implementation could be found at the end of the topic.

productConfiguration.
   HasArtificialAssociation( "Category", categoryConfiguration.ConfiguredType ).
   WithOppositeCollection( "Products" );
categoryConfiguration.
   HasArtificialCollectionAssociation( "Products", productConfiguration.ConfiguredType ).
   WithOpposite( "Category" );
productConfiguration.
    HasArtificialAssociation("Category", categoryConfiguration.ConfiguredType).
    WithOppositeCollection("Products")
categoryConfiguration.
    HasArtificialCollectionAssociation("Products", productConfiguration.ConfiguredType).
    WithOpposite("Category")

TestClass

Currently one of the limitations of Telerik Data Access is that you cannot have a Telerik Data Access project running without at least one persistent type defined. This basically means that you have to have a plain CLR type that is part of your model in order to run a Telerik Data Access project. There is no way to run Telerik Data Access entirely on artificial types. The simplest solution in this case is to add a dummy class to your model.

public class TestClass
{
   public int ID {get;set;}
}
Public Class TestClass
    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
End Class

Sample FluentMetadataSource Implementation - One-to-Many Artificial Associations

public class FluentModelMetadataSource : FluentMetadataSource
{
   protected override IList<MappingConfiguration> PrepareMapping()
   {
       List<MappingConfiguration> configurations = new List<MappingConfiguration>();

       MappingConfiguration<TestClass> testConfiguration = new MappingConfiguration<TestClass>();
       testConfiguration.MapType();
       testConfiguration.HasProperty( x => x.ID ).IsIdentity();

       MappingConfiguration productConfiguration = new MappingConfiguration( "Product", "ProductNamespace" );
       productConfiguration.HasArtificialPrimitiveProperty<int>( "Id" ).IsIdentity( KeyGenerator.Autoinc );
       productConfiguration.HasArtificialStringProperty( "ProductName" );
       productConfiguration.HasArtificialPrimitiveProperty<double>( "Price" );

       MappingConfiguration categoryConfiguration = new MappingConfiguration( "Category", "CategoryNamespace" );
       categoryConfiguration.HasArtificialStringProperty( "CategoryName" );
       categoryConfiguration.HasArtificialProperty<byte[]>( "Image" );
       categoryConfiguration.HasArtificialPrimitiveProperty<int>( "Id" ).IsIdentity( KeyGenerator.Autoinc );

       productConfiguration.
           HasArtificialAssociation( "Category", categoryConfiguration.ConfiguredType ).
           WithOppositeCollection( "Products" ).
           ToColumn( "CategoryId" );

       categoryConfiguration.
           HasArtificialCollectionAssociation( "Products", productConfiguration.ConfiguredType ).
           WithOpposite( "Category" );

       configurations.Add( productConfiguration );
       configurations.Add( categoryConfiguration );
       configurations.Add( testConfiguration );

       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 testConfiguration As New MappingConfiguration(Of TestClass)()
        testConfiguration.MapType()
        testConfiguration.HasProperty(Function(x) x.ID).IsIdentity()
        testConfiguration.FieldNamingRules.AddPrefix = "_"

        Dim productConfiguration As New MappingConfiguration("Product", "ProductNamespace")
        productConfiguration.HasArtificialStringProperty("ProductName")
        productConfiguration.HasArtificialPrimitiveProperty(Of Double)("Price")
        productConfiguration.HasArtificialPrimitiveProperty(Of Integer)("Id").IsIdentity(KeyGenerator.Autoinc)

        Dim categoryConfiguration As New MappingConfiguration("Category", "CategoryNamespace")
        categoryConfiguration.HasArtificialStringProperty("CategoryName")
        categoryConfiguration.HasArtificialProperty(Of Byte())("Image")
        categoryConfiguration.HasArtificialPrimitiveProperty(Of Integer)("Id").IsIdentity(KeyGenerator.Autoinc)

        productConfiguration.
            HasArtificialAssociation("Category", categoryConfiguration.ConfiguredType).
            WithOppositeCollection("Products").
            ToColumn("CategoryId")
        categoryConfiguration.
            HasArtificialCollectionAssociation("Products", productConfiguration.ConfiguredType).
            WithOpposite("Category")

        configurations.Add(productConfiguration)
        configurations.Add(categoryConfiguration)
        configurations.Add(testConfiguration)

        Return configurations
    End Function
End Class

Sample FluentMetadataSource Implementation - One-to-Many Self-Reference Artificial Associations

public class FluentModelMetadataSource : FluentMetadataSource
{
   protected override IList<MappingConfiguration> PrepareMapping()
   {
       List<MappingConfiguration> configurations = new List<MappingConfiguration>();

       MappingConfiguration<TestClass> testConfiguration = new MappingConfiguration<TestClass>();
       testConfiguration.MapType();
       testConfiguration.HasProperty( x => x.ID ).IsIdentity();

       MappingConfiguration employeeConfiguration = new MappingConfiguration( "Employee", "EmployeeNamespace" );
       employeeConfiguration.HasArtificialStringProperty( "Name" );
       employeeConfiguration.HasArtificialPrimitiveProperty<int>( "Id" ).IsIdentity( KeyGenerator.Autoinc );

       employeeConfiguration.HasArtificialAssociation( "ReportsTo", employeeConfiguration.ConfiguredType )
           .WithOppositeCollection( "Employees" );
       employeeConfiguration.HasArtificialCollectionAssociation( "Employees", employeeConfiguration.ConfiguredType )
           .WithOpposite( "ReportsTo" );

       configurations.Add( employeeConfiguration );
       configurations.Add( testConfiguration );

       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 testConfiguration As New MappingConfiguration(Of TestClass)()
        testConfiguration.MapType()
        testConfiguration.HasProperty(Function(x) x.ID).IsIdentity()
        testConfiguration.FieldNamingRules.AddPrefix = "_"

        Dim employeeConfiguration As New MappingConfiguration("Employee", "EmployeeNamespace")
        employeeConfiguration.HasArtificialStringProperty("Name")
        employeeConfiguration.HasArtificialPrimitiveProperty(Of Integer)("Id").IsIdentity(KeyGenerator.Autoinc)

        employeeConfiguration.
            HasArtificialAssociation("ReportsTo", employeeConfiguration.ConfiguredType).
            WithOppositeCollection("Employees")
        employeeConfiguration.
            HasArtificialCollectionAssociation("Employees", employeeConfiguration.ConfiguredType).
            WithOpposite("ReportsTo")

        configurations.Add(employeeConfiguration)
        configurations.Add(testConfiguration)

        Return configurations
    End Function
End Class

Person Class

public class Person
{
   public int Id {get;set;}
   public string FirstName {get;set;}
   public string LastName {get;set;}
   public string Address {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 _firstName As String
    Public Property FirstName() As String
        Get
            Return _firstName
        End Get
        Set(ByVal value As String)
            _firstName = value
        End Set
    End Property

    Private _lastName As String
    Public Property LastName() As String
        Get
            Return _lastName
        End Get
        Set(ByVal value As String)
            _lastName = value
        End Set
    End Property

    Private _address As String
    Public Property Address() As String
        Get
            Return _address
        End Get
        Set(ByVal value As String)
            _address = value
        End Set
    End Property
End Class

Sample FluentMetadataSource Implementation - One-To-Many Associations Between an Existing Type and an Artificial Type

public class FluentModelMetadataSource : FluentMetadataSource
{
   protected override IList<MappingConfiguration> PrepareMapping()
   {
       List<MappingConfiguration> configurations = new List<MappingConfiguration>();

       MappingConfiguration<Person> personConfiguration = new MappingConfiguration<Person>();
       personConfiguration.MapType().ToTable( "People" );
       personConfiguration.HasProperty( p => p.Id ).IsIdentity( KeyGenerator.Autoinc );

       MappingConfiguration childrenConfiguration = new MappingConfiguration( "Children", "ChildrenNamespace" );
       childrenConfiguration.HasArtificialStringProperty( "Name" );
       childrenConfiguration.HasArtificialPrimitiveProperty<int>( "Id" ).IsIdentity();

       childrenConfiguration.
           HasArtificialAssociation( "Father", personConfiguration.ConfiguredType ).
           WithOpposite( "Children" );

       configurations.Add( personConfiguration );
       configurations.Add( childrenConfiguration );

       return configurations;
   }
}
Public Class FluentModelMetadataSource
    Inherits FluentMetadataSource
    Protected Overrides Function PrepareMapping() As IList(Of MappingConfiguration)
        Dim configurations As New List(Of MappingConfiguration)()

        Dim personConfiguration As New MappingConfiguration(Of Person)()
        personConfiguration.MapType().ToTable("People")
        personConfiguration.HasProperty(Function(p) p.Id).IsIdentity(KeyGenerator.Autoinc)
        personConfiguration.FieldNamingRules.AddPrefix = "_"

        Dim childrenConfiguration As New MappingConfiguration("Children", "ChildrenNamespace")
        childrenConfiguration.HasArtificialStringProperty("Name")
        childrenConfiguration.HasArtificialPrimitiveProperty(Of Integer)("Id").IsIdentity()

        childrenConfiguration.
            HasArtificialAssociation("Father", personConfiguration.ConfiguredType).
            WithOpposite("Children")

        configurations.Add(personConfiguration)
        configurations.Add(childrenConfiguration)

        Return configurations
    End Function
End Class

Product Class

public class Product
{
   public int Id {get;set;}
   public string Name {get;set;}
}
Public Class Product
    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(ByVal value As String)
            _name = value
        End Set
    End Property
End Class

Category Class

public class Category
{
   public int Id { get; set; }
   public string Name {get;set;}
}
Public Class Category
    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(ByVal value As String)
            _name = value
        End Set
    End Property
End Class

Sample FluentMetadataSource Implementation - One-To-Many Artificial Associations Between Existing Types

public class FluentModelMetadataSource : FluentMetadataSource
{
   protected override IList<MappingConfiguration> PrepareMapping()
   {
       IList<MappingConfiguration> preparedConfigurations = new List<MappingConfiguration>();

       MappingConfiguration<Product> productConfiguration = new MappingConfiguration<Product>();
       productConfiguration.MapType( p => new
                                               {
                                                   Id = p.Id,
                                                   Name = p.Name
                                               } );
       productConfiguration.HasProperty( p => p.Id ).IsIdentity( KeyGenerator.Autoinc );

       MappingConfiguration<Category> categoryConfiguration = new MappingConfiguration<Category>();
       categoryConfiguration.MapType( c => new
                                               {
                                                   Id = c.Id,
                                                   CategoryName = c.Name
                                               } );
       categoryConfiguration.HasProperty( p => p.Id ).IsIdentity( KeyGenerator.Autoinc );

       productConfiguration.
           HasArtificialAssociation( "Category", categoryConfiguration.ConfiguredType ).
           WithOppositeCollection( "Products" );
       categoryConfiguration.
           HasArtificialCollectionAssociation( "Products", productConfiguration.ConfiguredType ).
           WithOpposite( "Category" );

       preparedConfigurations.Add( categoryConfiguration );
       preparedConfigurations.Add( productConfiguration );

       return preparedConfigurations;
   }
}
Public Class FluentModelMetadataSource
    Inherits FluentMetadataSource
    Protected Overrides Function PrepareMapping() As IList(Of MappingConfiguration)
        Dim preparedConfigurations As IList(Of MappingConfiguration) = New List(Of MappingConfiguration)()

        Dim productConfiguration As New MappingConfiguration(Of Product)()
        productConfiguration.MapType(Function(p) New With {Key .Id = p.Id, Key .Name = p.Name})
        productConfiguration.HasProperty(Function(p) p.Id).IsIdentity(KeyGenerator.Autoinc)
        productConfiguration.FieldNamingRules.AddPrefix = "_"

        Dim categoryConfiguration As New MappingConfiguration(Of Category)()
        categoryConfiguration.MapType(Function(c) New With {Key .Id = c.Id, Key .CategoryName = c.Name})
        categoryConfiguration.HasProperty(Function(p) p.Id).IsIdentity(KeyGenerator.Autoinc)
        categoryConfiguration.FieldNamingRules.AddPrefix = "_"

        productConfiguration.
            HasArtificialAssociation("Category", categoryConfiguration.ConfiguredType).
            WithOppositeCollection("Products")
        categoryConfiguration.
            HasArtificialCollectionAssociation("Products", productConfiguration.ConfiguredType).
            WithOpposite("Category")

        preparedConfigurations.Add(categoryConfiguration)
        preparedConfigurations.Add(productConfiguration)

        Return preparedConfigurations
    End Function
End Class