Multiple Many-To-Many relations in one class

2 posts, 0 answers
  1. Boris Rogge
    Boris Rogge avatar
    30 posts
    Member since:
    Mar 2006

    Posted 14 Sep Link to this post

    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

     

  2. Viktor Zhivkov
    Admin
    Viktor Zhivkov avatar
    291 posts

    Posted 19 Sep Link to this post

    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.
  3. DevCraft banner
Back to Top