Constraints not making it to the database schema

9 views
Skip to first unread message

Steven Lyons

unread,
Feb 18, 2009, 7:09:50 PM2/18/09
to Fluent NHibernate
Hi All,

I'm having a weird problem that hopefully someone might have some
thoughts about.

I am trying to auto map and assign more specific constraints to a type
(see User in code below). This is mostly just basic code I've gotten
from blogs. When I run my test, the hbm export file is created and has
the correct attributes. However, the the SchemaExport output to the
console is missing the unique constraint and non-null specification.

The strange part is that is if I use the hbm mappings in the
BuildSessionFactory method (currently commented out) the constraints
are added to the schema. It's when I try to use the auto mapping that
I run into trouble. I also had this working previously (using the non-
fluent configuration, see below) but that code also stopped working
with the same problem when I updated to a recent FNH version.

Is this something that I was doing wrong before and just happened to
work? Or is this a regression?

Thanks!
s.


-------

// Create SessionFactory
UnitOfWork.SessionFactory = new NHibernateHelper().BuildSessionFactory
(config, BuildSchema);

// Export Schema
public void BuildSchema(Configuration cfg)
{
new SchemaExport(cfg).Create(true, true);
}

// Build Session Factory
public ISessionFactory BuildSessionFactory(Configuration config,
Action<Configuration>
configAction)
{
var f = FluentNHibernate.Cfg.Fluently
.Configure(config)
.Mappings(m =>
{
//m.HbmMappings
// .AddFromAssemblyOf<NHibernateHelper>();

m.AutoMappings.Add(
AutoPersistenceModel.MapEntitiesFromAssemblyOf<IEntity>
()
.Where(entity => entity.Namespace.Contains
("Domain") &&
entity.GetProperty("Id") != null
&&
entity.IsAbstract == false)
.WithConvention(convention =>
{
convention.IsBaseType = (type => (type ==
typeof(Entity<int>) ||
(type ==
typeof(Entity<Guid>))));
})
.ForTypesThatDeriveFrom<User>(map =>
{
map.Map(p => p.Username).Unique().Not.Nullable
();
})
).ExportTo(@"c:\src\project\log\");
})
.ExposeConfiguration(configAction)
.BuildSessionFactory();

return f;
}

<!-- hbm Export File -->
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-
lazy="true" assembly="Project.Core" namespace="Project.Core.Domain">
<class name="User" table="Users" xmlns="urn:nhibernate-mapping-2.2">
<id name="Id" column="Id" type="Guid">
<generator class="guid.comb" />
</id>
<property name="Username" unique="true" not-null="true"
length="100" type="String">
<column name="Username" />
</property>
</class>
</hibernate-mapping>

-- SQLite schema export:
create table Users (
Id UNIQUEIDENTIFIER not null,
Username TEXT,
primary key (Id)
)

// Previously working code
public PersistenceModel BuildModel()
{
var model = new AutoPersistenceModel();

foreach (Assembly assembly in this.fluentAssemblies)
{
// Add assembly for the fluent mapping files
model.addMappingsFromAssembly(assembly);

// Add assembly and configuration for fluent AutoMapped
classes
model.AddEntityAssembly(assembly);
}

model.Where(entity => entity.Namespace.Contains("Domain") &&
entity.GetProperty("Id") != null &&
entity.IsAbstract == false)
.WithConvention(c =>
{
c.IsBaseType = (type => (type == typeof(Entity<int>) ||
(type == typeof
(Entity<Guid>))));
});

// TODO: Move these out to a proper location!!!
model.ForTypesThatDeriveFrom<User>(map =>
{
map.Map(p => p.Username).WithUniqueConstraint()
.CanNotBeNull();
});

return model;
}

James Gregory

unread,
Feb 19, 2009, 9:35:51 AM2/19/09
to fluent-n...@googlegroups.com
There was a bug in the Not.Nullable code that I've just fixed, could you confirm (or deny) whether this has had any affect on your problem?

Steven Lyons

unread,
Feb 19, 2009, 11:23:59 AM2/19/09
to Fluent NHibernate
Hi James,

The new fix has partly resolved the issue. The "not null" is now
making it through to the schema but the unique constraint is still
being dropped.

s.



On Feb 19, 9:35 am, James Gregory <jagregory....@gmail.com> wrote:
> There was a bug in the Not.Nullable code that I've just fixed, could you
> confirm (or deny) whether this has had any affect on your problem?
>

Steven Lyons

unread,
Feb 19, 2009, 5:27:43 PM2/19/09
to Fluent NHibernate
It looks like same problem occurs with the length attribute. As with
the previous fix, when the column element is present in a property, as
it is the FNH hbm exports, the length should be on the column instead
of the property.

James Gregory

unread,
Feb 19, 2009, 5:33:43 PM2/19/09
to fluent-n...@googlegroups.com
Thanks for the heads up, I'll fix this asap.

Steven Lyons

unread,
Feb 19, 2009, 6:41:55 PM2/19/09
to Fluent NHibernate
James,

Attached is a patch that gets most of the way there, I think. I added
a test for the unique attribute and made changes similar to what you
did for the previous fix.

There is one test that isn't passing. The hbm is getting two lengths
for strings now - the correct one on the column (length 20) and one on
the property (length 100). I'm guessing it's from a convention that
has been set. I'm going to try to track that down but in case I can't
find it, hopefully this will get you most of the way there.

s.

Index: src/FluentNHibernate.Testing/DomainModel/Mapping/
ClassMapXmlCreationTester.cs
===================================================================
--- src/FluentNHibernate.Testing/DomainModel/Mapping/
ClassMapXmlCreationTester.cs (revision 330)
+++ src/FluentNHibernate.Testing/DomainModel/Mapping/
ClassMapXmlCreationTester.cs (working copy)
@@ -463,7 +463,7 @@
{
new MappingTester<MappedObject>()
.ForMapping(m => m.Map(x => x.Name).Unique())
- .Element("class/property").HasAttribute("unique",
"true");
+ .Element("class/property/column").HasAttribute
("unique", "true");
}

[Test]
@@ -471,7 +471,7 @@
{
new MappingTester<MappedObject>()
.ForMapping(m => m.Map(x => x.Name).Not.Unique())
- .Element("class/property").HasAttribute("unique",
"false");
+ .Element("class/property/column").HasAttribute
("unique", "false");
}

[Test]
Index: src/FluentNHibernate.Testing/DomainModel/Mapping/
PropertyMapTester.cs
===================================================================
--- src/FluentNHibernate.Testing/DomainModel/Mapping/
PropertyMapTester.cs (revision 330)
+++ src/FluentNHibernate.Testing/DomainModel/Mapping/
PropertyMapTester.cs (working copy)
@@ -129,35 +129,21 @@
[Test]
public void
Map_WithFluentLength_OnString_UsesWithLengthOf_PropertyColumnAttribute
()
{
- var classMap = new ClassMap<PropertyTarget>();
+ new MappingTester<PropertyTarget>()
+ .ForMapping(m => m.Map(x => x.Name).WithLengthOf(20))
+ .Element("class/property
[@name='Name']").DoesntHaveAttribute("length")
+ .Element("class/property[@name='Name']/
column").HasAttribute("length", "20");
+ }

- classMap.Map(x => x.Name)
- .WithLengthOf(20);
-
- var document = classMap.CreateMapping(new MappingVisitor
());
-
- // attribute on property
- var classElement =
document.DocumentElement.SelectSingleNode("class");
- var propertyElement = (XmlElement)
classElement.SelectSingleNode("property");
- propertyElement.AttributeShouldEqual("length", "20");
+ [Test]
+ public void
Map_WithFluentLength_OnDecimal_UsesWithLengthOf_PropertyColumnAttribute
()
+ {
+ new MappingTester<PropertyTarget>()
+ .ForMapping(m => m.Map(x =>
x.DecimalProperty).WithLengthOf(1))
+ .Element("class/property
[@name='DecimalProperty']").DoesntHaveAttribute("length")
+ .Element("class/property[@name='DecimalProperty']/
column").HasAttribute("length", "1");
}

- [Test]
- public void
Map_WithFluentLength_OnDecimal_UsesWithLengthOf_PropertyColumnAttribute
()
- {
- var classMap = new ClassMap<PropertyTarget>();
-
- classMap.Map(x => x.DecimalProperty)
- .WithLengthOf(1);
-
- var document = classMap.CreateMapping(new MappingVisitor());
-
- // attribute on property
- var classElement = document.DocumentElement.SelectSingleNode
("class");
- var propertyElement = (XmlElement)classElement.SelectSingleNode
("property");
- propertyElement.AttributeShouldEqual("length", "1");
- }
-
[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void
Map_WithFluentLength_UsesInvalidWithLengthOf_PropertyColumnAttribute()
@@ -198,6 +184,15 @@
}

[Test]
+ public void
Map_WithFluentLength_UsesUnique_PropertyColumnAttribute()
+ {
+ new MappingTester<PropertyTarget>()
+ .ForMapping(m => m.Map(x => x.Name).Unique())
+ .Element("class/property
[@name='Name']").DoesntHaveAttribute("unique")
+ .Element("class/property[@name='Name']/
column").HasAttribute("unique", "true");
+ }
+
+ [Test]
public void
Map_WithFluentLength_UsesUniqueKey_PropertyColumnAttribute()
{
var classMap = new ClassMap<PropertyTarget>();
Index: src/FluentNHibernate/Mapping/PropertyMap.cs
===================================================================
--- src/FluentNHibernate/Mapping/PropertyMap.cs (revision 330)
+++ src/FluentNHibernate/Mapping/PropertyMap.cs (working copy)
@@ -157,7 +157,7 @@
public IProperty WithLengthOf(int length)
{
if (CanApplyLengthAttribute())
- this.AddAlteration(x => x.SetAttribute("length",
length.ToString()));
+ SetAttributeOnColumnElement("length", length.ToString
());
else
throw new InvalidOperationException(String.Format
("{0} is not a string.", this._property.Name));
return this;
@@ -232,7 +232,7 @@

public IProperty Unique()
{
- _extendedProperties.Store("unique", nextBool.ToString
().ToLowerInvariant());
+ SetAttributeOnColumnElement("unique", nextBool.ToString
().ToLowerInvariant());
nextBool = true;
return this;
}



On Feb 19, 5:33 pm, James Gregory <jagregory....@gmail.com> wrote:
> Thanks for the heads up, I'll fix this asap.
>

Steven Lyons

unread,
Feb 19, 2009, 7:47:57 PM2/19/09
to Fluent NHibernate
Take II: This patch passes the tests.
Index: src/FluentNHibernate/Conventions.cs
===================================================================
--- src/FluentNHibernate/Conventions.cs (revision 330)
+++ src/FluentNHibernate/Conventions.cs (working copy)
@@ -92,7 +92,7 @@
{
if (property.PropertyType == typeof(string))
{
- property.SetAttribute("length",
DefaultStringLength.ToString());
+ property.SetAttributeOnColumnElement("length",
DefaultStringLength.ToString());
}

ITypeConvention convention = FindConvention
(property.PropertyType);
Index: src/FluentNHibernate/Mapping/PropertyMap.cs
===================================================================
--- src/FluentNHibernate/Mapping/PropertyMap.cs (revision 330)
+++ src/FluentNHibernate/Mapping/PropertyMap.cs (working copy)
@@ -157,7 +157,7 @@
public IProperty WithLengthOf(int length)
{
if (CanApplyLengthAttribute())
- this.AddAlteration(x => x.SetAttribute("length",
length.ToString()));
+ this.AddAlteration(x => x.SetColumnProperty("length",
length.ToString()));
> ...
>
> read more »

Filip Kinsky

unread,
Mar 11, 2009, 11:53:22 AM3/11/09
to Fluent NHibernate
Is this applied to the trunk? I'm just facing simmilar problems (on
Oracle) - fields don't get length specified and FK names are generated
randomly even though I specify both in my conventions...
> ...
>
> číst dál >>

James Gregory

unread,
Mar 11, 2009, 12:00:49 PM3/11/09
to fluent-n...@googlegroups.com
Sorry guys, this one slipped under the radar. I'm swamped currently, but I should be doing a comb through of patches in the next few days.

Filip: Hopefully you should be able to apply Steven's patch directly to your code for the time being.

2009/3/11 Filip Kinsky <fi...@filovo.net>
Reply all
Reply to author
Forward
0 new messages