Problems with HasManyToMany and a IDictionary attributte

32 views
Skip to first unread message

Ivan Ruiz de Eguilaz Sosoaga

unread,
Aug 24, 2016, 8:21:20 AM8/24/16
to Fluent NHibernate
I have problems generating a new table by using HasManyToMany only When I have a IDictonary as a source, for instance If I try it with an IList I do not have any problem and I see how a new table is generated and the relations. But I need to use a IDictioonary 

The example:


public class Email: I_CLASS
    {

public virtual int Id { get; set; }
public virtual IDictionary<Person, short> Destiny_Persons { get; set; }

}

public class Person: I_CLASS
{

public virtual int Id { get; set; }


}

class Notification_DTO_Map : IAutoMappingOverride<Notification_DTO>
    {
        public void Override(AutoMapping<Notification_DTO> mapping)
        {

            mapping.HasManyToMany<User_DTO>(x => x.Destiny_Users).Table("Destiny_Persons")
                .ParentKeyColumn("Email")
            .ChildKeyColumn("Person")
            .AsEntityMap().Element("Email_Status", part => part.Type<short>());
 }

}

my target is to have that dictionary and a new table called Destiny_Persons with the followinf attributtes:
  • Person_Id (int) PK FK
  • Email_Id  (int) PK FK
  • Status (short) not null  
The status won´t be part of the PK

If a use a IList like this public virtual IList<Person> Destiny_Persons { get; set; }
and in the mapping: mapping.HasManyToMany(x => x.Destiny_Persons ).Table("Destiny_Persons"); 
this works without the Status attributte

I have tried a lot of different ways of putting this such as  changing the order of the elements in the dictionary <short, Person>, using asMap instead of AsEntityMap, not using partenkeycolums and child, changing the order... and so on

I do not have any error when I generate the database but I am not able to generate the table Destiny_Persons when I have a IDictionary as a source

Thanks


mwpowellhtx

unread,
Aug 25, 2016, 10:22:15 AM8/25/16
to Fluent NHibernate


On Wednesday, August 24, 2016 at 8:21:20 AM UTC-4, Ivan Ruiz de Eguilaz Sosoaga wrote:
I have problems generating a new table by using HasManyToMany only When I have a IDictonary as a source, for instance If I try it with an IList I do not have any problem and I see how a new table is generated and the relations. But I need to use a IDictioonary 

The example:

I once had a minor use case that involved a many to many joining table, but soon discovered that made better sense as a "joining" first class entity, especially when you factor in such "impedance mismatches" as properties on that relationship. Things like dates/times, flags, or other properties that might make sense to describe the relationship.

In either case, the trick, of course, is to ensure that both sides of the relational entity are persisted prior to persisting the joining entity.

In this way, then either side of the relationship may be treated "simply" as a bidirectional relationship and/or re-hydrated as opportunities arise.

HTH

Ivan Ruiz de Eguilaz Sosoaga

unread,
Aug 29, 2016, 7:56:56 AM8/29/16
to Fluent NHibernate
I finally found the problem about why I was not able to generate a new table from the dictionary. I did not have the override class as Public, so it did not work. 

  public class Email_Map : IAutoMappingOverride<Email>
    {
        public void Override(AutoMapping<Email> mapping)
        {

      ......

Now, the new table is generated as expected (with the 3 attributtes) but I have another problem. when I try to insert an element, the data is saved in the class email but nothing in the table destinies_persons, so it does not insert the information of the dictionary. 

this is the way I am mapping the dicctionary:

 mapping.HasManyToMany(x => x.Destiny_Persons ).AsEntityMap().Element("Status", c => c.Type<short>()).Not.LazyLoad();


I see that the object in the following method has the dicctionary with data but this Save only generate the insert in the table Email returning an OK result.

using (NHibernate.ITransaction tx = NHSession.BeginTransaction())
                        {
                            NHSession.Save((T)pObject);
                            tx.Commit();
                            result.DAO_Error = DAO_Error_Type.OK;
                        }



Do you see something wrong in my code?

thanks

Ivan Ruiz de Eguilaz Sosoaga

unread,
Aug 29, 2016, 8:23:51 AM8/29/16
to Fluent NHibernate


I would like to add that when I get the data from the database afther inserting data by hand (As I said, the insert does not work for the diccionary). It works properly and it brings the email objects with the dictionary attirbutte fulfilled. So the problem only happens when I try to add data to the database

Best regards.


El miércoles, 24 de agosto de 2016, 14:21:20 (UTC+2), Ivan Ruiz de Eguilaz Sosoaga escribió:

Michael Powell

unread,
Aug 29, 2016, 8:36:38 AM8/29/16
to fluent-n...@googlegroups.com
On Mon, Aug 29, 2016 at 7:56 AM, Ivan Ruiz de Eguilaz Sosoaga
<iruize...@gmail.com> wrote:
> I finally found the problem about why I was not able to generate a new table
> from the dictionary. I did not have the override class as Public, so it did
> not work.
>
> public class Email_Map : IAutoMappingOverride<Email>
> {
> public void Override(AutoMapping<Email> mapping)
> {
>
> ......
>
> Now, the new table is generated as expected (with the 3 attributtes) but I
> have another problem. when I try to insert an element, the data is saved in
> the class email but nothing in the table destinies_persons, so it does not
> insert the information of the dictionary.
>
> this is the way I am mapping the dicctionary:
>
> mapping.HasManyToMany(x => x.Destiny_Persons
> ).AsEntityMap().Element("Status", c => c.Type<short>()).Not.LazyLoad();
>
>
> I see that the object in the following method has the dicctionary with data
> but this Save only generate the insert in the table Email returning an OK
> result.
>
> using (NHibernate.ITransaction tx = NHSession.BeginTransaction())
> {
> NHSession.Save((T)pObject);
> tx.Commit();
> result.DAO_Error = DAO_Error_Type.OK;
> }
>
>
>
> Do you see something wrong in my code?

I promoted my many to many joining entities to first class models, as
I described. Which is working fine for me.
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "Fluent NHibernate" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/fluent-nhibernate/tAO2ISPHvBQ/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> fluent-nhibern...@googlegroups.com.
> To post to this group, send email to fluent-n...@googlegroups.com.
> Visit this group at https://groups.google.com/group/fluent-nhibernate.
> For more options, visit https://groups.google.com/d/optout.

Ivan Ruiz de Eguilaz Sosoaga

unread,
Aug 30, 2016, 7:42:30 AM8/30/16
to Fluent NHibernate
I have tried to simplify the data model. Creating by my hand the third table, and avoiding to use many to many, so I have define a IList element and a mapping hasMany

The idea is to try the following:

One Email has a list of Destiny_Person:

public virtual IList<Destiny_Person> Destiny_Persons {get; set; }

and the mapping:
mapping.HasMany(x => x.Destiny_Persons ).Inverse().Cascade.All();

This does not work properly neither because I save the email with a couple of elements in the list, the email is saved, the list of elements are saved as well but without the foring_key attributte. I see in the log the insert of the email and the inserts of the destiny_persons but nhibernate do not insert the column email_Id.

:(((


Michael

unread,
Aug 30, 2016, 9:17:16 AM8/30/16
to fluent-n...@googlegroups.com


On August 30, 2016 7:42:29 AM EDT, Ivan Ruiz de Eguilaz Sosoaga <iruize...@gmail.com> wrote:
>I have tried to simplify the data model. Creating by my hand the third
>table, and avoiding to use many to many, so I have define a IList
>element
>and a mapping hasMany

Remember it may look and feel naturally like a model, but it's still the database you are dealing with. Both sides of the now one to many need to be saved or updated first. Then you can save the joining entity.

Also assuming you have implemented the repository pattern for your session.

>The idea is to try the following:
>
>One Email has a list of Destiny_Person:
>
>public virtual IList<Destiny_Person> Destiny_Persons {get; set; }
>
>and the mapping:
>mapping.HasMany(x => x.Destiny_Persons ).Inverse().Cascade.All();

HasMany(x => x.Collection)
.LazyLoad()
.Inverse()
.AsBag()
// That or rely on you identity naming conventions
.ForeignKeys.Add("ParentId")
.Cascade.AllDeleteOrphan();

Remember there will be a database backing your model in the form of proxies.

Some people like to instruct the session to access a backing field, but I haven't found that to be as necessary, yet. But I reserve the right to change my mind, depending on the situation.

You may want a bidirectional list alongside the list property that sets or nullifies the parent reference upon adding or removing. You don't always need to use that property, but when you do, it hides the bookkeeping of connecting both sides to the joining entity.

I also like to initialize my collections to at least an empty list instead of null. Then I don't need to worry about any bidirectional null references.

Google StackOverflow; there is usually at least one question for virtually any level of question you can think of asking.

>This does not work properly neither because I save the email with a
>couple
>of elements in the list, the email is saved, the list of elements are
>saved
>as well but without the foring_key attributte. I see in the log the
>insert
>of the email and the inserts of the destiny_persons but nhibernate do
>not
>insert the column email_Id.
>
>:(((

--
Sent from my Android device with K-9 Mail. Please excuse my brevity.
Message has been deleted

Ivan Ruiz de Eguilaz Sosoaga

unread,
Aug 31, 2016, 5:31:04 AM8/31/16
to Fluent NHibernate

Thank you very much for your patient and your answer.

 

I do not know If i have understud properly the concept of this: " Both sides of the now one to many need to be saved or updated first. "

 

For instance, I have created a 2 new tables to do the tests. Teachers and Classes. They have only the attitubutes Id and Name. And I have added a relation one to many from teacher to classes.

 

 

public class Classes : I_DTO

    {

        public virtual int Id { get; set; }

        public virtual string Name { get; set; }

   

 

        public Classes()

        {

        }

}

 

namespace ExCon_DAO_SQL.DTO.Wall

{

    public class Teacher : I_DTO

    {

        public virtual int Id { get; set; }

        public virtual string Name { get; set; }

        public virtual IList<Classes> Classes { get; set; }

 

        public Teacher()

        {

            Classes = new List<Classes>();

        }

 

  }

 

 

public class Teacher_Map : IAutoMappingOverride<Teacher>

    {

        public void Override(AutoMapping<Teacher> mapping)

        {

            mapping.HasMany(x => x.Classes).LazyLoad().

                Inverse().AsBag().ForeignKeyConstraintName("Teacher_Id").Cascade.AllDeleteOrphan(); 

        }

    }

 

 

 

Ok, I have Saved a Teacher with a clases in the list of clases. All elements are saved in the database but the clases elements have in the database the attribute Teacher_Id as null. So the relation is not saved. Is possible to use an unidirectional relationship one to many and get the foreing key saved???????

 

is this behaivor normal?

 

second test:

 

public class Classes : I_DTO

    {

        public virtual int Id { get; set; }

        public virtual string Name { get; set; }

        public virtual Teacher teacher { get; set; }

   

 

        public Classes()

        {

            teacher = new Teacher();

        }

}

 

 public class Classes_Map : IAutoMappingOverride<Classes>

    {

        public void Override(AutoMapping<Classes> mapping)

        {

            mapping.References(x => x.teacher).Column("Teacher_Id");

        }

    }

 

Now I have been able to get the target but in this way:

 

 

 Teacher profe = new Teacher();

            profe.Name = "Peter";

 

            List<Classes> classes = new List<Classes>();

            Classes clase1 = new Classes();

            clase1.Name = "Class1";

            clase1.teacher = profe;

            classes.Add(clase1);

            profe.Classes = classes;

            DAO_Result resultado = SQL_DAO_Service.Add<Teacher>(profe);

 

I this bidirectional example, I have to add to the teacher the clasess, and each class have to has as well the reference of the teacher to se that in the save it is able to generate all properly

 

is this behaviour correct?

 

And last but not least

 

If I have do and update of this teacher and and 2 clases with him, and after that I remove one of the element of the classes list, and I update the teacher, the system is not able to know that What I want is to delete the class from the database, so i will have to check on my own if the list of clases does not have and ald element to delete it...

 

is this correct?

 

thanks a lot!!!

 

best regards...

Michael

unread,
Aug 31, 2016, 8:24:36 AM8/31/16
to fluent-n...@googlegroups.com
This is basic stuff with both database and ORM. Google is your friend. All I can suggest is, where is the Teacher reference in Classes, and bidirectional reference in Teacher? I don't know about auto mappings, as I usually do fluent mapping, but this is a personal design decision. Beyond that I can quote you my hourly rate.

On August 31, 2016 2:22:37 AM EDT, Ivan Ruiz de Eguilaz Sosoaga <iruize...@gmail.com> wrote:
Thank you very much for your patient and your answer.

I do not know If i have understud properly the concept of this: " Both sides of the now one to many need to be saved or updated first. "

For instance, I have created a 2 new tables to do the tests. Teachers and Classes. They have only the attitubutes Id and Name. And I have added a relation one to many from teacher to classes.


public class Classes : I_DTO
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
   

        public Classes()
        {
        }
}

namespace ExCon_DAO_SQL.DTO.Wall
{
    public class Teacher : I_DTO
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual IList<Classes> Classes { get; set; }

        public Teacher()
        {
            Classes = new List<Classes>();
        }

  }


public class Teacher_Map : IAutoMappingOverride<Teacher>
    {
        public void Override(AutoMapping<Teacher> mapping)
        {
            mapping.HasMany(x => x.Classes).LazyLoad().
                Inverse().AsBag().ForeignKeyConstraintName("Teacher_Id").Cascade.AllDeleteOrphan(); 
        }
    }



Ok, I have Save a Teacher with a clases in the list of clases. Both elements are saved in the database but the clases has in the database the element Teacher_Id as null

is this behaivor normal?

second test:

public class Classes : I_DTO
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual Teacher teacher { get; set; }
   

        public Classes()
        {
            teacher = new Teacher();
        }
}

 public class Classes_Map : IAutoMappingOverride<Classes>
    {
        public void Override(AutoMapping<Classes> mapping)
        {
            mapping.References(x => x.teacher).Column("Teacher_Id");
        }
    }

Now I have been able to get the target but in this way:


 Teacher profe = new Teacher();
            profe.Name = "Peter";

            List<Classes> classes = new List<Classes>();
            Classes clase1 = new Classes();
            clase1.Name = "Class1";
            clase1.teacher = profe;
            classes.Add(clase1);
            profe.Classes = classes;
            DAO_Result resultado = SQL_DAO_Service.Add<Teacher>(profe);

I have to add to the teacher the clasess, and each class have to has as well the reference of the teacher to se that in the save it is able to generate all properly

is this behaviour correct?

And last but not least

If I have do and update of this teacher and and 2 clases with him, and after that I remove one of the element of the classes list, and I update the teacher, the system is not able to know that What I want is to delete the class from the database, so i will have to check on my own if the list of clases does not have and ald element to delete it...

is this correct?

thanks a lot!!!

best regards...
 
Reply all
Reply to author
Forward
0 new messages