This is a migrated thread and some comments may be shown as answers.

Multiple Many-To-Many relations in one class

1 Answer 43 Views
Development (API, general questions)
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Boris Rogge
Top achievements
Rank 1
Boris Rogge asked on 14 Sep 2016, 12:43 PM

Hello

I am facing the following issue:

We have class Company, with a list of Relations, that references 2 companies.
The idea is that if CompanyX has a relationship with CompanyY, that both of them have a list property 'Relations' with the same Relation in it, referencing one another.

The setup is as follows:

CompanyModel

01.public class CompanyModel
02.{
03.    public int Id { get; set; }
04. 
05.    public IList<RelationModel> Relations { get; set; }
06. 
07.    public CompanyModel()
08.    {
09.        Relations = new List<RelationModel>();
10.    }
11. 
12.    public void AddRelation(RelationModel relationModel)
13.    {
14.        if (Relations.Contains(relationModel)) return;
15. 
16.        relationModel.From = this;
17.        relationModel.FromId = Id;
18. 
19.        Relations.Add(relationModel);
20.    }
21.}

01.private static MappingConfiguration<CompanyModel> GetCompanyModelMappingConfiguration()
02.{
03.    var mapping = new MappingConfiguration<CompanyModel>();
04. 
05.    mapping.MapType().UseDefaultMap().ToTable("Companies");
06. 
07.    mapping.HasProperty(x => x.Id).IsIdentity(KeyGenerator.Autoinc);
08.
09.    return mapping;
10.}

RelationModel

01.public class RelationModel
02.{
03.    public int Id { get; set; }
04. 
05.    public CompanyModel From { get; set; }
06.    public int FromId { get; set; }
07. 
08.    public CompanyModel To { get; set; }
09.    public int ToId { get; set; }
10.}

01.private static MappingConfiguration<RelationModel> GetRelationModelMappingConfiguration()
02.{
03.    var mapping = new MappingConfiguration<RelationModel>();
04. 
05.    mapping.MapType().UseDefaultMap().ToTable("Relations");
06. 
07.    mapping.HasProperty(x => x.Id).IsIdentity(KeyGenerator.Autoinc);
08. 
09.    mapping.HasAssociation(x => x.From)
10.           .WithOpposite(x => x.Relations)
11.           .ToColumn("FromId")
12.           .HasConstraint((x, y) => x.FromId == y.Id)
13.           .IsManaged();
14. 
15.    mapping.HasAssociation(x => x.To)
16.           .WithOpposite(x => x.Relations)
17.           .ToColumn("ToId")
18.           .HasConstraint((x, z) => x.ToId == z.Id)
19.           .IsManaged();
20. 
21.    return mapping;
22.}

The database holds a Relation record, FromId 2 (CompanyY), ToId 1 (CompanyX).
However, the list 'Relations' only gets filled on one of the two companies, whereas I'd expect both companies to have a filled Relations list.

What is happening? What am I doing wrong?

Thanks

Boris

 

1 Answer, 1 is accepted

Sort by
0
Viktor Zhivkov
Telerik team
answered on 19 Sep 2016, 11:41 AM
Hello Boris,

The behavior that you are experiencing is known limitation of Telerik Data Access.
The runtime will simply check of it has loaded company.Relations property and skip it the second time it when it should load data using the ToId key.
Your options to work around this limitations include:
  1. Changing the design of your data model - may offer best consistency of your data;
  2. Introducing non-persistent Relations property that will merge two persistent FromRelations and ToRelations lists - middle ground solution that allows Data Access to fill correctly both persistent collections and clients to use the in-memory one as abstraction over the two lists. See the code below as illustration:
    01.// Relation class definition
    02.public IEnumerable<Relation> Relations
    03.{
    04.    get { return FromRelations.Union(ToRelations); }
    05.}
    06. 
    07.public IList<Relation> FromRelations { get; set; }
    08.public IList<Relation> ToRelations { get; set; }
    09. 
    10. 
    11.// Company class mapping
    12.mapping.HasProperty(x => x.Relations).AsTransient();
    13. 
    14. 
    15.// Relation class mapping
    16.mapping.HasAssociation(x => x.From)
    17.                   .WithOpposite(x => x.FromRelations)
    18.                   .ToColumn("FromId")
    19.                   .HasConstraint((x, y) => x.FromId == y.Id)
    20.                   .IsManaged();
    21. 
    22.            mapping.HasAssociation(x => x.To)
    23.                   .WithOpposite(x => x.ToRelations)
    24.                   .ToColumn("ToId")
    25.                   .HasConstraint((x, z) => x.ToId == z.Id)
    26.                   .IsManaged();
  3. Persisting two relations records instead of one - "A to B" and "B to A" - may be easiest solution, but you should be careful with management of the data in these two tables and make sure that your transactions are as short as possible to avoid data inconsistencies.

I am sorry for the inconvenience. If you need any further assistance, please let us know.

Regards,
Viktor Zhivkov
Telerik by Progress
 
Check out the latest announcement about Telerik Data Access vNext as a powerful framework able to solve core development problems.
Tags
Development (API, general questions)
Asked by
Boris Rogge
Top achievements
Rank 1
Answers by
Viktor Zhivkov
Telerik team
Share this question
or