I am new to using Fluent NHibernate and NHibernate for the first time. I've used a custom written mapper since about 2000 that was written in house. Made a switch to LinqToSQL about 2 years ago, and about 6 months ago to Entities.
I'd like to see what Fluent/NHibernate have to offer. However, I can't seem to get it to run correctly. The following is a copy of my classes, their references, the ClassMaps. Can someone tell me if this simple implementation is correct?
This is my mappings and object classes:
using System;
using FluentNHibernate.Mapping;
namespace MyData.Data.Mappings
{
public class Login
{
public virtual int LoginId { get; private set; }
public virtual string Username { get; set; }
public virtual User User { get; set; }
}
public class LoginClassMap : ClassMap<Login>
{
public LoginClassMap()
{
Table("Logins");
Id(d => d.LoginId).GeneratedBy.Guid();
Map(d => d.Username).Not.Nullable().Length(50);
HasOne(d => d.User).ForeignKey("UserId").Cascade.All();
}
}
public class User
{
public virtual Guid UserId{ get; private set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual Login Login { get; set; }
}
public class UserClassMap : ClassMap<User>
{
public UserClassMap()
{
Table("Users");
Id(d => d.UserId).GeneratedBy.Guid();
Map(d => d.FirstName).Not.Nullable().Length(100);
Map(d => d.LastName).Not.Nullable().Length(100);
References(r => r.Login, "UserId").Not.Nullable();
}
}
}
This is my Repository:
using System;
using System.Linq;
using NHibernate;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate.Linq;
using MyData.Data.Mappings;
namespace MyData.Data.Repository
{
public class LoginRepository
{
private readonly ISessionFactory _sessionFactory;
ISession _session;
public LoginRepository()
{
_sessionFactory = this.CreateSessionFactory();
_session = _sessionFactory.OpenSession();
}
private ISessionFactory CreateSessionFactory()
{
string connString = "MyDataConnectionString";
FluentConfiguration config = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(
x => x.FromConnectionStringWithKey(connString)))
.ExposeConfiguration(
c => c.SetProperty("current_session_context_class", "webContext"))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Login>());
return config.BuildSessionFactory();
}
public IQueryable<Login> GetAllLogins()
{
return _session.Linq<Login>();
}
}
}
Whenever it gets to config.BuildSessionFactory() it throws the following error:
An invalid or incomplete configuration was used while creating a SessionFactory.
The inner Exception is:
Exception has been thrown by the target of an invocation.
Is this the correct way to approach this? Any ideas or tweaks would be greatly appreciated!
Sean, you cannot use GeneratedBy.Guid() on LoginId because it's an int. Try to use another generator or change the type of LoginId.
I suspect you cannot use "private set" on UserId because it's the Id.
Also, HasOne(d => d.User).ForeignKey("UserId") means that if you expose your database model from your mappings, the name of the FK constraint will be "UserId". It seems to me that your intention was to specify the name column that holds the PK on table "Users".
These links have more infos:
http://wiki.fluentnhibernate.org/Fluent_mapping
http://jagregory.com/writings/i-think-you-mean-a-many-to-one-sir/
one-to-one fluent nhibernate?
It seems you forgot to specify proxy factory. It can be done like this:
OracleDataClientConfiguration persistenceConfigurer = OracleDataClientConfiguration
.Oracle10
.ConnectionString(connectionStringBuilder => connectionStringBuilder.FromAppSetting("Main.ConnectionString"))
.ProxyFactoryFactory<ProxyFactoryFactory>()
.CurrentSessionContext<ThreadStaticSessionContext>()
.AdoNetBatchSize(25)
.DoNot.ShowSql();
FluentConfiguration cfg = Fluently.Configure()
.Database(persistenceConfigurer)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<UserMap>());
return cfg.BuildConfiguration();
Related
I am new to NHibernate and am facing some issues with Fluent NHibernate automap.
I am using Nhibernate 3.3.3.400, Fluent Nhibernate 1.3.0.733 Automapper 2.2.1
I have a column in Database which is of type Xml. When I try to create a ma mapping column it give me the following error.
An association from the table Product refers to an unmapped class: System.Xml.XmlDocument
Following is the code I am trying to implement.
using System.Collections.Generic;
using System.Xml;
//using System.Xml.Linq;
namespace Examples.FirstAutomappedProject.Entities
{
public class Product
{
public virtual int Id { get; protected set; }
public virtual string Name { get; set; }
public virtual double Price { get; set; }
public virtual Location Location { get; set; }
public virtual IList<Store> StoresStockedIn { get; set; }
public virtual XmlDocument SalesRange { get; set; }
public Product()
{
StoresStockedIn = new List<Store>();
}
}
}
I have been struggling for a couple of days now anhy help or samples would be greatly appreciated.
it seems it FNH will not map it on it's own. you'll need a Override there
Map(x => x.SalesRange).CustomType<NHibernate.Type.XmlDocType>();
Since Firo has sent his answer in comment I am answering it on his behalf.
basically here is what I ended up doing.
I created an override class as follows
using FluentNHibernate.Automapping;
using FluentNHibernate.Automapping.Alterations;
using Examples.FirstAutomappedProject.Entities;
using NHibernate.Mapping;
using NHibernate.Type;
namespace Examples.FirstAutomappedProject.Overrides
{
public class OrderQueueOverride : IAutoMappingOverride<Product>
{
public void Override(AutoMapping<Product> mapping)
{
mapping.Map(x => x.SalesRange).CustomType<XmlDocType>();
}
}
}
So the auto mapper will pick this override and map the column accodingly.
I'm using fluent nhibernate, I would turn on delete cascade. but I do not work. it only deletes the foregin key.
The following configuration fluent nhibernate:
public virtual void TreatConfiguration(NHibernate.Cfg.Configuration configuration)
{
var update = new SchemaUpdate(configuration);
update.Execute(false, true);
}
public ISessionFactory CreateSessionFactory(string istanza, string db)
{
//string server = #"BRUX-PC\SQLEXPRESS";
//int port = 1433;
string server = istanza;
string database = db;
const string user = "xxxx";
const string password = "xxxx";
var connectionString = string.Format("Server={0};Database={1};User Id={2};Password={3};",
server, database, user, password);
var autoMap = AutoMap.AssemblyOf<AggregateBase>()
.Where(t => typeof (AggregateBase).IsAssignableFrom(t))
.Conventions.Add(
ConventionBuilder.HasMany.Always(x => x.Cascade.AllDeleteOrphan()),
PrimaryKey.Name.Is(o => "Id"),
ForeignKey.EndsWith("Id"),
DefaultLazy.Never(),
DefaultCascade.All(),
DynamicUpdate.AlwaysTrue(),
DynamicInsert.AlwaysTrue()
);
return Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2008.ConnectionString(connectionString))
.Mappings(m => m.AutoMappings.Add(autoMap))
.ExposeConfiguration(TreatConfiguration)
.BuildSessionFactory();
}
my controller :
contabilitaRepository.RemoveByIdFattura(testataContabilita.IdFattura);
my repository:
public void RemoveByIdFattura(Guid? id)
{
var userToDelete =
repository.Single(c => c.IdFattura == id);
repository
.Remove(userToDelete);
}
my model:
public class TestataContabilita : AggregateBase
{
public virtual Guid IdFattura
{
get;
set;
}
public virtual int NumeroRegistrazione
{
get;
set;
}
public virtual string TipoVendita
{
get;
set;
}
public virtual IList<CorpoContabilita> CorpoContabilita { get; set; }
}
public class CorpoContabilita : AggregateBase
{
public virtual int NumeroRegistrazione
{
get;
set;
}
public virtual int? ControPartita
{
get;
set;
}
public virtual string Automatico
{
get;
set;
}
}
when I run the elimination, I only deletes "TestataContabilita" while the "CorpoContabilita" remains, but only deletes the foregin key. why?
You may have to do
ConventionBuilder.HasMany.Always(x => x.Cascade.AllDeleteOrphan().Inverse()
in the mapping
Also you have to do
TestataContabilita.CorpoContabilita.Clear();
to remove the items from the collection.
I've tried to reproduce your case. I implemented some kind of a repository and your mapping works just it supposed to. Deletes testataContabilita object with collection of CorpoContabilita.
But I accidentally made a several mistakes in a repository at first - and got null in foreign keys too. In fact they were null even before deleting testataContabilita - due to errors in implementation.
So, what repository implementation do you use? How do you work with Session and Transaction objects? On what object you perform Save? May be you can upload your project somewhere with full implementation.
I have read this in order to compile NH spatial for Nhibernate 3.1
http://build-failed.blogspot.it/2012/02/nhibernate-spatial-part-2.html
I have also read this
NHibernate.Spatial and Sql 2008 Geography type - How to configure
but the same code for me don't compile... I have this
using NetTopologySuite.Geometries;
namespace Core
{
public class District
{
public virtual int Id { get; set; }
public virtual Polygon Area { get; set; }
public virtual string Name { get; set; }
}
}
using Core;
using FluentNHibernate.Mapping;
namespace TestNHSpatial
{
public class DistrictMap : ClassMap<District>
{
public DistrictMap()
{
ImportType<NetTopologySuite.Geometries.Point>();
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.Area).CustomType<Wgs84GeographyType>();
}
}
}
and this
[Serializable]
public class Wgs84GeographyType : MsSql2008GeographyType
{
protected override void SetDefaultSRID(GeoAPI.Geometries.IGeometry geometry)
{
geometry.SRID = 4326;
}
}
finally
var cfg = new OrderingSystemConfiguration();
var configuration = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(connString)
.Dialect<MsSql2008GeographyDialect>())
.Mappings(m => m.AutoMappings.Add(
AutoMap.AssemblyOf<District>(cfg)))
.BuildConfiguration();
var exporter = new SchemaExport(configuration);
exporter.Drop(false, true);
exporter.Create(true, true);
i have this error...
NHibernate.MappingException : An association from the table District refers to an unmapped class: NetTopologySuite.Geometries.Polygon
can anyone help me?
thanks
UPDATE:
The code has some issues, namely:
You're using AutoMappings. You need to use custom mappings
You're using the wrong assembly when searching for the mappings
The export schema code is incorrect.
I'm the author of the blog post that you refer.
Change the type from Polygon (from NetTopologySuite) to IPolygon(from GeoAPI).
Should be something like this:
using GeoAPI.Geometries;
public class District
{
public virtual int Id { get; set; }
public virtual IPolygon Area { get; set; }
public virtual string Name { get; set; }
}
Anyway, if this doesn't work, send me a zip with a test project and I'll check it out.
i have written a code like this
public class person
{
public person()
{
public virtual int Id { get; set; }
public virtual string Code { get; set; }
}
}
public class Child : Person
{
public person()
{
public virtual string Name{ get; set; }
public virtual string Lastname{ get; set; }
}
}
public class Book
{
public virtual int Id { get; set; }
public virtual string Name {get;set;}
}
and my Mapper classes is like these
public class PersonMapping : ClassMap<Person>
{
public PersonMapping()
{
Table("tblPersons");
Id(x => x.Id).GeneratedBy.Native();
Map(p => p.Code);
JoinedSubClass<Child>("Id", MapChild);
}
public static void MapChild(JoinedSubClassPart<Child> child)
{
child.Table("tblChilds");
child.Map(p => p.Name);
child.Map(p => p.Lastname);
child.HasMany(x => x.Relatives);
}
}
public class RelativeMapping : ClassMap<Relative>
{
public RelativeMapping()
{
Table("tblRelatives");
Id(x => x.Id);
Map(p => p.Name);
References(x => x.Child).Column("ChildId");
}
}
this is Configuration
Assembly assm = Assembly.Load("BLL");
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(c => c
.FromAppSetting("ConnStr"))
.Cache(c => c
.UseQueryCache()
.ProviderClass<HashtableCacheProvider>())
.ShowSql())
.Mappings(m => m.FluentMappings.AddFromAssembly(assm))
.BuildSessionFactory();
and this is the code of delete
public void Delete<T>(T obj)
{
ISessionFactory fact = FluentConfiguration.CreateSessionFactory();
ISession session = fact.OpenSession();
session.Delete(obj);
session.Flush();
}
my problem : when i wanna delete a Child it messages
" ILLEGAL ATTEMPT TO ASSOCIATE WITH TWO OPEN SESSION "
please help me
The error tells you the problem, and it is not with your entities or your mapping.
You have two or more open sessions and you're attempting to associate some entity with more than one of them.
update
In response to the updated code, I see that you have a method that accepts an entity as a parameter, creates a new session factory, creates a new session, and then tries to delete the entity.
There are some problems here:
You should only create the session factory once. Ever. This is an expensive operation.
You are passing the entity to the Delete() method. Where is this entity coming from? You've clearly already loaded it elsewhere in your application, using a different ISession. This is the crux of the problem. Unless you Evict() the entity from the first ISession (not recommended), trying to manipulate it with a different ISession will throw.
You're calling Flush() which should almost never be used.
You're using an implicit transaction.
You should really be deleting the entity with the same ISession with which it was loaded, and you should be performing work within a transaction, like this:
using(var transaction = session.BeginTransaction())
{
session.Delete(obj);
transaction.Commit();
}
I am trying to learn Nhibernate using fluent nhibernate mappings and i have created a small test app. Below is the code:
UserClass:
public class User
{
public string UserName { get; set; }
public string Password { get; set; }
public string Role { get; set; }
public string Email { get; set; }
public DateTime JoinDate { get; set; }
}
User Map Class:
public class UserMapping: ClassMap<User>
{
public UserMapping()
{
WithTable("UserT");
Not.LazyLoad();
Id(u => u.UserName);
Map(u => u.Password);
Map(u => u.Role);
Map(u => u.Email);
Map(u => u.JoinDate);
}
}
DAL User Class:
public class DALUser
{
public User GetUserByUserName(string userName)
{
ISessionFactory sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(c => c.Server("ServerName").Database("DBName").TrustedConnection()))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<UserMapping>()).BuildSessionFactory();
ISession session = sessionFactory.OpenSession();
return session.Get<User>(userName);
}
}
Nunit Test Class:
[TestFixture]
public class UserTest
{
[Test]
public void CanGetUserByUserName()
{
DALUser user1 = new DALUser();
Assert.AreEqual("testUser", user1.GetUserByUserName("testUser").UserName);
}
}
When i try to run the test class i get the following error :Object reference not set to an instance of an object.
I have placed a breakpoint in the GetUserByUserName method and noticed that its returning a null user. But i am not able to figure out why this is happening. Can anyone help me?
Take a look is your database configuration correct?
Are you sure that you database server is "ServerName"
and you have existing Database "DBName"