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:
- Configuring One-to-Many Associations
-
Configuring One-to-Many Self-Reference Associations
- Configuring One-To-Many Associations Between an Existing Type and an Artificial Type
- Configuring One-to-Many Artificial Associations Between Existing CLR Types
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