Many-to-Many Associations
This topic teaches you how to create many-to-many artificial associations, as follows:
- Many-to-Many Associations
- Configuring Many-to-Many Self-Reference Associations
- Configuring Many-to-Many Associations Between an Existing Type and an Artificial Type
- Configuring Many-to-Many Artificial Associations Between Existing CLR Types
You need to use/import the Telerik.OpenAccess.Metadata.Fluent.Artificial namespace.
Configuring Many-To-Many Associations
This section describes how to create a many-to-many association between artificial types. The following example declares two artificial types - Employee and Territory. Several primitive properties are declared for each of the types. Finally, a many-to-many association is created between the Employee and Territory types. Creating many-to-many associations is very similar to the one-to-many associations. Again, you should explicitly declare both of the association ends. However, in this case you have to use only the HasArtificialCollectionAssociation and WithOppositeCollection methods. Below is the source code demonstrating the creation of a many-to-many association between artificial types. Sample FluentMetadataSource implementation could be found at the end of the topic.
employeeConfiguration.
HasArtificialCollectionAssociation( "Territories", territoryConfiguration.ConfiguredType ).
WithOppositeCollection( "Employees" );
territoryConfiguration.
HasArtificialCollectionAssociation( "Employees", employeeConfiguration.ConfiguredType ).
WithOppositeCollection( "Territories" )
employeeConfiguration.
HasArtificialCollectionAssociation("Territories", territoryConfiguration.ConfiguredType).
WithOppositeCollection("Employees")
territoryConfiguration.
HasArtificialCollectionAssociation("Employees", employeeConfiguration.ConfiguredType).
WithOppositeCollection("Territories")
Specifying the Join Table
In the previous example Telerik Data Access will create a new join table with default name "employee_territory".
However, you have the option to explicitly specify the join table by using the MapJoinTable method.
employeeConfiguration.
HasArtificialCollectionAssociation( "Territories", territoryConfiguration.ConfiguredType ).
WithOppositeCollection( "Employees" ).MapJoinTable("EmployeeTerritory");
territoryConfiguration.
HasArtificialCollectionAssociation( "Employees", employeeConfiguration.ConfiguredType ).
WithOppositeCollection( "Territories" ).MapJoinTable( "EmployeeTerritory" );
employeeConfiguration.
HasArtificialCollectionAssociation("Territories", territoryConfiguration.ConfiguredType).
WithOppositeCollection("Employees").MapJoinTable("EmployeeTerritory")
territoryConfiguration.
HasArtificialCollectionAssociation("Employees", employeeConfiguration.ConfiguredType).
WithOppositeCollection("Territories").MapJoinTable("EmployeeTerritory")
Creating Many-To-Many Self-Reference Associations
This section describes how to create a many-to-many self-reference association 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 a many-to-many self-reference association is very similar to the creation of a regular many-to-many association. However, in this case the configured type is one and the same. The code below demonstrates the creation of many-to-many self-reference associations. Sample FluentMetadataSource implementation could be found at the end of the topic.
employeeConfiguration.
HasArtificialCollectionAssociation( "ReportsTo", employeeConfiguration.ConfiguredType ).
WithOppositeCollection( "Employees" );
employeeConfiguration.
HasArtificialCollectionAssociation( "Employees", employeeConfiguration.ConfiguredType ).
WithOppositeCollection( "ReportsTo" );
employeeConfiguration.
HasArtificialCollectionAssociation("ReportsTo", employeeConfiguration.ConfiguredType).
WithOppositeCollection("Employees")
employeeConfiguration.
HasArtificialCollectionAssociation("Employees", employeeConfiguration.ConfiguredType).
WithOppositeCollection("ReportsTo")
Creating Many-To-Many Associations Between an Existing Type And an Artificial Type
This section describes how to create a many-to-many association between a CLR type (the Employee class) and an artificial type. Since the Employee type is a real type, you have to use the generic MappingConfiguration<T> class. A new artificial type named Territory with one artificial property (Name) is created. Next, a new many-to-many association is created between the Employee and Territory. The process of creation of a many-to-many association in this case is absolutely the same as the creation of a many-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.
employeeConfiguration.
HasArtificialCollectionAssociation( "Territories", territoryConfiguration.ConfiguredType ).
WithOppositeCollection( "Employees" );
territoryConfiguration.
HasArtificialCollectionAssociation( "Employees", employeeConfiguration.ConfiguredType ).
WithOppositeCollection( "Territories" );
employeeConfiguration.
HasArtificialCollectionAssociation("Territories", territoryConfiguration.ConfiguredType).
WithOppositeCollection("Employees")
territoryConfiguration.
HasArtificialCollectionAssociation("Employees", employeeConfiguration.ConfiguredType).
WithOppositeCollection("Territories")
Creating Many-To-Many Artificial Associations Between Existing Types
The next example demonstrates how to create a new many-to-many artificial association between the Employee and Territory classes. The process of creation of a many-to-many association in this case is absolutely the same as the creation of a many-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.
employeeConfiguration.
HasArtificialCollectionAssociation( "Territories", territoryConfiguration.ConfiguredType ).
WithOppositeCollection( "Employees" );
territoryConfiguration.
HasArtificialCollectionAssociation( "Employees", employeeConfiguration.ConfiguredType ).
WithOppositeCollection( "Territories" );
employeeConfiguration.
HasArtificialCollectionAssociation("Territories", territoryConfiguration.ConfiguredType).
WithOppositeCollection("Employees")
territoryConfiguration.
HasArtificialCollectionAssociation("Employees", employeeConfiguration.ConfiguredType).
WithOppositeCollection("Territories")
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 - Many-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 employeeConfiguration = new MappingConfiguration( "Employee", "EmployeeNamespace" );
employeeConfiguration.HasArtificialPrimitiveProperty<Int32>( "Id" ).IsIdentity();
employeeConfiguration.HasArtificialStringProperty( "Name" );
employeeConfiguration.HasArtificialPrimitiveProperty<DateTime>( "HireDate" );
MappingConfiguration territoryConfiguration = new MappingConfiguration( "Territory", "TerritoryNamespace" );
territoryConfiguration.HasArtificialPrimitiveProperty<Int32>( "Id" ).IsIdentity();
territoryConfiguration.HasArtificialStringProperty( "Name" );
employeeConfiguration.
HasArtificialCollectionAssociation( "Territories", territoryConfiguration.ConfiguredType ).
WithOppositeCollection( "Employees" ).MapJoinTable( "EmployeeTerritory" );
territoryConfiguration.
HasArtificialCollectionAssociation( "Employees", employeeConfiguration.ConfiguredType ).
WithOppositeCollection( "Territories" ).MapJoinTable( "EmployeeTerritory" );
configurations.Add( employeeConfiguration );
configurations.Add( territoryConfiguration );
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.HasArtificialPrimitiveProperty(Of Int32)("Id").IsIdentity()
employeeConfiguration.HasArtificialStringProperty("Name")
employeeConfiguration.HasArtificialPrimitiveProperty(Of Date)("HireDate")
Dim territoryConfiguration As New MappingConfiguration("Territory", "TerritoryNamespace")
territoryConfiguration.HasArtificialPrimitiveProperty(Of Int32)("Id").IsIdentity()
territoryConfiguration.HasArtificialStringProperty("Name")
employeeConfiguration.
HasArtificialCollectionAssociation("Territories", territoryConfiguration.ConfiguredType).
WithOppositeCollection("Employees").MapJoinTable("EmployeeTerritory")
territoryConfiguration.
HasArtificialCollectionAssociation("Employees", employeeConfiguration.ConfiguredType).
WithOppositeCollection("Territories").MapJoinTable("EmployeeTerritory")
configurations.Add(employeeConfiguration)
configurations.Add(territoryConfiguration)
Return configurations
End Function
End Class
Sample FluentMetadataSource Implementation - Many-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<Int32>( "Id" ).IsIdentity( KeyGenerator.Autoinc );
employeeConfiguration.
HasArtificialCollectionAssociation( "ReportsTo", employeeConfiguration.ConfiguredType ).
WithOppositeCollection( "Employees" );
employeeConfiguration.
HasArtificialCollectionAssociation( "Employees", employeeConfiguration.ConfiguredType ).
WithOppositeCollection( "ReportsTo" );
configurations.Add( employeeConfiguration );
configurations.Add( testConfiguration );
return configurations;
}
}
Public Class FluentModelMetadataSource
Inherits FluentMetadataSource
Protected Overrides Function PrepareMapping() As IList(Of MappingConfiguration)
Dim configurations As New List(Of MappingConfiguration)()
Dim testConfiguration As New MappingConfiguration(Of TestClass)()
testConfiguration.MapType()
testConfiguration.FieldNamingRules.AddPrefix = "_"
testConfiguration.HasProperty(Function(x) x.ID).IsIdentity()
Dim employeeConfiguration As New MappingConfiguration("Employee", "EmployeeNamespace")
employeeConfiguration.HasArtificialStringProperty("Name")
employeeConfiguration.HasArtificialPrimitiveProperty(Of Int32)("Id").IsIdentity(KeyGenerator.Autoinc)
employeeConfiguration.
HasArtificialCollectionAssociation("ReportsTo", employeeConfiguration.ConfiguredType).
WithOppositeCollection("Employees")
employeeConfiguration.
HasArtificialCollectionAssociation("Employees", employeeConfiguration.ConfiguredType).
WithOppositeCollection("ReportsTo")
configurations.Add(employeeConfiguration)
configurations.Add(testConfiguration)
Return configurations
End Function
End Class
Employee Class
public class Employee
{
public int Id {get;set;}
public string Name {get;set;}
}
Public Class Employee
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
End Class
Sample FluentMetadataSource Implementation - Many-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<Employee> employeeConfiguration = new MappingConfiguration<Employee>();
employeeConfiguration.MapType( e => new
{
EmployeeId = e.Id,
EmplName = e.Name
} ).ToTable( "Employees" );
employeeConfiguration.HasProperty( e => e.Id ).IsIdentity();
MappingConfiguration territoryConfiguration = new MappingConfiguration( "Territory", "TerritoryNamespace" );
territoryConfiguration.HasArtificialStringProperty( "Name" );
territoryConfiguration.HasArtificialPrimitiveProperty<int>( "Id" ).IsIdentity();
employeeConfiguration.
HasArtificialCollectionAssociation( "Territories", territoryConfiguration.ConfiguredType ).
WithOppositeCollection( "Employees" );
territoryConfiguration.
HasArtificialCollectionAssociation( "Employees", employeeConfiguration.ConfiguredType ).
WithOppositeCollection( "Territories" );
configurations.Add( employeeConfiguration );
configurations.Add( territoryConfiguration );
return configurations;
}
}
Public Class FluentModelMetadataSource
Inherits FluentMetadataSource
Protected Overrides Function PrepareMapping() As IList(Of MappingConfiguration)
Dim configurations As New List(Of MappingConfiguration)()
Dim employeeConfiguration As New MappingConfiguration(Of Employee)()
employeeConfiguration.MapType(Function(e) New With {Key .EmployeeId = e.Id, Key .EmplName = e.Name}).ToTable("Employees")
employeeConfiguration.HasProperty(Function(e) e.Id).IsIdentity()
employeeConfiguration.FieldNamingRules.AddPrefix = "_"
Dim territoryConfiguration As New MappingConfiguration("Territory", "TerritoryNamespace")
territoryConfiguration.HasArtificialStringProperty("Name")
territoryConfiguration.HasArtificialPrimitiveProperty(Of Integer)("Id").IsIdentity()
employeeConfiguration.
HasArtificialCollectionAssociation("Territories", territoryConfiguration.ConfiguredType).
WithOppositeCollection("Employees")
territoryConfiguration.
HasArtificialCollectionAssociation("Employees", employeeConfiguration.ConfiguredType).
WithOppositeCollection("Territories")
configurations.Add(employeeConfiguration)
configurations.Add(territoryConfiguration)
Return configurations
End Function
End Class
Territory Class
public class Territory
{
public int Id { get; set; }
public string Name {get;set;}
}
Public Class Territory
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
End Class
Sample FluentMetadataSource Implementation - Many-To-Many Artificial Associations Between Existing Types
public class FluentModelMetadataSource : FluentMetadataSource
{
protected override IList<MappingConfiguration> PrepareMapping()
{
List<MappingConfiguration> configurations = new List<MappingConfiguration>();
MappingConfiguration<Employee> employeeConfiguration = new MappingConfiguration<Employee>();
employeeConfiguration.MapType( e => new
{
EmployeeId = e.Id,
EmplName = e.Name
} ).ToTable( "Employees" );
employeeConfiguration.HasProperty( e => e.Id ).IsIdentity();
MappingConfiguration<Territory> territoryConfiguration = new MappingConfiguration<Territory>();
territoryConfiguration.MapType( t => new
{
TerritoryId = t.Id,
TerritoryName = t.Name
} ).ToTable( "Territories" );
territoryConfiguration.HasProperty( e => e.Id ).IsIdentity();
employeeConfiguration.
HasArtificialCollectionAssociation( "Territories", territoryConfiguration.ConfiguredType ).
WithOppositeCollection( "Employees" );
territoryConfiguration.
HasArtificialCollectionAssociation( "Employees", employeeConfiguration.ConfiguredType ).
WithOppositeCollection( "Territories" );
configurations.Add( employeeConfiguration );
configurations.Add( territoryConfiguration );
return configurations;
}
}
Public Class FluentModelMetadataSource
Inherits FluentMetadataSource
Protected Overrides Function PrepareMapping() As IList(Of MappingConfiguration)
Dim configurations As New List(Of MappingConfiguration)()
Dim employeeConfiguration As New MappingConfiguration(Of Employee)()
employeeConfiguration.MapType(Function(e) _
New With {Key .EmployeeId = e.Id, Key .EmplName = e.Name}).ToTable("Employees")
employeeConfiguration.HasProperty(Function(e) e.Id).IsIdentity()
employeeConfiguration.FieldNamingRules.AddPrefix = "_"
Dim territoryConfiguration As New MappingConfiguration(Of Territory)()
territoryConfiguration.MapType(Function(t) _
New With {Key .TerritoryId = t.Id, Key .TerritoryName = t.Name}).ToTable("Territories")
territoryConfiguration.HasProperty(Function(e) e.Id).IsIdentity()
territoryConfiguration.FieldNamingRules.AddPrefix = "_"
employeeConfiguration.
HasArtificialCollectionAssociation("Territories", territoryConfiguration.ConfiguredType).
WithOppositeCollection("Employees")
territoryConfiguration.
HasArtificialCollectionAssociation("Employees", employeeConfiguration.ConfiguredType).
WithOppositeCollection("Territories")
configurations.Add(employeeConfiguration)
configurations.Add(territoryConfiguration)
Return configurations
End Function
End Class