I want to combine table-per-class and table-per-hierarchy strategies using fluent nhibernate or nhibernate itself(I mean hbm files), but I don't know how. I prefer fluent over hbm but if it's impossible, then hbm is also fine. I tested this by introducing Entity as ClassMap and all other as SubClassMap in fluent but then in hbm files generated by fluent, Entity was a class and all other were joined-classes which is not what I want. I will describe the problem in more detail below.
Class hierarchy:
public class Entity
{
public int ID { get; set; }
public string Name { get; set; }
}
public abstract class Person : Entity
{
public string Phone { get; set; }
}
public class SystemUser : Person
{
public string Password { get; set; }
}
I want to have one table for entity and one for person and all kinds of it(all its subclasses).I mean I want to use table-per-class strategy for Entity and table-per-hierarchy strategy for Person and SystemUser classes. Database structure is something like this:
EntityTable(ID(PK),Name)
PersonTable(EntityID(PK,FK),Phone,Password)
any help appreciated.
if EntityTable Id is not database generated (which is discouraged by NH anyways) you can use the trick
public PersonMap : ClassMap<Person>
{
public PersonMap()
{
Table("PersonTable");
Id(p => p.Id, "EntityID").GeneratedBy.HiLo("100");
DiscriminateSubClassesOnColumn("PersonType");
Map(x => x.Phone);
Join("EntityTable", join =>
{
join.KeyColumn("ID");
join.Map(p => p.Name);
});
}
}
public SystemUserMap : SubclassMap<SystemUser>
{
public SystemUserMap()
{
Map(x => x.Password);
}
}
Related
With FluentNHibernate I mapped a collection of interface by specifying the concrete type in the mapping class. I'm trying to convert to Maping.ByCode.
Entity classes:
public class Parent Entity
{
public virtual Guid Id{get;set;}
public virtual IList<IChildEntity> Children{get;set;}
}
public class ChilEntity:IChildEntity
{
public virtual Guid Id{get;set;}
}
With FluentNHibernate:
public class ParentEntityMap:ClassMap<ParentEntity>
{
public ParentEntityMap()
{
Table("ParentEntity");
Id(x => x.Id);
HasMany<ChildEntity>(x=>x.Children)
.KeyColumn("Parent");
}
}
With Mapping ByCode:
public class ParentEntityMap:ClassMapping<ParentEntity>
{
Public ParentEntityMap()
{
Table("ParentEntity");
Id(x=>x.Id);
Bag<ChildEntity>(x=>(IList<ChildEntity>)x.Children,
m=>m.Key(k=>k.Column("Parent")),
ce=>ce.OneToMany()
);
The mapping ByCode doesn't work. Is there a way to achieve what is done with Fluent NHibernate?
Try setting Class:
Bag(x=>x.Children,
m=> m.Key(k=>k.Column("Parent")),
ce=> ce.OneToMany(m => m.Class(typeof(ChildEntity)))
);
I have a table called openTickets. I have another table called openTicketFollowers that relates to it using a foreign key. OpenTickets does not know about openTicketFollowers but I want openTickets to have a property that is a list of its followers. Is there anyway to do this with fluent nhibernate?
Check this Fluent mapping document. The OpenTicket class will contain IList of Followers:
public class OpenTicket
{
...
public virtual IList<OpenTicketFollower> Followers { get; set; }
}
public class OpenTicketFollowers
{
public virtual OpenTicket OpenTicket { get; set; }
}
And this is fluent mapping of the OpenTicketFollowercollection:
HasMany(x => x.Followers)
.KeyColumn("OpenTicketId");
and the OpenTicketFollower class mapping referencing the OpenTicket
References(x => x.OpenTicket)
.Column("OpenTicketId")
After reading some of the articles about Fluent NHibernate I got confused from where to start
I have an existing database to which I need to create DataAccessLayer. I am new to NHibernate and FluentNhibernate. Since I understood that there is no need to write hbm.xml files, I picked Fluent Nhibernate.
So, What is FluentMapping? and AutoMapping?
I have created a classLibraryProject named FirstProject.Entities
I have created a class named "Customer"
namespace FirstProject.Entities
{
public class Customer
{
public virtual int CustomerID { get; set; }
public virtual string CustomerName { get; set; }
public virtual string Address1 { get; set; }
public virtual string Address2 { get; set; }
public virtual string City { get; set; }
public virtual string State { get; set; }
public virtual int Zip { get; set; }
}
}
Then I created a Mapping class
namespace FirstProject.Entities
{
public class CusotmerMap : ClassMap<Customer>
{
public CustomerMap()
{
Id(x => x.CustomerID).Column("CustomerID").GeneratedBy.Assigned();
Map(x => x.CustomerName);
Map(x => x.Address1);
Map(x => x.Address2);
Map(x => x.City);
Map(x => x.Zip);
}
}
}
I now don't know how to proceed further. Am I doing it right.. please suggest
how to configure and proceed further
The following is Fluent
Id(x => x.CustomerID).Column("CustomerID").GeneratedBy.Assigned();
I use Fluent assertions, like the following
actual.Should().BeGreaterThan(1).And().LessThan(2);
Fluent is basically where you chain together the commands such that it reads quite well.
Auto mapping is where you do nothing. Everything is done by conventions. I tend to use Auto. Fluent is nice if you don't follow conventions.
Based on your mapping, the CustomerId being Assigned is not the out-of-the-box convention. As such you need to either
Use Fluent to specify exactly how it should map. This is just like doing it the standard way in XML, but with a fluent interface.
Use Auto and specify a Convention that will automatically change CustomerId to be Assigned.
Use Auto and specify an Override, that will use Auto but override CustomerId to be Assigned.
If you want to do option 3, here is the code:
var model = AutoMap
.AssemblyOf<Customer>()
.Where(IsMapped)
.Override<Customer>(a => a.Id(b => b.CustomerId, "CustomerId").GeneratedBy.Assigned());
The function IsMapped must return True for entities you want to Map.
I'm doing a very basic thing with Fluent NHibernate. I found a lot of people with similar problems here in SO but none seemed to fix my problem.
I have 1 Class like:
public abstract class ParentClass
{
public virtual long Id { get; private set; }
public virtual DateTime CreateDate { get; set; }
public virtual int Type { get; set; }
}
And 1 Concrete classes like:
public class ChildClass : ParentClass
{
public virtual string PropertyX { get; set; }
public virtual int PropertyY{ get; set; }
}
So I made the mapping as follows:
public class ParentMap : ClassMap<ParentClass>
{
public ParentMap()
{
Id(x => x.Id);
Map(x => x.CreateDate);
DiscriminateSubClassesOnColumn("Type");
}
}
And
public class ChildMap : SubclassMap<ChildClass>
{
public ChildMap()
{
Extends<ParentClass>();
DiscriminatorValue(1);
Map(x => x.PropertyX);
Map(x => x.PropertyY);
}
}
My legacy database has 2 tables, 1 that holds all the data from the ParentClass and another one that holds the data from the Child with a foreign key in the ID.
The idea is to have different tables for each different implementation of the ParentClass but having the ParentClass table as a single repository for "Ids" and "Create Dates".
I'm creating my SessionFactory as follows:
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlCeConfiguration.Standard.ConnectionString(cstr => cstr.FromConnectionStringWithKey("TheConnectionString")))
.Mappings(mappings => mappings.FluentMappings.AddFromAssemblyOf<ParentClass>()
.ExportTo(#"c:\temp\Mappings"))
.BuildSessionFactory();
}
I'm doing just a basic test of storing things to the database as:
public void Store(ParentClass parent)
{
using (var session = sessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(parent);
transaction.Commit();
}
}
}
But despite the method waits for a ParentClass variable, I'm passing a ChildClass instance for it (the method is actually a inheritance of an interface, that's why it expects a ParentClass).
And every time I it raises an error on "SaveOrUpdate" method saying "No persister for: ChildClass".
What am I doing wrong?
ps.: Another strange thing is that even with the "ExportTo" method on the SessionFactory creation, no mapping is being write on the folder.
Change
.Mappings(mappings => mappings.FluentMappings.AddFromAssemblyOf<ParentClass>()
To
.Mappings(mappings => mappings.FluentMappings.AddFromAssemblyOf<ParentMap>()
I have an abstract base class, Entity, that all my POCOs derive from:
public abstract class Entity
{
public virtual Guid Id { get; set; }
}
And the mapping file:
public class EntityMap<T> : ClassMap<T> where T : Entity
{
public EntityMap
{
Id(x => x.Id);
}
}
This way, I don't have to write Id(x => x.Id) in every mapping file by using this:
public class Something : EntityMap<T>
{
blahblah
}
I'm auto-generating my database schema, and everything looks fine, except that the Entity base class is added as a table. Using fluent mappings, how do I configure it so that the Entity class is excluded from the database schema?
You can add it to the ignore list of auto mapper:
AutoMap.AssemblyOf<Entity>()
.IgnoreBase(typeof(Entity));