HasManyToMany is not saving middle table data

1,079 views
Skip to first unread message

Rúben Lício

unread,
Aug 1, 2010, 7:44:12 PM8/1/10
to Fluent NHibernate
Hello,

I am trying to use HasManyToMany relation with fluent, it compile and
run, but do not insert middle table data.

Here is the mapping:


public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("tb_users");
//LazyLoad();
//DynamicInsert();

Id(x => x.Id).GeneratedBy.Native();
Map(x => x.Name).Length(100).Not.Nullable();
Map(x => x.Login).Length(30).Unique().Not.Nullable();
Map(x =>
x.PasswordHash).Column("password").Length(100).Not.Nullable();
Map(x =>
x.CPFString).Column("cpf").Length(30).Not.Nullable().Unique();
Map(x => x.ExpiratedDate);
Map(x =>
x.EMailString).Column("email").Length(100).Not.Nullable().Unique();
References<UserStatus>(x => x.Status,
"user_status").Not.LazyLoad();
HasManyToMany<Group>(x => x.Groups)
.Table("tb_users_group")
.Inverse()
.ParentKeyColumn("id_user")
.ChildKeyColumn("id_group")
.Cascade.SaveUpdate();
}
}

public class GroupMap : ClassMap<Group>
{
public GroupMap()
{
Table("tb_groups");
//LazyLoad();
//DynamicInsert();

Id(x => x.Id).GeneratedBy.Native();
Map(x => x.Name).Length(100).Not.Nullable();
Map(x => x.Active).Not.Nullable();
HasManyToMany<User>(x => x.Users)
.Table("tb_users_group")
.Inverse()
.ParentKeyColumn("id_group")
.ChildKeyColumn("id_user")
.Cascade.SaveUpdate();
}
}

And the tables:

CREATE TABLE tb_users
(
id INT IDENTITY PRIMARY KEY,
name VARCHAR(100) NOT NULL,
login VARCHAR(30) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL,
cpf VARCHAR(30) NOT NULL UNIQUE,
expiratedDate DATETIME DEFAULT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
user_status int REFERENCES tb_user_status(id) NOT NULL
);

CREATE TABLE tb_groups
(
id INT IDENTITY PRIMARY KEY,
name VARCHAR(100) NOT NULL UNIQUE,
active BIT NOT NULL
);

CREATE TABLE tb_users_group
(
id_user INT REFERENCES tb_users(id) NOT NULL,
id_group INT REFERENCES tb_groups(id) NOT NULL,
PRIMARY KEY(id_user, id_group)
);

When I run this code:


User u = new User();
Group g = new Group();
g.Name = "abc teste";

u.Name = "ADM";
u.Login = "admin";
u.PasswordRaw = "1234mudar";
// u.Groups.Add(groupAdmin);
u.Groups.Add(g);
u.CPFString = "123.456.789-01";
u.EMailString = "as...@fake.com";
u.Status = status;
u.ExpiratedDate =
DatabaseUtils.Instance.GetDateTime(this.session).AddMonths(-1);

UserBusiness.Instance.Save(u, this.session);

I get this result:

NHibernate: INSERT INTO tb_users (Name, Login, password, cpf,
ExpiratedDate, email, user_status) VALUES (@p0, @p1, @p2, @p3, @p4,
@p5, @p6); select SCOPE_IDENTITY();@p0 = 'ADM', @p1 = 'admin', @p2 =
'???u? e?? ?j ?? ??G', @p3 = '123.456.789-01', @p4 = 01/07/2010
20:36:45, @p5 = 'as...@fake.com', @p6 = 1
NHibernate: INSERT INTO tb_groups (Name, Active) VALUES (@p0, @p1);
select SCOPE_IDENTITY();@p0 = 'abc teste', @p1 = False

The problem is, it should insert relation data into tb_users_group,
does't it?

What I'm doing wrong? I checked a lot of internet example, and tried
to change my code a lot but no result so far.

Thank you.

Rúben

Paul Batum

unread,
Aug 7, 2010, 7:48:42 AM8/7/10
to fluent-nhibernate
You're mapping both sides as inverse. The inverse relationship tells
NH "ignore this side of the relationship". By doing inverse on both
sides, you're telling NH to ignore the relationship completely.

Choose one side to control the relationship, make the other side inverse.

> --
> You received this message because you are subscribed to the Google Groups "Fluent NHibernate" group.
> To post to this group, send email to fluent-n...@googlegroups.com.
> To unsubscribe from this group, send email to fluent-nhibern...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/fluent-nhibernate?hl=en.
>
>

Rúben Lício Reis

unread,
Aug 7, 2010, 1:19:06 PM8/7/10
to fluent-n...@googlegroups.com
I've tried without inverse in both sides and with inverse in one of them. Nothing has worked.
Is that some bug of nhibernate? I tried in native .xml too, but with this approach the middle table is saved but i am not able to map another side of relationship.

As commented in this list before, almost everybody avoid to use many-to-many without mapping the middle table too because it has a lot of problems, so I decided to avoid it to :/

Thank you.

Rúben Lício Reis
+55 11 67041245

Paul Batum

unread,
Aug 7, 2010, 9:56:45 PM8/7/10
to fluent-nhibernate
Hi Rúben,

I think you must still be doing something wrong. This is an extremely commonly used feature.

I've updated my fluent nhibernate test project with a very simple working example. Maybe if you download it you can compare it to your own code and figure out the problem.

http://github.com/paulbatum/Fluent-NH-Test-Bed/tree/fluent-many-to-many

If you just want a .zip file, I suggest you use the Download Source button.

2010/8/8 Rúben Lício Reis <rub...@gmail.com>:

Leo

unread,
Oct 1, 2010, 1:00:39 PM10/1/10
to Fluent NHibernate
I was having this exact problem and I felt silly when I realized what
I was doing wrong. If you don't wrap your session.Save(...) in a
transaction. You need to call session.Flush().

On Aug 7, 11:19 am, Rúben Lício Reis <rube...@gmail.com> wrote:
> I've tried without inverse in both sides and with inverse in one of them.
> Nothing has worked.
> Is that some bug of nhibernate? I tried in native .xml too, but with this
> approach the middle table is saved but i am not able to map another side of
> relationship.
>
> As commented in this list before, almost everybody avoid to use many-to-many
> without mapping the middle table too because it has a lot of problems, so I
> decided to avoid it to :/
>
> Thank you.
>
> Rúben Lício Reis
> +55 11 67041245
>
>
>
> On Sat, Aug 7, 2010 at 8:48 AM, Paul Batum <paul.ba...@gmail.com> wrote:
> > You're mapping both sides as inverse. The inverse relationship tells
> > NH "ignore this side of the relationship". By doing inverse on both
> > sides, you're telling NH to ignore the relationship completely.
>
> > Choose one side to control the relationship, make the other side inverse.
>
> > >                u.EMailString = "a...@fake.com";
> > >                u.Status = status;
> > >                u.ExpiratedDate =
> > > DatabaseUtils.Instance.GetDateTime(this.session).AddMonths(-1);
>
> > >                UserBusiness.Instance.Save(u, this.session);
>
> > > I get this result:
>
> > > NHibernate: INSERT INTO tb_users (Name, Login, password, cpf,
> > > ExpiratedDate, email, user_status) VALUES (@p0, @p1, @p2, @p3, @p4,
> > > @p5, @p6); select SCOPE_IDENTITY();@p0 = 'ADM', @p1 = 'admin', @p2 =
> > > '???u? e??  ?j ?? ??G', @p3 = '123.456.789-01', @p4 = 01/07/2010
> > > 20:36:45, @p5 = 'a...@fake.com', @p6 = 1
> > > NHibernate: INSERT INTO tb_groups (Name, Active) VALUES (@p0, @p1);
> > > select SCOPE_IDENTITY();@p0 = 'abc teste', @p1 = False
>
> > > The problem is, it should insert relation data into tb_users_group,
> > > does't it?
>
> > > What I'm doing wrong? I checked a lot of internet example, and tried
> > > to change my code a lot but no result so far.
>
> > > Thank you.
>
> > > Rúben
>
> > > --
> > > You received this message because you are subscribed to the Google Groups
> > "Fluent NHibernate" group.
> > > To post to this group, send email to fluent-n...@googlegroups.com.
> > > To unsubscribe from this group, send email to
> > fluent-nhibern...@googlegroups.com<fluent-nhibernate%2Bunsubscr i...@googlegroups.com>
> > .
> > > For more options, visit this group at
> >http://groups.google.com/group/fluent-nhibernate?hl=en.
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "Fluent NHibernate" group.
> > To post to this group, send email to fluent-n...@googlegroups.com.
> > To unsubscribe from this group, send email to
> > fluent-nhibern...@googlegroups.com<fluent-nhibernate%2Bunsubscr i...@googlegroups.com>
> > .
Reply all
Reply to author
Forward
0 new messages