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

vak*_*man 11 nhibernate fluent-nhibernate

我正在使用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...
Run Code Online (Sandbox Code Playgroud)

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

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

    // other properties to be mapped from aspnetuser/membership tables ...
Run Code Online (Sandbox Code Playgroud)

我的映射文件如下:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试使用上面的代码运行,我会得到一个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)并对连接 .Map(user => user.ApplicationId)进行其中任何一项更改,那么我会得到同样的异常,当然除了异常与插入aspnet_Membership表有关

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

gra*_*der 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);

        }
    }
Run Code Online (Sandbox Code Playgroud)

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

我的 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 中没有看到它。

无论如何,这应该提供一些值得深思的内容。