i've got one more question. I upgraded to FluentNHibernate and got now a
problem with my dicitionary mappings.
The class i'am trying to map has the following Property
IDictionary LohnParameter
The mapping is as follows
HasMany(x => x.LohnParameter)
.ForeignKey("cat_condition_version__id")
.DictionaryKey("wrd_cntry__id")
.OneToMany<boLohnartEigenschaften>()
.Not.Lazy()
.Inverse()
.Cascade.AllDeleteOrphan();
The resulting hbm.xml looks like this:
<map cascade="all-delete-orphan" inverse="true" lazy="false" name="LohnParameter" table="boLohnartVersionLohnParameter" mutable="true">
<key>
<column name="cat_condition_version__id" />
</key>
<index-many-to-many class="proSoft.Office.Model.Business.Welt.boLand, proSoft.Office.Model.Business, Version=0.1.19.20243, Culture=neutral, PublicKeyToken=b0e4f89242e69335">
<column name="wrd_cntry__id" />
</index-many-to-many>
<one-to-many class="proSoft.Office.Model.Business.Konditionen.boLohnartEigenschaften, proSoft.Office.Model.Business, Version=0.1.19.20243, Culture=neutral, PublicKeyToken=b0e4f89242e69335" />
</map>
With the new version, the compiler complains, that the Property
"ForeignKey" is missing. I tried now everything, but i can't get it to
work properly. My last try was:
HasMany(x => x.LohnParameter)
.AsMap<boCountry>(
index => index.Column("wrd_cntry__id").Type<boCountry>(),
element => element.Type<boLohnartEigenschaften>()
)
.KeyColumn("cat_condition_version__id")
.Not.LazyLoad()
.Inverse()
.Cascade.AllDeleteOrphan();
But the error i always get is:
{"Could not determine type for:
proSoft.Office.Model.Business.Welt.boCountry,
proSoft.Office.Model.Business, Version=0.1.14.556, Culture=neutral,
PublicKeyToken=b0e4f89242e69335, for columns:
NHibernate.Mapping.Column(wrd_cntry__id)"}
I don't have clue what do do.
Regards
Christian Erhardt
i think you searching for this
HasMany(x => x.LohnParameter)
.AsEntityMap("wrd_cntry__id")
Thank you for the hint, it was the right way. The correct mapping is this:
HasMany(x => x.LohnParameter)
.KeyColumn("cat_condition_version__id")
.AsEntityMap("wrd_cntry__id")
.Not.LazyLoad()
.Inverse()
.Cascade.AllDeleteOrphan();
This results in exact the same hbm.xml file.
Thank you!
Related
I have a requirement to write the mapping using Nhibernate fluent.
I have the following in hbm
<class name="XYZ" table="Some_Table">
<composite-id>
<key-many-to-one name="A" column="A_ID"/>
<key-property name="Term" type="Some_Assembly">
<column name="YEAR"/>
<column name="MONTH"/>
</key-property>
</composite-id>
<property name="P" column="P"/>
</class>
and I would need to rewrite this in fluent. the main reason is that we are moving away from hbm files to fluent.
so far I have the following
public class XYZMap: ClassMap<XYZ>
{
public XYZMap()
{
Table("Some_Table");
CompositeId()
.KeyProperty(x=> x.Term, set =>
{
set.ColumnName("Year");
set.ColumnName("Month");
set.Type(typeof(Some_Assembly));
})
.KeyProperty(x=> x.A, set =>
{
set.ColumnName("A");
set.Type(typeof (Other_Assembly));
});
Map(x=> x.P, "P");
}
}
But I am getting the following error
X.Y.TestZ.PostCreate:
SetUp : Autofac.Core.DependencyResolutionException : An exception was thrown while executing a resolve operation. See the InnerException for details.
----> FluentNHibernate.Cfg.FluentConfigurationException : An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
----> NHibernate.MappingException : Could not compile the mapping document: (XmlDocument)
----> NHibernate.MappingException : Could not determine type for: Other_Assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null, for columns: NHibernate.Mapping.Column(A_ID)
I think I am unable to map many-to-one when I am trying to configure using fluent.
So can someone please help.
You should be using KeyReference instead for column A.
.KeyReference(x => x.A, "A");
I need to define a unique constraint on multiple properties. In XML this would look like:
<properties name="Name" unique="true">
<property name="FirstName" />
<property name="LastName" />
</properties>
What is the mapping-by-code equivalent in NHibernate (3.3+)? Are there any alternatives to create a multi-column unique index?
An alternative way to create a unique index is the following:
this.Property(x => x.FirstName, m => m.UniqueKey("name"));
this.Property(x => x.LastName, m => m.UniqueKey("name"));
I still have not found out how to map <properties>, though.
I am trying to user NHibernate / FluentNHibernate to create a table in my database. I seem to have figured it out for the most part but when I run the test the table isn't created. I see in the Configuration object that the ClassMappings is a big fat zero even thought I have user FluentNHibernate to configure them from an assembly. I somewhat understand this but I am missing some connection somewhere... Here is the code snippets, maybe someone can see what I forogt?
Here is my dataconfig class.
public static FluentConfiguration GetFluentConfiguration()
{
string hibernateCfgFile = #"C:\Users\kenn\Documents\Visual Studio 2008\Projects\NHibernateTestTwo\Infrastructure\hibernate.cfg.xml";
return Fluently.Configure(new Configuration().Configure(#hibernateCfgFile))
.Mappings(cfg => cfg.FluentMappings.AddFromAssembly(typeof(AddressMap).Assembly));
}
Here is the test class.
[Test, Explicit]
public void SetupDatabase()
{
FluentConfiguration conf = DataConfig.GetFluentConfiguration();
conf.ExposeConfiguration(BuildSchema).BuildSessionFactory();
}
private static void BuildSchema(Configuration conf)
{
new SchemaExport(conf).SetOutputFile("drop.sql").Drop(false, true);
new SchemaExport(conf).SetOutputFile("create.sql").Create(false, true);
}
Here is the mappings
public AddressMap()
{
Table("Address");
DynamicUpdate();
Id(a => a.Id).GeneratedBy.GuidComb();
Map(a => a.AddressOne).Not.Nullable().Length(100);
Map(a => a.AddressTwo).Length(100);
Map(a => a.City).Not.Nullable().Length(100);
Map(a => a.state).Not.Nullable().Length(100);
Map(a => a.zip).Not.Nullable().Length(50);
Map(a => a.Primary).Not.Nullable();
}
The hibernate.cfg.xml file
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name="connection.connection_string">
Data Source=MYPC;Initial Catalog=NHibernateSample;Integrated Security=True;
</property>
<property name="show_sql">true</property>
<property name="dialect">
NHibernate.Dialect.MsSql2005Dialect
</property>
<property name="adonet.batch_size">100</property>
<!--<property name="proxyfactory.factory_class">
NHibernate.ByteCode.LinFu.ProxyFactoryFactory,
NHibernate.ByteCode.LinFu
</property>-->
<property name="proxyfactory.factory_class">
NHibernate.ByteCode.Castle.ProxyFactoryFactory,
NHibernate.ByteCode.Castle
</property>
</session-factory>
I am just not sure what is missing there... It clearly is talking to the DB cause if I change the name of the database to something that doesn't exist it trows an exception, I am stuck - I have gone round and round on this and just haven't figured it out yet so any help would be greatly appreciated.
Thanks!
See my comment... Don't forget to make your map classes public or FluentNHibernate won't see them.
I'm trying to switch out .hbm mappings to fluent mappings and have a problem with the mapping of composite-ids and the usage of Interfaces
the Class looks as follows:
public class ClassWithCompositeId {
public virtual IKeyOne KeyOne { get; set; }
public virtual IKeyTwo KeyTwo { get; set; }
}
our hbm mapping looks like this:
<hibernate-mapping ...>
<class name="ClassWithCompositeId" table="t_classwithcompositeid">
<composite-id>
<key-many-to-one name="KeyOne" column="colkeyone" class="company.namespace.boSkillBase, BL_Stammdaten" />
<key-many-to-one name="KeyTwo" column="colkeytwo" class="boQualifikation" />
</composite-id>
</hibernate-mapping>
Please note, that we got interfaces in the Class! No I'm trying to map this with Fluent nhibernate.
Map {
public ClassWithCompositeIdMap() {
CompositeId()
.KeyReference(x => x.KeyOne, "colkeyone")
.KeyReference(x => x.KeyTwo, "colkeytwo");
...
}
}
But now Fluent generates the Mapping as follows:
...
<composite-id mapped="false" unsaved-value="undefined">
<key-many-to-one name="KeyOne" class="company.namespace.IKeyOne, Interfaces, Version=0.1.4.3379, Culture=neutral, PublicKeyToken=null">
<column name="colkeyone" />
</key-many-to-one>
<key-many-to-one name="KeyTwo" class="company.namespace.IKeyTwo, Interfaces, Version=0.1.4.3379, Culture=neutral, PublicKeyToken=null">
<column name="colkeytwo" />
</key-many-to-one>
</composite-id>
...
The "Class" Attribute points now to the Interface not to the implementation of this interface which results in an error.
How can I tell Fluent nHibernate to use another class as the attribute value?
Try downloading NhGen from SourceForge. It reads database schemas and generates Fluent mappings and classes etc. While all the code might not be what you need, it should start you off in the right direction as it supports composite keys and represents them as separate classes off the main entity.
I beleive it uses a syntax similar to
CompositeId()
.ComponentCompositeIdentifier(x => x.Key, "Namespace.Key, Assembly")
.KeyProperty(x => x.Key.Id1, "Id1")
.KeyProperty(x => x.Key.Id2, "Id2")
.KeyProperty(x => x.Key.Id3, "Id3");
Tanks! But I've found the answer on my on. In fact i found a missing feature in fluent nHibernate. The feature has already been added to the dev branch by Paul Batum.
You would use it like so:
Map {
public ClassWithCompositeIdMap() {
CompositeId()
.KeyReference(x => x.KeyOne, k =>
k.Type<KeyOneImplementation>(), "colkeyone")
.KeyReference(x => x.KeyTwo, k =>
k.Type<KeyTwoImplementation>(), "colkeytwo");
...
}
}
http://github.com/paulbatum/fluent-nhibernate/tree/dev
You can see the original Conversation here: http://support.fluentnhibernate.org/discussions/help/349-how-to-map-a-composite-id-when-using-interfaces-or-how-to-change-the-class-attribute-in-the-key-many-to-one-tag
I am then using Fluent NHibernate and its automapping feature to map the the following simplified POCO classes:
public class Webpage
{
public virtual int Id { get; set; }
public virtual string UrlIdentifier { get; set; }
public virtual WebpageType WebpageType { get; set; }
}
public class WebpageType
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
I am then overriding the following mapping to explicitly set no cascading from Webpage to WebpageType:
public class WebpageMap : IAutoMappingOverride<Webpage>
{
public void Override(AutoMapping<Webpage> mapping)
{
mapping.References(w => w.WebpageType).Cascade.None();
}
}
For any pur NHibernate readers, here are the xml mappings produced by fluent:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" name="EveryPage.Core.Domain.Webpage, EveryPage.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Webpage`">
<id name="Id" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
<column name="Id" />
<generator class="identity" />
</id>
<property name="UrlIdentifier" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="UrlIdentifier" />
</property>
<many-to-one cascade="none" class="EveryPage.Core.Domain.WebpageType, EveryPage.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="WebpageType">
<column name="WebpageType_id" />
</many-to-one>
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" name="EveryPage.Core.Domain.WebpageType, EveryPage.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`WebpageType`">
<id name="Id" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
<column name="Id" />
<generator class="identity" />
</id>
<property name="Name" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Name" />
</property>
</class>
</hibernate-mapping>
The problem comes when I test that updates do not cascade to WebpageType via webpage, basically they do!!
I have the following test:
[Test]
public void Assert_SaveOrUpdate_On_Webpage_Does_Not_Cascade_Update_To_WebpageType()
{
// Get the existing webpage.
webpage = _webpageRepository.Get("~/testwebpage1.aspx");
// Update the WebpageType.
const string webpageTypeName = "qwerty test";
webpage.WebpageType.Name = webpageTypeName;
// Save the changes.
Assert.DoesNotThrow(() => _webpageRepository.SaveOrUpdate(webpage));
// We need to flush the changes to the store for it to execute the changes.
Assert.DoesNotThrow(() => NHibernateSession.Current.Flush());
// Remove the webpage and tag from the level 1 cache so we force a trip to the store on our next check.
NHibernateSession.Current.Evict(webpage);
// Check that the webpageType has not been updated.
webpageType = _webpageTypeRepository.Get(webpageType.Id);
Assert.AreNotEqual(webpageTypeName, webpageType.Name);
}
The above test is wrapped in a global transaction.
The test fails and NHibernate does execute an update to the Name of the related WebpageType. The delete and save(create new) cascades work correctly and do not cascade.
Have I missunderstood cascade and/or is there a problem with my logic/test.
Any help/advice is appreciated. Thanks.
If you are trying to stop your app from accidentally changing properties on WebPageType, I think it would be easier and safer to achieve this by marking WebPageType as ReadOnly in the mapping. Then you won't need to protect it via handling cascading in all its associations.
I think this is a misunderstanding of what cascading means.
In your example, NHibernate will update the Name property of you WebPageType no matter what you set cascading to. If you think about it, how would the NHibernate library tell if you're manipulating the property's value using the association from the WebPage instance, or if it's done "directly"?
The settings for cascading in NHibernate tells how associations between entities should be handled, not how the actual value inside each entity is handled. For example, you can set delete cascading, which will automatically delete associated entities when the entity itself is deleted.
Things blog post might make things a bit clearer, or at least work as some kind of reference: http://ayende.com/Blog/archive/2006/12/02/NHibernateCascadesTheDifferentBetweenAllAlldeleteorphansAndSaveupdate.aspx
What does your repository do? Make sure it doesn't run a saveorupdate on the webpagetype. If it isn't then I don't see any obvious explanation for this behaviour.