如何微调 FluentNHibernate 的自动映射器?

发布于 2024-08-30 06:05:11 字数 753 浏览 4 评论 0原文

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

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

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

然而,有一些小问题:

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

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

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

最终编辑: 非常感谢所有过来帮忙的人。 我所有的 Fluent 问题现在都解决了。

Okay, so yesterday I managed to get the latest trunk builds of NHibernate and FluentNHibernate to work with my latest little project. (I'm working on a bug tracking application.) I created a nice data access layer using the Repository pattern.

I decided that my entities are nothing special, and also that with the current maturity of ORMs, I don't want to hand-craft the database.
So, I chose to use FluentNHibernate's auto mapping feature with NHibernate's "hbm2ddl.auto" property set to "create".

It really works like a charm. I put the NHibernate configuration in my app domain's config file, set it up, and started playing with it. (For the time being, I created some unit tests only.) It created all tables in the database, and everything I need for it. It even mapped my many-to-many relationships correctly.

However, there are a few small glitches:

  • All of the columns created in the DB allow null. I understand that it can't predict which properties should allow null and which shouldn't, but at least I'd like to tell it that it should allow null only for those types for which null makes sense in .NET (eg. non-nullable value types shouldn't allow null).
  • All of the nvarchar and varbinary columns it created, have a default length of 255. I would prefer to have them on max instead of that.

Is there a way to tell the auto mapper about the two simple rules above?

If the answer is no, will it work correctly if I modify the tables it created?
(So, if I set some columns not to allow null, and change the allowed length for some other, will it correctly work with them?)

FINAL EDIT:
Big Thanks to everyone who dropped by and helped out.
All of my issues with Fluent are solved now.

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

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

发布评论

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

评论(3

凉风有信 2024-09-06 06:05:11

您可以使用自动映射覆盖来更改自动映射器的工作方式,还可以定义将由自动映射器使用的约定。

以下是有关如何使用约定和覆盖的示例:

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

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

You can use Auto Mapping Overrides to change how the Auto Mapper work, and you can also define Conventions, that will be used instead by the auto mapper.

Here is an example on how to use both the conventions and the overrides:

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

Check these links for more examples:

我为君王 2024-09-06 06:05:11

对于您的 Id 问题,您需要更改 FindIdentity 设置。它在自动映射 wiki 页面中进行了介绍,尽管很简短。

它应该是这样的:

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

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

For your Id woes, you need to change the FindIdentity setting. It's covered in the automapping wiki page, although albeit briefly.

It should go something like this:

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

What this does is instruct the automapper to use your new lambda (m => m.Name == "ID") when trying to discover Ids. m is the property/member, and this lambda is called for each property on each entity; whichever you return true for is the id.

素染倾城色 2024-09-06 06:05:11

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

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 维基。

It's not widely known, but you can set many conventions from the Mappings section in your Configure code e.g.

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

to set a Primary Key convention.

Edit: Clarification of what the PrimaryKey convention does:

The PrimaryKey convention is used to
specify what the column of the
primary key is, not the property.
Discovering the property is a pure
automapping exercise, while
conventions are applied to ClassMaps
and automappings. – James Gregory

This is the list of supported conventions (from the 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")

See The Simplest Conventions section on the FNH wiki.

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