首页 文章

Fluent NHibernate - 如何映射两个连接表中存在的不可为空的外键

提问于
浏览
11

我正在使用Fluent NHibernate为我的应用程序映射一组成员资格类 . 我正在将类映射到asp.net成员资格数据库结构 . 与问题相关的数据库模式如下所示:

ASPNET_USERS
UserId        PK
ApplicationId FK NOT NULL
other user columns ...

ASPNET_MEMBERSHIP
UserId        PK,FK
ApplicationID FK NOT NULL
other membership columns...

这两个表之间存在一对一的关系 . 我正在尝试将两个表连接在一起,并将两个表中的数据映射到单个“用户”实体,如下所示:

public class User
{
    public virtual Guid Id { get; set; }
    public virtual Guid ApplicationId { get; set; }

    // other properties to be mapped from aspnetuser/membership tables ...

我的映射文件如下:

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        Table("aspnet_Users");
        Id(user => user.Id).Column("UserId").GeneratedBy.GuidComb();
        Map(user => user.ApplicationId);
        // other user mappings

        Join("aspnet_Membership", join => {
            join.KeyColumn("UserId");
            join.Map(user => user.ApplicationId);
            // Map other things from membership to 'User' class
        }
    }
}

如果我尝试使用上面的代码运行,我会得到一个FluentConfiguration异常

尝试添加属性'ApplicationId' .

如果我删除行"Map(user => user.ApplicationId);"或将其更改为“Map(user => user.ApplicationId) .Not.Update().Not.Insert(); ”然后应用程序运行,但在尝试插入新用户时出现以下异常:

无法将值NULL插入列'ApplicationId',表'ASPNETUsers_Dev.dbo.aspnet_Users';列不允许空值 . INSERT失败 . 该语句已终止 .

如果我按原样离开.Map(user => user.ApplicationId)并对 join .Map(user => user.ApplicationId)进行其中任何一项更改,那么我会得到同样的异常,当然除了异常与插入aspnet_Membership表有关

那么......假设我无法更改数据库架构,我该怎么做这种映射?

2 回答

  • 4

    我想我得到了一些有用的东西 .

    public class Application
        {
            public virtual Guid ApplicationId { get; set; }
    
    
            /* Scalar Properties of an Application  */
            public virtual string ApplicationName { get; set; }
            public virtual string Description { get; set; }
    
            public virtual string LoweredApplicationName 
            {
                get
                {
                    return this.ApplicationName.ToLower();
                }
                set
                {
                    if (String.IsNullOrEmpty(this.ApplicationName))
                    {
                        this.ApplicationName = value;
                    }
                } 
            }
    
            public virtual IList<Membership> TheManyMemberships { get; protected set; }
    
        }
    
    
        public class User
        {
            public virtual Guid Id { get; set; }
            public virtual Application TheApplication { get; set; }
    
            public virtual Membership TheMembership { get; set; }
    
            /* Scalar Properties of a User  */
            public virtual string UserName { get; set; }
        }
    
    
        public class Membership
        {
            private Guid UserId { get; set; }
            private User _theUser { get; set; }
    
            protected Membership() { }
    
            public Membership(User theUser)
            {
                _theUser = theUser;
            }
    
            public virtual Application TheApplication { get; set; }
    
            /* Scalar Properties of a Membership  */
            public virtual string Password { get; set; }
    }
    
    
    
    
    
        public class ApplicationMap : ClassMap<Application>
        {
            public ApplicationMap()
            {
                Table("aspnet_Applications");
                Id(app => app.ApplicationId).Column("ApplicationId").GeneratedBy.GuidComb();
                Map(x => x.ApplicationName );
                Map(x => x.LoweredApplicationName);
                Map(x => x.Description );
    
                HasMany<Membership>(x => x.TheManyMemberships)
                    .Inverse()
                    .AsBag();
            }
        }
    
    
        public class UserMap : ClassMap<User>
        {
            public UserMap()
            {
                Table("aspnet_Users");
                Id(user => user.Id).Column("UserId").GeneratedBy.GuidComb();
                References(x => x.TheApplication, "ApplicationId")
                      .Not.Nullable();
    
                HasOne(x => x.TheMembership)
                .Cascade.All();//
                //.Constrained();
    
                Map(x => x.UserName).Not.Nullable();
    
            }
        }
    
    
       public class MembershipMap : ClassMap<Membership>
        {
            public MembershipMap()
            {
                Table("aspnet_Membership");
    
                Id(Reveal.Member<Membership>("UserId"))
                    .GeneratedBy.Foreign("_theUser");
                HasOne(
                  Reveal.Member<Membership, User>("_theUser"))
                        .Constrained()
                        .ForeignKey();
    
                References<Application>(x => x.TheApplication, "ApplicationId")
                .Not.Nullable();
    
                Map(x => x.Password);
    
            }
        }
    

    原谅一些命名约定,在原型设计时,我使用不明确的名称而不是正确的约定来避免混淆 .

    我有的DDL(来自上面的代码)和asp.net(4.0)的输出中的DDL(使用aspnet_regsql.exe构建DDL)似乎是一致的(两个版本之间) .

    我要感谢这篇文章:http://brunoreis.com/tech/fluent-nhibernate-hasone-how-implement-one-to-one-relationship/

    如果您进行任何调整,请发布它们 .

    但我能够保存应用程序,用户和成员资格 .

    但是,我认为我可能会略微偏离用户:会员关系 . 微软的场景似乎是“拥有一个用户,但允许该用户为每个应用程序设置不同的密码”,这是有道理的 . 但有时当使用MembershipProvider代码(MS代码,与NHibernate无关)时,我“感觉”有时会假设一个应用程序 .

    我觉得MS DDL应该对dbo.Membership(UserId,ApplicationId)有一个独特的约束,但我没有在他们的DDL中看到它 .

    无论如何,这应该提供一些思考的食物 .

  • 0

    你尝试继承了吗?

    public class User
    ....
    
    public class Member : User
    ....
    

    你有没有加入ApplicationId的原因?我相信它在两个表格中供参考 . 由于UserId是一个Guid,它是独一无二的 . 如果您确实遇到需要为两个不同的应用程序存储相同用户的情况,那么asp.net成员资格不能像那样工作,它会创建两个不同的用户记录 . 用户名/密码上的查找会根据Web应用程序设置(计算机密钥)检查应用程序ID,以启用其唯一性 . 会员桌是红鲱鱼 .

相关问题