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

发布于 2024-08-29 19:02:38 字数 1745 浏览 6 评论 0原文

我正在使用 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 值插入表“ASPNETUsers_Dev.dbo.aspnet_Users”的“ApplicationId”列;列不允许为空。插入失败。 该声明已终止。

如果我将 .Map(user => user.ApplicationId) 保留为原来的样子,并对 join 进行任何一项更改.Map(user => user.ApplicationId) 然后我得到与上面相同的异常,当然该异常与插入 aspnet_Membership 表有关

那么...我该如何做这种事情假设我无法更改数据库模式映射?

I'm mapping a set of membership classes for my application using Fluent NHibernate. I'm mapping the classes to the asp.net membership database structure. The database schema relevant to the problem looks like this:

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

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

There is a one to one relationship between these two tables. I'm attempting to join the two tables together and map data from both tables to a single 'User' entity which looks like this:

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

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

My mapping file is as follows:

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
        }
    }
}

If I try to run with the code above I get a FluentConfiguration exception

Tried to add property 'ApplicationId' when already added.

If I remove the line "Map(user => user.ApplicationId);" or change it to "Map(user => user.ApplicationId).Not.Update().Not.Insert();" then the application runs but I get the following exception when trying to insert a new user:

Cannot insert the value NULL into column 'ApplicationId', table 'ASPNETUsers_Dev.dbo.aspnet_Users'; column does not allow nulls. INSERT fails.
The statement has been terminated.

And if I leave the .Map(user => user.ApplicationId) as it originally was and make either of those changes to the join.Map(user => user.ApplicationId) then I get the same exception above except of course the exception is related to an insert into the aspnet_Membership table

So... how do I do this kind of mapping assuming I can't change my database schema?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

贱贱哒 2024-09-05 19:02:38

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

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

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

I think I got something that works.

  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);

        }
    }

Forgive some of the naming conventions, when prototyping, I use un-ambiguous names over proper-convention to avoid confusion.

The DDL I have (from the above code) and the DDL from the output of the asp.net (4.0) (using aspnet_regsql.exe to build the DDL) seem consistent (between the two versions).

I need to thank this post:
http://brunoreis.com/tech/fluent-nhibernate-hasone-how-implement-one-to-one-relationship/

If you make any tweaks, then please post them.

But I was able to save an Application, User and Membership.

However, I think I may be slightly off with the User:Membership relationship.
The microsoft scenario seems to be "Have a user, but allow that user to have a different password for each application", which makes sense.
But sometimes when using the MembershipProvider code (the MS code, nothing to do with NHibernate, I "feel" like sometimes it assumes a single application.

I feel like the MS DDL should have a unique constraint on
dbo.Membership (UserId, ApplicationId), but I don't see it in their DDL.

Regardless, this should provide some food for thought.

末蓝 2024-09-05 19:02:38

您是否尝试过继承:

public class User
....

public class Member : User
....

您加入 ApplicationId 的原因是什么?我相信这两个表中都有供参考。由于 UserId 是一个 Guid,因此它是唯一的。如果您确实遇到需要为两个不同的应用程序存储相同用户的情况,那么您不能使用 asp.net 成员资格,因为它会创建两个不同的用户记录。用户名/密码的查找会根据 Web 应用程序设置(机器密钥)检查应用程序 ID,以确保其唯一性。会员表是一个转移注意力的话题。

Did you try inheritance:

public class User
....

public class Member : User
....

?

Any reason why you are joining on on ApplicationId at all? I believe it is in both tables for reference. As UserId is a Guid, it is unique. If you do have the situation where you need to store the same user for two distinct applications, well you can't asp.net membership does not work like that, it would create two distinct users records. The lookup on username/password checks the app id based on the web apps setup (machine key) to enable its uniqueness. The membership table is a red herring.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文