【问题标题】:How to fine tune FluentNHibernate's auto mapper?如何微调 Fluent NHibernate 自动映射器?
【发布时间】:2010-04-26 10:28:40
【问题描述】:

好的,所以昨天我设法获得了最新的 NHibernate 和 FluentNHibernate 主干构建,以用于我最新的小项目。 (我正在开发一个错误跟踪应用程序。)我使用存储库模式创建了一个不错的数据访问层。

我认为我的实体没有什么特别之处,而且随着 ORM 目前的成熟,我不想手工制作数据库。 因此,我选择使用 FluentNHibernate 的自动映射功能,并将 NHibernate 的“hbm2ddl.auto”属性设置为“create”。

它真的像一个魅力。我将 NHibernate 配置放在我的应用程序域的配置文件中,进行设置,然后开始使用它。 (目前,我只创建了一些单元测试。)它创建了数据库中的所有表,以及我需要的一切。它甚至正确地映射了我的多对多关系。

但是,有一些小故障:

  • 在数据库中创建的所有列都允许为空。我知道它无法预测哪些属性应该允许 null 哪些不应该,但至少我想告诉它,它应该只允许 null 对于那些 null 在 .NET 中有意义的类型(例如,非- 可空值类型不应允许为空)。
  • 它创建的所有 nvarchar 和 varbinary 列的默认长度为 255。我更愿意将它们设置为 max 而不是那个。

有没有办法告诉自动映射器上面的两个简单规则?

如果答案是否定的,如果我修改它创建的表,它会正常工作吗? (所以,如果我将某些列设置为不允许为空,并更改其他一些列的允许长度,它会正确使用它们吗?)

最终编辑: 非常感谢所有路过并提供帮助的人。 我所有的 Fluent 问题现在都解决了。

【问题讨论】:

    标签: .net nhibernate orm fluent-nhibernate nhibernate-mapping


    【解决方案1】:

    您可以使用 Auto Mapping Overrides 来更改 Auto Mapper 的工作方式,您还可以定义将由 auto mapper 使用的约定。

    这是一个关于如何使用约定和覆盖的示例:

    var mappings = new AutoPersistenceModel();
    mappings.Conventions.Setup(s => s.Add<ColumnNullabilityConvention>());
    mappings.UseOverridesFromAssemblyOf<AssemblyName>();
    
    // This convention will set all properties to be not nullable
    
    public class ColumnNullabilityConvention: IPropertyConvention, IPropertyConventionAcceptance
    {
       public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
       {
           criteria.Expect(x => x.Nullable, Is.Not.Set);
       }
    
       public void Apply(IPropertyInstance instance)
       {
           instance.Not.Nullable();
       }
    }
    
    // This override will change "string" to use "text" instead of "varchar(255)".
    // Also set the property to be not nullable
    
    public class SomeOverrideInTheSameAssembly : IAutoMappingOverride<TypeName>
    {
       public void Override(AutoMapping<TypeName> mapping)
       {
           mapping.Map(x => x.Property).CustomType("StringClob").CustomSqlType("text");
           mapping.Map(x => x.Property).Not.Nullable();
       }
    }    
    

    查看这些链接以获取更多示例:

    【讨论】:

    • 非常感谢!我设法使用以下代码使其工作: persistenceModel.Conventions.Add(ConventionBuilder.Property.Always(x => x.Length(16000)));虽然这有点 hacky,因为在 SQL Server 中,16000 会将其设置为 MAX,但对于其他数据库服务器可能并不好。有通用的方法吗?
    • 并非如此。一般来说,您应该将其设置为“StringClob”自定义类型,因为这对 NHibernate 意味着它是一个“文本”类型,但即便如此,一些 NHibernate 数据库提供商(如 PostgreSQL)也会忽略它。这就是为什么例如在我的 Override 示例中,我同时使用了 CustomType 和 CustomSqlType 声明,将其设置为“文本”。或者,如果您更改下面的数据库模式,那么 NHibernate 将不会真正关心它是 varchar 还是更大的东西(文本、blob 等)。但这也不是一个好的解决方案,因为有很多显而易见的事情。
    • 好吧,我暂时就这样吧。顺便说一句,很高兴在这里看到另一个匈牙利人。 :)
    【解决方案2】:

    对于您的身份问题,您需要更改 FindIdentity 设置。 automapping wiki page 对此进行了介绍,尽管内容很简短。

    应该是这样的:

    AutoMap.AssemblyOf<Entity>() // your usual setup
      .Setup(s =>
      {
        s.FindIdentity = m => m.Name == "ID";
      });
    

    它的作用是指示自动映射器在尝试发现 Id 时使用新的 lambda (m =&gt; m.Name == "ID")。 m 是属性/成员,每个实体上的每个属性都会调用这个 lambda;无论您返回 true 都是 id。

    【讨论】:

    • @James - 那么为什么 PrimaryKey 约定对他不起作用呢? FNH中的错误?方法误用?
    • PrimaryKey 约定用于指定主键的是什么,而不是属性。发现属性是一个纯粹的自动映射练习,而约定适用于 ClassMaps 和自动映射。
    • 感谢您的澄清 - 猜猜这个名字欺骗了 Venemo 和我。我将编辑我的答案。
    • 感谢詹姆斯的澄清。
    【解决方案3】:

    它并不广为人知,但您可以从配置代码中的映射部分设置许多约定,例如

    Fluently.Configure()
      .Database(/* database config */)
      .Mappings(m =>
      {
        m.FluentMappings
          .AddFromAssemblyOf<Entity>()
          .Conventions.Add(PrimaryKey.Name.Is(x => "ID"));
      })
    

    设置主键约定。

    编辑:澄清 PrimaryKey 约定的作用:

    PrimaryKey 约定用于 指定的内容 主键是,不是属性。 发现财产是一个纯粹的 自动映射练习,同时 约定应用于 ClassMap 和自动映射。 ——詹姆斯·格雷戈里

    这是支持的约定列表(来自 wiki):

    Table.Is(x => x.EntityType.Name + "Table")
    PrimaryKey.Name.Is(x => "ID")
    AutoImport.Never()
    DefaultAccess.Field()
    DefaultCascade.All()
    DefaultLazy.Always()
    DynamicInsert.AlwaysTrue()
    DynamicUpdate.AlwaysTrue()
    OptimisticLock.Is(x => x.Dirty())
    Cache.Is(x => x.AsReadOnly())
    ForeignKey.EndsWith("ID")
    

    请参阅 FNH wiki 上的 The Simplest Conventions 部分。

    【讨论】:

    • 非常感谢您的回答。我设法使用一些自定义约定让它工作。但是,在查看了 wiki 之后,还有一件事让我感到烦恼。我无法让 PrimaryKey.Name.Is(x => "ID") 正常工作。
    • 抱歉,我从未使用过 PrimaryKey 约定 - 我只是从 wiki 复制了示例。可能是一个错误。我建议你在 FNH 支持论坛上发帖提问 - support.fluentnhibernate.org
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-10
    • 1970-01-01
    • 2013-05-20
    • 2011-06-18
    相关资源
    最近更新 更多