NH spatial and Fluent Mapping - nhibernate

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.

Related

Fluent Nhibernate Enum Mapping

I have some problem with enum mapping in fluent NHibernate. I know this question has been asked many times but I couldn't find any solution that worked for me. I'm newbie in NHibernate and it looks like I may have missed something simple and stupid. Here is my code.
public class DBPublication
{
public virtual int pub_id { get; set; }
public virtual PublicationStatuses status { get; set; }
...
}
public enum PublicationStatuses
{
on_moderation,
active,
...
}
public class DBPublicationMap : ClassMap<DBPublication>
{
public DBPublicationMap()
{
Table("content.publications");
Id(x => x.pub_id).GeneratedBy.Sequence("content.pub_sq");
Map(x => x.status);
...
}
}
postgres enum type
CREATE TYPE content.enum_publication_status AS ENUM('on_moderation', 'active', ...);
but when I try to save, postgres throws this
column "status" is of type content.enum_publication_status but expression is of type text
any suggestion?
Here is a working sample of configuring nhibernate to store enum field.
public class Entity
{
public virtual int id { get; set; }
public virtual SomeEnum EnumField { get; set; }
}
public enum SomeEnum
{
Value1,
Value2
}
class EntityMap : ClassMap<Entity>
{
public EntityMap()
{
Id(x => x.id).GeneratedBy.Native();
Map(x => x.EnumField);
}
}
class Program
{
static void Main(string[] args)
{
var factory = Fluently.Configure().Mappings(x => x.FluentMappings.AddFromAssemblyOf<Entity>())
.ExposeConfiguration(config => new SchemaExport(config).Create(false, true))
.Database(MsSqlConfiguration.MsSql2008.ConnectionString("Data Source=.;Initial Catalog=nhtest;Integrated Security=True"))
.BuildSessionFactory();
using (var session = factory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var entity = new Entity();
entity.EnumField = SomeEnum.Value2;
session.Save(entity);
transaction.Commit();
}
}
}
}
In such case it is stored as strings in data base. If you want it be saved as integers, you need to change mapping for Enum field property to the following:
Map(x => x.EnumField).CustomType<int>();
Why are you creating enum types in progres? isn't this a maintenance-nightmare?
What does your configuration look like? Have you already tried using the conventions discribed here?
Looks like a simple casting error, so please consider using CustomType() / CustomSQLType() inside your mapping.
Simply add this class to your project:
public class PgEnumMapper<T> : NHibernate.Type.EnumStringType<T>
{
public override NHibernate.SqlTypes.SqlType SqlType
{
get { return new NHibernate.SqlTypes.SqlType(System.Data.DbType.Object); }
}
}
Then, you can use:
Map(x => x.status).CustomType<PgEnumMapper<PublicationStatuses>>();

Why doesn't this class hierarchy fluent mapping work?

What's wrong with my mapping shown below? Is this a problem with GeneratedBy.Foreign()? How should I use it cause my PK in UserTable(UID) is also the FK which refers to PersonTable PK(PID). I get the Duplicate class/entity mapping consoleMappingTest.SystemUser error. what do you suggest(be sure to look at database structure- no way to change it). thanks.
Inheritance structure:
public class Person
{
public virtual int ID { get; set; }
}
public class User:Person
{
public override int ID
{
get
{
return base.ID;
}
set
{
base.ID = value;
}
}
public virtual string Name { get; set; }
public virtual int Salary { get; set; }
}
public class SystemUser:User
{
public virtual int Password { get; set; }
}
Database structure:
for saving some info about person(some fields not shown here):
PersonTable(PID)
for saving User and all it's subclasses like system user:
UserTable(UID,Name,Salary,Type)
and here is my mapping:
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Table("PersonTable");
Id(x => x.ID, "PID").GeneratedBy.Assigned();//or HiLo-not important
}
}
public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("UserTable");
DiscriminateSubClassesOnColumn("Type").Default("U");
Id(x => x.ID, "UID").GeneratedBy.Foreign("Person");//how should use this?
Map(x => x.Salary);
Join("PTable", j =>
{
j.KeyColumn("UID");
j.Map(x => x.Name);
});
}
}
public class SystemUserMap : SubclassMap<SystemUser>
{
public SystemUserMap()
{
DiscriminatorValue("SU");
Map(x => x.Password);
}
}
Foreign("") is meant to point to a Reference (Property with another mapped entity) from which the Id should be retrieved. You don't have a Reference to class Person named Person so you can't use it like this.
you already asked the same question with an answer. I know i didn't do it right first shot but would be nice if you told me what doesnt work with the latest edit or you dont like the solution befor asking the same question again

Fluent Nhibernate 3 Mapping Composite Field (Custom Type)

HI all, my scenario
public class Permission
{
public virtual Function Function { get; set; }
public virtual Profile Profile { get; set; }
}
public class MapPermission : ClassMap<Permission>
{
public MapPermission()
{
Table("Permissions".ToUpper());
CompositeId().KeyProperty(x => x.Function, "FunctionID").KeyProperty(x => x.Profile, "ProfileID");
}
}
Where Function AND Profile are two easy mapped entities. When i Run i have this error:
Could not determine type for: Data.Model.Entities.Function, Data.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null, for columns: NHibernate.Mapping.Column(FunctionID)"}
Is there a way to avoid this? ultimately i need to create a class with CompositeID made by two custom mapped classes. If i uses compositeID with int fields it works like a charm
Thanks in Advance
Function (Like Profile) Mapping
public class Function
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
}
public class MapFunction : ClassMap<Function>
{
public MapFunction()
{
Table("FUNCTIONS");
Id(x => x.ID);
Map(x => x.Name);
}
}
Use KeyReference instead of KeyProperty
public class MapPermission : ClassMap<Permission>
{
public MapPermission()
{
Table("Permissions".ToUpper());
CompositeId()
.KeyReference(x => x.Function, "FunctionID")
.KeyReference(x => x.Profile, "ProfileID");
}
}

Fluent NHibernate? Am I doing this correctly?

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

Fluent NHibernate mapping IDictionary<string, class> in a smart way

Given these classes:
using System.Collections.Generic;
namespace FluentMappingsQuestion
{
public class Entity
{
public virtual int Id { get; set; }
public virtual IDictionary<string, Property> Properties { get; set; }
}
public class Property
{
public virtual Entity OwningEntity { get; set; }
public virtual string Name { get; set; }
public virtual int Value { get; set; }
public virtual decimal OtherValue { get; set; }
}
}
How can I map them using NHibernate (preferably fluent flavor) so that doing this is possible:
[Test]
public void EntityPropertyMappingTest()
{
using (var session = _factory.OpenSession())
{
var entity = new Entity();
// (#1) I would *really* like to use this
entity.Properties["foo"] = new Property { Value = 42, OtherValue = 42.0M };
session.Save(entity);
session.Flush();
// (#2) I would like the entity below to "update itself"
// on .Save or .Flush. I got it to work with .Load()
Assert.AreEqual(42, entity.Properties["foo"].Value);
Assert.AreEqual(42.0M, entity.Properties["foo"].OtherValue);
Assert.AreEqual("foo", entity.Properties["foo"].Name);
Assert.AreEqual(entity, entity.Properties["foo"].Owner);
}
}
I have almost managed to do this with these mappings:
// class EntityMap : ClassMap<Entity>
public EntityMap()
{
Id(x => x.Id);
HasMany(x => x.Properties)
.Cascade.AllDeleteOrphan()
.KeyColumn("EntityId")
.AsMap(x => x.Name);
}
// class PropertyMap : ClassMap<Property>
public PropertyMap()
{
Id(x => x.Id);
References(x => x.OwningEntity).Column("EntityId");
Map(x => x.Name).Length(32);
Map(x => x.Value);
{
The problems I have:
If I make Entity.Properties .Inverse(), it starts breaking
If I don't make it .Inverse() then NHibernate does: INSERT(Entity), INSERT(Property), UPDATE(Property) instead of just INSERT(Entity), INSERT(Property)
If I make Property.Name .Not.Nullable(), it starts breaking
If I don't make it .Not.Nullable(), I have a hole in my db schema
How should I change my mappings?
I worked around this by specifying this mapping:
HasMany<Property>(Reveal.Member<Entity>("InternalProperties"))
.AsMap(p => p.Name)
.Cascade.AllDeleteOrphan()
.Inverse();
and creating two properties of type IDictionary<string, Property>: Properties and InternalProperties. The first one is a proxy dictionary over the second one, and deals with setting the OwningEntity and Name properties for the Property entries.