NHibernate - Could not compile the mapping document - nhibernate

It is my firs time using NHibernate, I'm getting source code for a program from my friend after that, the program is running well after that I'm trying to add "Stock.hbm.xml" as following:
`
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="NBooks.Core.Models"
assembly="NBooks.Core">
<class name="Stock" table="Stocks" lazy="false">
<id name="ID">
<column name="Stock_ID" />
<generator class="identity" />
</id>
<property name="Stock_name" column="Stock_name" />
<property name="Comp_ID" column="Comp_ID" />
<property name="Stock_Code" column="Stock_Code" />
<property name="Address" column="Address" />
<property name="Nots" column="Nots" />
</class>
</hibernate-mapping>
`
with my class "Stock.cs"
using System;
using System.Collections.Generic;
namespace NBooks.Core.Models
{
public class Stock : BaseModel<Stock>
{
public virtual string Stock_name { get; set; }
public virtual string Stock_Code { get; set; }
public virtual int Comp_ID { get; set; }
public virtual string Notes { get; set; }
public virtual string Address { get; set; }
public virtual bool Inactive { get; set; }
public Stock()
{
}
public Stock(string name)
{
this.Stock_name = name;
}
}
public class StockEventArgs : EventArgs
{
public Stock Stock { get; set; }
public StockEventArgs(Stock Stock)
{
this.Stock = Stock;
}
}
public delegate void StockEventHandler(Stock sender, EventArgs e);
}
the Base model is:
using System;
using System.Collections.Generic;
using NBooks.Core.Util;
using NBooks.Data.NHibernate;
using NHibernate;
namespace NBooks.Core.Models
{
public interface IBaseModel
{
int Id { get; set; }
}
public class BaseModel<T> : IBaseModel
{
IList<string> errors = new List<string>();
public virtual int Id { get; set; }
public virtual bool HasErrors {
get { return errors.Count > 0; }
}
public virtual IList<string> Errors {
get { return errors; }
}
public BaseModel()
{
}
public virtual void Validate()
{
Errors.Clear();
}
public virtual void SaveOrUpdate()
{
ITransaction trans = null;
try {
ISession session = NHibernateHelper.OpenSession();
trans = session.BeginTransaction();
session.SaveOrUpdate(this);
session.Flush();
trans.Commit();
} catch (Exception ex) {
LoggingService.Error(ex.Message);
MessageService.ShowError(ex.Message);
trans.Rollback();
}
}
public virtual void Delete()
{
ITransaction trans = null;
try {
ISession session = NHibernateHelper.OpenSession();
trans = session.BeginTransaction();
session.Delete(this);
session.Flush();
trans.Commit();
} catch (Exception ex) {
LoggingService.Error(ex.Message);
MessageService.ShowError(ex.Message);
trans.Rollback();
}
}
public static T Read(int id)
{
return NHibernateHelper.OpenSession().Load<T>(id);
}
public static IList<T> FindAll()
{
return
NHibernateHelper.OpenSession().CreateCriteria(typeof(T)).List<T>();
}
}
}
when build it appers every thing is well and no errors , when run the error "NHibernate - Could not compile the mapping document Stock.hbm.xml" appears.
Thanx in advance

I noticed you have a typo in you XML:
<property name="Nots" column="Nots" />
I would suggest that you look into using Fluent NHibernate as well. It is strongly typed (for the most part) and the mapping files are easier to read and use lambda expressions so that you don't have to go the XML route.
Your mapping would instead look like this:
public class StockMap(): ClassMap<Stock>
{
public StockMap(){
Id(x => x.Id).Column("Stock_ID").GeneratedBy.Identity();
Map(x => x.Comp_ID);
Map(x => x.Address);
Map(x => x.Notes);
}
}

You have a typo in your mapping
<property name="Nots" column="Nots" />
should be
<property name="Notes" column="Nots" />

Related

Adding IAutoMappingOverride with interface for all domain classes

I have an IAuditable interface that defines my class domain as auditable.
public interface IAuditable
{
DateTime CreateAt { get; }
IUser CreateBy { get; }
DateTime? UpdateAt { get; }
IUser UpdateBy { get; }
}
For these classes (there are many) that implement this interface, the configuration is the same! So I decided to override convention:
public class AudityConvention : IAutoMappingOverride<IAuditable>
{
public void Override(AutoMapping<IAuditable> mapping)
{
mapping.Map(p => p.CreateAt).ReadOnly().Access.Property().Not.Nullable().Not.Update().Default("getDate()").Generated.Insert();
mapping.References<Usuario>(p => p.CreateBy).Not.Nullable().Not.Update();
mapping.Map(p => p.UpdateAt).ReadOnly().Access.Property().Default("getDate()").Not.Insert().Generated.Always();
mapping.References<Usuario>(p => p.UpdateBy).Nullable().Not.Insert();
}
}
And configure it
_configuration = Fluently.Configure() // All config from app.config
.Mappings(m =>
{
m.AutoMappings.Add(
AutoMap.AssemblyOf<Usuario>()
.UseOverridesFromAssemblyOf<AudityConvention>()
.Conventions.Setup(c => c.AddFromAssemblyOf<EnumConvention>())
);
m.FluentMappings
.AddFromAssemblyOf<UsuarioMap>()
.Conventions.AddFromAssemblyOf<EnumConvention>()
;
})
.BuildConfiguration();
SessionFactory = _configuration.BuildSessionFactory();
Session = SessionFactory.OpenSession();
var export = new SchemaExport(_configuration);
export.Drop(false, true); // drop and recreate the database (Just to make sure that the settings are being applied)
export.Execute(false, true, false); // Create de database
With this app.config
<appSettings>
<add key="FluentAssertions.TestFramework" value="mstest"/>
</appSettings>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
<property name="connection.connection_string_name">Data</property>
<property name="show_sql">true</property>
</session-factory>
</hibernate-configuration>
Exemple domain class:
public class Entidade : IAuditable
{
public virtual int Id { get; protected set; }
[StringLength(255)]
public virtual string Nome { get; set; }
// Implements IAuditable
public virtual DateTime CreateAt { get; protected set; }
public virtual IUser CreateBy { get; set; }
public virtual DateTime? UpdateAt { get; protected set; }
public virtual IUser UpdateBy { get; set; }
}
And map it:
public class EntidadeMap : ClassMap<Entidade>
{
public EntidadeMap()
{
Id(p => p.Id);
Map(p => p.Nome);
Table("Entidades");
}
}
Results:
Question
What am I doing wrong?
How to create a convention for all classes that implement IAuditable settings are the same!
The part of the configuration below was added later. From what I read, overwrite support only by AutoMappings conventions.
m.AutoMappings.Add(
AutoMap.AssemblyOf<Usuario>()
.UseOverridesFromAssemblyOf<AudityConvention>()
.Conventions.Setup(c => c.AddFromAssemblyOf<EnumConvention>())
);
I think you're out of luck. I don't believe overrides work on interfaces.
You're better off doing something like this:
public class BaseAuditable : IAuditable
{
....
}
public class Entidade : BaseAuditable
{ ... }
You can use
IAutoMappingOverride<BaseAuditable> instead of IAutoMappingOverride<IAuditable>
I hope I'm wrong but I tried to make it work so many times with interfaces with no luck.
a possiblity
var overrideMethod = typeof(AutoPersistenceModel).GetMethod("Override");
foreach (var type in typeof(IAuditable).Assembly)
{
if (typeof(IAuditable).IsAssignableFrom(type))
{
overrideMethod.MakeGenericMethod(type).Invoke(new Action<IAuditable>(MapAuditables));
}
}

Best way to implement Entity with translatable properties in NHibernate

Consider the following class (simplified in order to focus in the core problem):
public class Question
{
public virtual string QuestionId { get; set; }
public virtual string Text { get; set; }
public virtual string Hint { get; set; }
}
and tables:
Question
- QuestionId ((primary key, identity column and key)
- Code
QuestionTranslation
- QuestionTranslationId (primary key, identity column; not really relevant to the association)
- QuestionId (composite key element 1)
- CultureName (composite key element 2) (sample value: en-US, en-CA, es-ES)
- Text
- Hint
How I can map the Question class so the Text and Hint properties are populated using the current thread's culture. If the thread's culture is changed I would like the Text and Hint properties to automatically return the appropriate value without the need for the Question entity to be reloaded.
Note that I'm only outlining the relevant class and properties from the business side. I'm totally open to any new class or property needed to achieve the desired functionality.
An alternative to Firo's answer (yes, I copied it and adapted it and feel bad about this).
It uses a dictionary and maps the translations as composite element (so it doesn't need the id at all)
public class Question
{
public virtual string QuestionId { get; set; }
public virtual string Text
{
get
{
var translation = Translations[CultureInfo.CurrentCulture.Name];
if (translation != null) return translation.Text
return null;
}
set
{
GetTranslation(CultureInfo.CurrentCulture.Name).Text = value;
}
}
public virtual string Hint
{
get
{
var translation = Translations[CultureInfo.CurrentCulture.Name];
if (translation != null) return translation.Hint
return null;
}
set
{
GetTranslation(CultureInfo.CurrentCulture.Name).Hint = value;
}
}
private QuestionTranslation GetTranslation(CultureInfo.CurrentCulture.Name)
{
QuestionTranslation translation;
if (!Translations.TryGetValue(CultureInfo.CurrentCulture.Name, out translation))
{
translation = new QuestionTranslation()
Translations[CultureInfo.CurrentCulture.Name] = translation;
}
return translation;
}
protected virtual IDictionary<string, QuestionTranslation> Translations { get; private set; }
}
class QuestionTranslation
{
// no id, culture name
public virtual string Text { get; set; }
public virtual string Hint { get; set; }
}
mapping:
<class name="Question">
<id name="QuestionId" column="QuestionId"/>
<map name="Translations" table="QuestionTranslation" lazy="true">
<key column="QuestionId"/>
<index column="CultureName"/>
<composite-element class="QuestionTranslation">
<property name="Text"/>
<property name="Hint"/>
</composite-element>
</bag>
</class>
Edited to reflect changed answer:
public class Question
{
public virtual string QuestionId { get; set; }
public virtual string Text
{
get
{
var currentculture = CultureInfo.CurrentCulture.Name;
return Translations
.Where(trans => trans.CultureName == currentculture)
.Select(trans => trans.Text)
.FirstOrDefault();
}
set
{
var currentculture = CultureInfo.CurrentCulture.Name;
var translation = Translations
.Where(trans => trans.CultureName == currentculture)
.FirstOrDefault();
if (translation == null)
{
translation = new QuestionTranslation();
Translations.Add(translation);
}
translation.Text = value;
}
}
public virtual string Hint
{
get
{
var currentculture = CultureInfo.CurrentCulture.Name;
return Translations
.Where(trans => trans.CultureName == currentculture)
.Select(trans => trans.Hint)
.FirstOrDefault();
}
set
{
var currentculture = CultureInfo.CurrentCulture.Name;
var translation = Translations
.Where(trans => trans.CultureName == currentculture)
.FirstOrDefault();
if (translation == null)
{
translation = new QuestionTranslation();
Translations.Add(translation);
}
translation.Hint = value;
}
}
protected virtual ICollection<QuestionTranslation> Translations { get; set; }
}
class QuestionTranslation
{
public virtual int Id { get; protected set; }
public virtual string CultureName { get; set; }
public virtual string Text { get; set; }
public virtual string Hint { get; set; }
}
<class name="Question" xmlns="urn:nhibernate-mapping-2.2">
<id name="QuestionId" column="QuestionId"/>
<bag name="Translations" table="QuestionTranslation" lazy="true">
<key>
<column name="QuestionId"/>
</key>
<one-to-many class="QuestionTranslation"/>
</bag>
</class>
<class name="QuestionTranslation" table="QuestionTranslation" xmlns="urn:nhibernate-mapping-2.2">
<id name="QuestionTranslationId"/>
<many-to-one name="ParentQuestion" column="QuestionId"/>
</class>
if you have a lot of translations then change ICollection<QuestionTranslation> Translations { get; set; } to IDictionary<string, QuestionTranslation> Translations { get; set; } and map as <map> but normally the above should do it

Nhibernate 3.1 .Net 4.0 - Get Composite-Id from List of Query

I have a MS SQL db with a table that has a composite id.
This is my xml configuration file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="SimpleMapping.Domain"
namespace="SimpleMapping.Domain">
<class name="TabMaster" table="TabMaster">
<composite-id class="TabMasterCompositeKey">
<key-property column="Configuration" name="Configuration" type="AnsiString" />
<key-property column="ResolutionType" name="ResolutionType" type="int" />
</composite-id>
<property name="Description" column="Description" type="AnsiString" />
<property name="Title" column="Title" type="AnsiString" />
<property name="IdResolutionFileDes" column="idResolutionFileDes" type="AnsiString" />
<property name="WorkflowType" column="WorkflowType" type="AnsiString" />
<property name="ViewAllStep" column="ViewAllStep" type="AnsiString" />
<property name="ManagedData" column="ManagedData" type="AnsiString" />
</class>
</hibernate-mapping>
I have created my mapping objects:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SimpleMapping.Domain
{
public class TabMaster
{
public virtual string Configuration { get; set; }
public virtual int ResolutionType { get; set; }
public virtual string Description { get; set; }
public virtual string Title { get; set; }
public virtual string IdResolutionFileDes { get; set; }
public virtual string WorkflowType { get; set; }
public virtual string ViewAllStep { get; set; }
public virtual string ManagedData { get; set; }
}
}
and
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SimpleMapping.Domain
{
class TabMasterCompositeKey
{
public virtual string Configuration { get; set; }
public virtual int ResolutionType { get; set; }
public override bool Equals(object obj)
{
TabMasterCompositeKey compareTo = (TabMasterCompositeKey)obj;
return (this.Configuration == compareTo.Configuration) && (this.ResolutionType == compareTo.ResolutionType);
}
public override int GetHashCode()
{
return this.ToString().GetHashCode();
}
public override string ToString()
{
return Configuration.ToString() + "/" + ResolutionType.ToString();
}
}
}
In my Main() I try to list the elements in the table doing:
namespace SimpleMapping.Console
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Cfg;
using SimpleMapping.Domain;
class Program
{
static void Main(string[] args)
{
ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
using (ISession session = sessionFactory.OpenSession())
{
using (ITransaction tx = session.BeginTransaction())
{
IQuery query = session.CreateQuery("from TabMaster");
foreach (TabMaster tm in query.List<TabMaster>())
System.Console.WriteLine(string.Format("ID: {0}\nConfiguration: {1}\nManagedData: {2}\n", tm.Configuration, tm.Description, tm.ManagedData));
tx.Commit();
session.Close();
}
}
System.Console.ReadKey();
}
}
}
and I can see the parameters that are not a key.
So I can see Description and ManagedData but I can't see tm.Configuration : in the stack is set to Null for every record.
What's the problem?
I think this is related to the composite-id rule (?)
Thank you for your reply!
You should name the composite key:
<composite-id class="TabMasterCompositeKey" name="TheKey">
<key-property column="Configuration" name="Configuration" type="AnsiString" />
<key-property column="ResolutionType" name="ResolutionType" type="int" />
</composite-id>
and put a property in the TabMaster entity:
public class TabMaster
{
public virtual TabMasterCompositeKey TheKey { get; set; }
public virtual string Description { get; set; }
public virtual string Title { get; set; }
public virtual string IdResolutionFileDes { get; set; }
public virtual string WorkflowType { get; set; }
public virtual string ViewAllStep { get; set; }
public virtual string ManagedData { get; set; }
}
with this you will be able to see the single key property on the entity.

nhibernate says 'mapping exception was unhandled' no persister for: MyNH.Domain.User

I am using nHibernate and fluent.
I created a User.cs:
public class User
{
public virtual int Id { get; set; }
public virtual string Username { get; set; }
public virtual string Password { get; set; }
public virtual string Email { get; set; }
public virtual DateTime DateCreated { get; set; }
public virtual DateTime DateModified { get; set; }
}
Then in my mappinds folder:
public class UserMapping : ClassMap<User>
{
public UserMapping()
{
WithTable("ay_users");
Not.LazyLoad();
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Username).Not.Nullable().WithLengthOf(256);
Map(x => x.Password).Not.Nullable().WithLengthOf(256);
Map(x => x.Email).Not.Nullable().WithLengthOf(100);
Map(x => x.DateCreated).Not.Nullable();
Map(x => x.DateModified).Not.Nullable();
}
}
Using the repository pattern for the nhibernate blog:
public class UserRepository : Repository<User>
{
}
public class Repository<T> : IRepository<T>
{
public ISession Session
{
get
{
return SessionProvider.GetSession();
}
}
public T GetById(int id)
{
return Session.Get<T>(id);
}
public ICollection<T> FindAll()
{
return Session.CreateCriteria(typeof(T)).List<T>();
}
public void Add(T product)
{
Session.Save(product);
}
public void Remove(T product)
{
Session.Delete(product);
}
}
public interface IRepository<T>
{
T GetById(int id);
ICollection<T> FindAll();
void Add(T entity);
void Remove(T entity);
}
public class SessionProvider
{
private static Configuration configuration;
private static ISessionFactory sessionFactory;
public static Configuration Configuration
{
get
{
if (configuration == null)
{
configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof(User).Assembly);
}
return configuration;
}
}
public static ISessionFactory SessionFactory
{
get
{
if (sessionFactory == null)
sessionFactory = Configuration.BuildSessionFactory();
return sessionFactory;
}
}
private SessionProvider()
{ }
public static ISession GetSession()
{
return SessionFactory.OpenSession();
}
}
My config:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">Server=.\SqlExpress;Initial Catalog=TestNH;User Id=dev;Password=123</property>
<property name="show_sql">true</property>
</session-factory>
</hibernate-configuration>
I created a console application to test the output:
static void Main(string[] args)
{
Console.WriteLine("starting...");
UserRepository users = new UserRepository();
User user = users.GetById(1);
Console.WriteLine("user is null: " + (null == user));
if(null != user)
Console.WriteLine("User: " + user.Username);
Console.WriteLine("ending...");
Console.ReadLine();
}
Error:
nhibernate says 'mapping exception was unhandled' no persister for: MyNH.Domain.User
What could be the issue, I did do the mapping?
NH says that you don't have the mapping for the User class.
You probably forgot to include that. Try to call this from your SessionProvider configurator:
Fluently.Configure()
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<UserMapping>())
.BuildSessionFactory();

FluentNHibernate - AutoMappings producing incorrect one-to-many column key

I'm new to NHibernate and FNH and am trying to map these simple classes by using FluentNHibernate AutoMappings feature:
public class TVShow : Entity
{
public virtual string Title { get; set;}
public virtual ICollection<Season> Seasons { get; protected set; }
public TVShow()
{
Seasons = new HashedSet<Season>();
}
public virtual void AddSeason(Season season)
{
season.TVShow = this;
Seasons.Add(season);
}
public virtual void RemoveSeason(Season season)
{
if (!Seasons.Contains(season))
{
throw new InvalidOperationException("This TV Show does not contain the given season");
}
season.TVShow = null;
Seasons.Remove(season);
}
}
public class Season : Entity
{
public virtual TVShow TVShow { get; set; }
public virtual int Number { get; set; }
public virtual IList<Episode> Episodes { get; set; }
public Season()
{
Episodes = new List<Episode>();
}
public virtual void AddEpisode(Episode episode)
{
episode.Season = this;
Episodes.Add(episode);
}
public virtual void RemoveEpisode(Episode episode)
{
if (!Episodes.Contains(episode))
{
throw new InvalidOperationException("Episode not found on this season");
}
episode.Season = null;
Episodes.Remove(episode);
}
}
I'm also using a couple of conventions:
public class MyForeignKeyConvention : IReferenceConvention
{
#region IConvention<IManyToOneInspector,IManyToOneInstance> Members
public void Apply(FluentNHibernate.Conventions.Instances.IManyToOneInstance instance)
{
instance.Column("fk_" + instance.Property.Name);
}
#endregion
}
The problem is that FNH is generating the section below for the Seasons property mapping:
<bag name="Seasons">
<key>
<column name="TVShow_Id" />
</key>
<one-to-many class="TVShowsManager.Domain.Season, TVShowsManager.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bag>
The column name above should be fk_TVShow rather than TVShow_Id. If amend the hbm files produced by FNH then the code works.
Does anyone know what it's wrong?
Thanks in advance.
Have you stepped through the auto map in the debugger to make sure your convention is being called?
Assuming you have it wired up correctly you may need to implement the Accept interface for ReferenceConvention