Fluent NHibernate Composite ID 表问题 [英] Fluent NHibernate Composite ID table problem

查看:32
本文介绍了Fluent NHibernate Composite ID 表问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

I'm kinda new to nhibernate and i ran into a problem. I have the following tables:

Table 1: Table Name: Users, Column 1: ID, Column 2: Name

Table 2: Table Name: Missions, Column 1: ID, Column 2: Description

Table 3: Table Name: UserToDoMissions, Column 1: UserID, Column 2: MissionID, Column 3: Rank

Here is the code: MissionMap:

public class MissionMap : ClassMap<Mission>
{
    public const string TableName = "tblMissions";
    public const string c_id = "achID";
    public const string c_name = "achName";

    public MissionMap()
    {
        Table(TableName);
        Id(x => x.ID).Column(c_id).Not.Nullable();
        Map(x => x.Name).Column(c_name).Not.Nullable();

        HasMany(x => x.UserToDoList).Cascade.All().Inverse().KeyColumn(UserToDoMap.c_missionID);
    }
}

User Map:

public class UserMap : ClassMap<User>
{
    public const string TableName = "tblUsers";
    public const string c_id = "usrID";
    public const string c_userName = "usrUserName";

    public UserMap()
    {
        Table(TableName);
        Id(x => x.ID).Column(c_id).Not.Nullable();
        Map(x => x.UserName).Column(c_userName).UniqueKey(DBConsts.UniqueKeys.User_UserName).Not.Nullable();

        HasMany(x => x.UserToDoList).Cascade.All().Inverse().KeyColumn(UserToDoMap.c_userID);
    }
}

UserToDo Map:

public class UserToDoMap : ClassMap<UserToDo>
{
    public const string TableName = "tblToDoList";
    public const string c_userID = "tdlUserID";
    public const string c_missionID = "tdlMissionID";
    public const string c_rank = "tdlRank";

    public UserToDoMap()
    {
        Table(TableName);
        CompositeId().KeyReference(x => x.User, c_userID).KeyReference(x => x.Achievment, c_missionID);
        References(x => x.User).Column(c_userID).Cascade.All().UniqueKey(DBConsts.UniqueKeys.ToDoList_UserRanks).Not.Nullable();
        References(x => x.Mission).Column(c_missionID).Cascade.All().Not.Nullable();
        Map(x => x.Rank).Column(c_rank).UniqueKey(DBConsts.UniqueKeys.ToDoList_UserRanks).Not.Nullable();
    }
}

My problem is that i can;t save a new line. I can select and get all of the things but can't save. Any ideas?

Thanks.

Edit: I'm not getting anything. No exception is thrown but the row isn't added to the DB. BTW, I'm using the save method on UserToDo object.

Edit 2: After docmanhattan answer here is the code:

UserToDoMap:

public class UserToDoMap : ClassMap<UserToDo>
{
    public const string TableName = "tblToDoList";
    public const string c_userID = "tdlUserID";
    public const string c_missionID = "tdlMissionID";
    public const string c_rank = "tdlRank";

    public UserToDoMap()
    {
        Table(TableName);
        CompositeId<UserToDoId>(x => x.ID)
            .KeyReference(x => x.UserIdPart, c_userID)
            .KeyReference(x => x.MissionIdPart, c_missionID);
        References(x => x.ID.UserIdPart).Column(c_userID).Cascade.All().UniqueKey(DBConsts.UniqueKeys.ToDoList_UserRanks).Not.Nullable();
        References(x => x.ID.MissionIdPart).Column(c_missionID).Cascade.All().Not.Nullable();
        Map(x => x.Rank).Column(c_rank).UniqueKey(DBConsts.UniqueKeys.ToDoList_UserRanks).Not.Nullable();
    }
}

UserToDoId entity:

public class UserToDoId
{
    public virtual User UserIdPart { get; set; }
    public virtual Mission MissionIdPart { get; set; }

    public override bool Equals(object obj)
    {
        UserToDoId recievedObject = (UserToDoId)obj;

        if ((UserIdPart.ID == recievedObject.UserIdPart.ID) &&
            (MissionIdPart.ID == recievedObject.MissionIdPart.ID))
        {
            return (true);
        }

        return (false);
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }
}

UserToDo entity:

public class UserToDo
{
    public virtual UserToDoId ID { get; set; }

    public virtual int Rank { get; set; }

    public UserToDo()
    {

    }

    public override bool Equals(object obj)
    {
        UserToDo recievedObject = (UserToDo)obj;

        if ((ID.UserIdPart.ID == recievedObject.ID.UserIdPart.ID) &&
            (ID.MissionIdPart.ID == recievedObject.ID.MissionIdPart.ID) &&
            (Rank == recievedObject.Rank))
        {
            return (true);
        }

        return (false);
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }
}

I'm getting the exception when i'm trying to create the session factory:

{"Could not find a getter for property 'UserIdPart' in class 'DatabaseEntities.UserToDo'"}

解决方案

I've had lots of problems with doing things with composite ids, such as this. I'd suggest doing what I did which is create a new type that just encompasses what the composite id uses for the id and then mapping it like so:

CompositeId<UserToDoId>(x => x.ID)
    .KeyReference(x => x.UserIdPart, c_userID)
    .KeyReference(x => x.AchievementIdPart, c_missionID);

Where UserToDoId has the two references used in the composite id:

public class UserToDoId
{
    User UserIdPart { get; set; }
    Achievement AchievementIdPart { get; set; }

    public override bool Equals(object obj)
    {
        return Equals(obj as UserToDoId);
    }

    private bool Equals(UserToDoId other)
    {
        if (ReferenceEquals(other, null)) return false;
        if (ReferenceEquals(other, this)) return true;

        return UserIdPart.ID == other.UserIdPart.ID &&
            MissionIdPart.ID == other.MissionIdPart.ID;
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int hash = GetType().GetHashCode();
            hash = (hash * 31) ^ UserIdPart.ID.GetHashCode();
            hash = (hash * 31) ^ MissionIdPart.ID.GetHashCode();

            return hash;
        }
    }
}

I have no idea why, but there are a bunch of little problems that pop up when you don't use another type to hold the pieces of the component id.

One problem I had was linked at the beginning on my answer. Another one I had was using a composite id for a parent abstract class with subclass mappings would attempt to create instances of the abstract class (which you can't do) for certain queries. Implementing this new type fixed both of these problems.

Give it a try and see if that works. Also, 'achievment' is spelled 'achievement' (not trying to taunt, I just hope you'll avoid people snickering at your code cause of a spelling error :-D)

这篇关于Fluent NHibernate Composite ID 表问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆