如何使用 FluentHibernate 配置多个映射?

发布于 2024-08-26 17:42:21 字数 1154 浏览 4 评论 0原文

第一次使用 NHibernate/Fluent 来摇摆它,所以如果这是一个天真的问题,请提前道歉。我有一组想要映射的模型。当我创建会话工厂时,我试图立即完成所有映射。我没有使用自动映射(尽管如果我想做的事情最终比应有的更加痛苦,我可能会使用自动映射)。我遇到的问题是,似乎只有顶部地图被占用。给出下面的代码片段并运行一个尝试保存“bar”的单元测试,它失败并检查日志,我看到 NHibernate 正在尝试将 bar 实体保存到 foo 表中。虽然我怀疑这是我的映射,但它可能是我忽略的其他东西。

创建会话工厂的代码(注意我也尝试过单独调用 .Mappings):

Fluently.Configure().Database(MsSqlConfiguration.MsSql2008
    .ConnectionString(c => c
        .Server(@"localhost\SQLEXPRESS")
        .Database("foo")
        .Username("foo")
        .Password("foo")))
    .Mappings(m => 
        { 
            m.FluentMappings.AddFromAssemblyOf<FooMap>()
                .Conventions.Add(FluentNHibernate.Conventions.Helpers
                .Table.Is(x => "foos"));
            m.FluentMappings.AddFromAssemblyOf<BarMap>()
                .Conventions.Add(FluentNHibernate.Conventions.Helpers
                .Table.Is(x => "bars"));
        })
    .BuildSessionFactory();

单元测试片段:

using (var session = Data.SessionHelper.SessionFactory.OpenSession()) {      
   var bar = new Bar();
   session.Save(bar);
   Assert.NotNull(bar.Id);
}

First time rocking it with NHibernate/Fluent so apologies in advance if this is a naive question. I have a set of Models I want to map. When I create my session factory I'm trying to do all mappings at once. I am not using auto-mapping (though I may if what I am trying to do ends up being more painful than it ought to be). The problem I am running into is that it seems only the top map is taking. Given the code snippet below and running a unit test that attempts to save 'bar', it fails and checking the logs I see NHibernate is trying to save a bar entity to the foo table. While I suspect it's my mappings it could be something else that I am simply overlooking.

Code that creates the session factory (note I've also tried separate calls into .Mappings):

Fluently.Configure().Database(MsSqlConfiguration.MsSql2008
    .ConnectionString(c => c
        .Server(@"localhost\SQLEXPRESS")
        .Database("foo")
        .Username("foo")
        .Password("foo")))
    .Mappings(m => 
        { 
            m.FluentMappings.AddFromAssemblyOf<FooMap>()
                .Conventions.Add(FluentNHibernate.Conventions.Helpers
                .Table.Is(x => "foos"));
            m.FluentMappings.AddFromAssemblyOf<BarMap>()
                .Conventions.Add(FluentNHibernate.Conventions.Helpers
                .Table.Is(x => "bars"));
        })
    .BuildSessionFactory();

Unit test snippet:

using (var session = Data.SessionHelper.SessionFactory.OpenSession()) {      
   var bar = new Bar();
   session.Save(bar);
   Assert.NotNull(bar.Id);
}

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

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

发布评论

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

评论(3

薔薇婲 2024-09-02 17:42:21

你做错了。 :)

首先, m.FluentMappings.AddFromAssemblyOf()m.FluentMappings.AddFromAssemblyOf() 正在做完全相同的事情(如果 FooMapBarMap 位于同一个程序集中)。每个都只是告诉 Fluent NHibernate 扫描包含泛型类型的程序集;因此,如果两种类型位于同一程序集中,它将扫描两次。

其次,Conventions 调用的范围不限于您调用它之后的特定程序集,它适用于整个映射集。因此,您要做的就是提供两个约定来将表名称设置为显式值,第二个约定是最后一个要应用的约定。您想要做的是使用 x 参数(这是实体类型)并从中创建表名称。

你需要的是这样的:

.Mappings(m => 
{ 
  m.FluentMappings.AddFromAssemblyOf<FooMap>()
   .Conventions.Add(Table.Is(x => x.Name + "s"));
})

显然我的实现很幼稚,并且根据你的表命名约定,你可能想要使用复数(我相信 Castle 有一个,但用 google 找到一个应该不难) 。

您可以在 约定 上阅读更多有关 约定 的信息。 org" rel="nofollow noreferrer">流畅的 NHibernate wiki。

You're doing it wrong. :)

Firstly, m.FluentMappings.AddFromAssemblyOf<FooMap>() and m.FluentMappings.AddFromAssemblyOf<BarMap>() are doing exactly the same thing (if FooMap and BarMap are in the same assembly). Each one just tells Fluent NHibernate to scan the assembly that contains the generic type; so if both types are in the same assembly, it'll scan it twice.

Secondly, the Conventions call is not scoped to the specific assembly you call it after, it's for the whole set of mappings. So what you're doing is supplying two conventions to set the table name to an explicit value, and the second one is the last one to be applied. What you want to do is use the x parameter (which is the entity type) and create your table name from that.

What you need is something like this:

.Mappings(m => 
{ 
  m.FluentMappings.AddFromAssemblyOf<FooMap>()
   .Conventions.Add(Table.Is(x => x.Name + "s"));
})

Obviously my implementation is naive, and depending on what your table naming convention is you might want to use a pluraliser (I believe Castle has one, but it shouldn't be hard to find one with google).

You can read up more about conventions on the Fluent NHibernate wiki.

巨坚强 2024-09-02 17:42:21

使用类映射,您可以在映射中指定表名称。如果不指定,则与实体类名相同。

class FooMap : ClassMap<Foo>
{
    public FooMap()
    {
        Table("foos");
    }
}

约定适用于所有映射。由于您添加了 2 个表名称约定,因此只有 1 个会生效。

您的 FooMap 和 BarMap 是否在同一个程序集中?您只需添加每个程序集一次。

.Mappings(m => m.FluentMappings.AddFromAssemblyOf<FooMap>())

With classmap you specify the table name in the mapping. If not specified, it will be the same as the entity class name.

class FooMap : ClassMap<Foo>
{
    public FooMap()
    {
        Table("foos");
    }
}

Conventions apply to all mappings. As you added 2 table name conventions, only 1 will take effect.

Are your FooMap and BarMap in the same assembly? You only need to add each assembly once.

.Mappings(m => m.FluentMappings.AddFromAssemblyOf<FooMap>())
夜清冷一曲。 2024-09-02 17:42:21

只是想分享这个会根据结尾字母自动添加复数名称 s、es、ies。不太确定语法和一些例外,但这对我来说似乎没问题。任何异常都使用 Table("foos") 就像 @Lachlan Roche 所说。例如,Customer 类将具有 Customers 表,Category 类将具有 Categories 表。

修改@James Gregory 答案:

.Mappings(m => 
{ 
  m.FluentMappings.AddFromAssemblyOf<FooMap>()
   .Conventions.Add(Table.Is(x => GetPluralName(x.Name));
})


public static string GetPluralName(string oldName)
{
    // This is the very simple. Just ignore exception like days, boys, photos and other specific nouns.
    if (oldName.EndsWith("y"))
        return oldName.Remove(oldName.Length - 1) + "ies";
    else if (oldName.EndsWith("s") || oldName.EndsWith("e") || oldName.EndsWith("h") || oldName.EndsWith("z") || oldName.EndsWith("o")) // Sibilant consonant or "o"
        return oldName + "es";
    return oldName + "s";
}

Just want to share this will automatically add plural name either s, es, ies based on the end alphabet. Not so sure about grammar and some exception but this seems ok for me. Any exception use Table("foos") like @Lachlan Roche said. E.g. Customer class will have Customers table and Category class will have Categories table.

Modified @James Gregory answer:

.Mappings(m => 
{ 
  m.FluentMappings.AddFromAssemblyOf<FooMap>()
   .Conventions.Add(Table.Is(x => GetPluralName(x.Name));
})


public static string GetPluralName(string oldName)
{
    // This is the very simple. Just ignore exception like days, boys, photos and other specific nouns.
    if (oldName.EndsWith("y"))
        return oldName.Remove(oldName.Length - 1) + "ies";
    else if (oldName.EndsWith("s") || oldName.EndsWith("e") || oldName.EndsWith("h") || oldName.EndsWith("z") || oldName.EndsWith("o")) // Sibilant consonant or "o"
        return oldName + "es";
    return oldName + "s";
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文