I have two classes:
class User {
public int Id { get;set; }
public string Name { get; set; }
}
class VerifiedUser : User {
public ICollection<Verified> { get; set; }
}
I would like NHibernate to treat VerifiedUser and User as the same table but keep them separate to, so.
Session.Query<User>() //would return a User
Session.Query<VerifiedUser>() //would return a VerifiedUser
Is this possible or is it unsupported?
You will need to implement the table-per-hierarchy strategy with Fluent Nhiberate in mapping classes. These are like overrides for the AutoMapping feature (if used) of FNH, otherwise mapping classes are de facto and you will be used to them.
Something like:
public class UserMappingOverride : IAutoMappingOverride<User>
{
public void Override(AutoMapping<User> mapping)
{
mapping.DiscriminateSubClassesOnColumn("IsVerified").Not.Nullable();
}
}
public class VerifiedUserClassMap : SubclassMap<VerfiedUser>
{
public VerifiedUserClassMap()
{
DiscriminatorValue("Yes");
}
}
And to answer your question, yes as far as I remember nothing to do here: Session.QueryOver<VerifiedUser>() as NHibernate will add on the where clause for the discriminator
Related
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);
}
}
I have a class that is many-to-one with its parent. I'd like to expose the parent's properties through the child without exposing the parent directly. I'd also like to query on and order by those properties.
Classes
public class Organization
{
public virtual string Name { get; set; }
public virtual bool IsNonProfit { get; set; }
}
public class Contact
{
private Organization _organization;
public virtual string OrganizationName
{ get { return _organization.Name; } }
public virtual bool OrganizationIsNonProfit
{ get { return _organization.IsNonProfit; } }
}
Mapping
public class OrganizationMap : ClassMap<Organization>
{
public OrganizationMap()
{
Map(x => x.Name);
Map(x => x.IsNonProfit);
}
}
public class ContactMap : ClassMap<Contact>
{
public ContactMap()
{
References<Organization>(Reveal.Member<Contact>("_organization"))
.Access.CamelCaseField();
}
}
Query
public class Example
{
private ISessionFactory _sessionFactory;
public Example(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
}
public IEnumerable<Contact> DoQuery(int forPage, int rowsPerPage)
{
using (var session = _sessionFactory.OpenSession())
{
return session.Query<Contact>().OrderBy(x => x.OrganizationName)
.Skip((forPage - 1) * rowsPerPage).Take(rowsPerPage);
}
}
}
The problem is that this results in a "Could not resolve property: OrganizationName" error. It looks like I could map those fields with a formula, but then I'd end up with a sub-select for each field on a table that's already joined into my query. Alternatively, I could wrap the Contact's organization with a public getter and change my query to OrderBy(x => x.Organization.Name). That leaves me with a Law of Demeter violation though.
Am I off track? How should I handle this?
edited to show paging
You can't use non-mapped properties in queries. How should NHibernate know how to create a SQL condition for it? In your case it might be easy, but what if you'd have a call to a method or some complicated logic in that property?
So yes, you need at least a public getter property.
Alternatively, do the sorting in memory (after NHibernate has executed the query).
How should the following mapping configuration be solved?
public abstract class RepositoryEntity
{
public virtual int Id { get; set; }
}
public class Descriptor : RepositoryEntity
{
public virtual String Name { get; set; }
public virtual DateTime Timestamp { get; set; }
}
public class Proxy<TDescriptor> : RepositoryEntity
{
public virtual TDescriptor Descriptor { get; set; }
public virtual Byte[] SerializedValue { get; set; }
};
public class TestUnit : Proxy<Descriptor>
{
};
I receive problems when testing the TestUnit mapping - it says it's impossible to map the item with generic parameters. This happens if I attempt to map every class from the specified before.
If I attempt to map everything, except Proxy<T>, then I receive that there is no persister for the 'TestUnit'.
If I stop inheriting TestUnit from Proxy<Descriptor>, the mapping test works fine.
Does Fluent NHibernate have possibility to automap types inherited from some concrete Class<T> template? Could you help me with mapping these entities?
I used a combination of Fluent and Auto mappings.
Fluent mappings should be used for generics.
Configuration = Fluently.Configure()
.Database(SQLiteConfiguration.Standard.ShowSql().InMemory)
.Mappings(x =>
{
x.FluentMappings.AddFromAssemblyOf<RepositoryEntity>();
x.AutoMappings.Add(autoPersistenceModel);
});
I have an abstract class and subclasses of this, and I want to map this to my database using NHibernate. I'm using Fluent and how to do the mapping. But when I add the mapping of the subclass an NHibernate.DuplicateMappingException is thrown when it is mapping. Why?
Here are my (simplified) classes:
public abstract class FieldValue
{
public int Id { get; set; }
public abstract object Value { get; set; }
}
public class StringFieldValue : FieldValue
{
public string ValueAsString { get; set; }
public override object Value
{
get
{
return ValueAsString;
}
set
{
ValueAsString = (string)value;
}
}
}
And the mappings:
public class FieldValueMapping : ClassMap<FieldValue>
{
public FieldValueMapping()
{
Id(m => m.Id).GeneratedBy.HiLo("1");
// DiscriminateSubClassesOnColumn("type");
}
}
public class StringValueMapping : SubclassMap<StringFieldValue>
{
public StringValueMapping()
{
Map(m => m.ValueAsString).Length(100);
}
}
And the exception:
> NHibernate.MappingException : Could not compile the mapping document: (XmlDocument)
----> NHibernate.DuplicateMappingException : Duplicate class/entity mapping NamespacePath.StringFieldValue
Any ideas?
Discovered the problem. It turned out that I did reference the same Assembly several times in the PersistenceModel used to configure the database:
public class MappingsPersistenceModel : PersistenceModel
{
public MappingsPersistenceModel()
{
AddMappingsFromAssembly(typeof(FooMapping).Assembly);
AddMappingsFromAssembly(typeof(BarMapping).Assembly);
// Where FooMapping and BarMapping is in the same Assembly.
}
}
Apparently this is not a problem for ClassMap-mappings. But for SubclassMap it doesn't handle it as well, causing duplicate mappings - and hence the DuplicateMappingException. Removing the duplicates in the PersistenceModel fixes the problem.
If you are using automappings together with explicit mappings then fluent can generate two mappings for the same class.
I'm in the process of adapting Fluent NHibernate to our existing legacy app and am trying to determine how to use ClassMap and SubclassMap for the entity hierarchy shown.
// BaseObject contains database columns common to every table
public class BaseObject
{
// does NOT contain database id column
public string CommonDbCol1 { get; set; }
public string CommonDbCol2 { get; set; }
// ...
}
public class Entity1 : BaseObject
{
public int Entity1Id { get; set; }
// other Entity1 properties
}
public class Entity2 : BaseObject
{
public int Entity2Id { get; set; }
// other Entity2 properties
}
The identity columns for Entity1 and Entity2 are uniquely named per table. BaseObject contains columns that are common to all of our entities. I am not using AutoMapping, and thought I could use ClassMap on the BaseObject, and then use SubclassMap on each Entity like this:
public class Entity1Map : SubclassMap<Entity1>
{
public Entity1Map()
{
Id(x => x.Entity1Id);
// ...
}
}
Problem is, Id() is not defined for SubclassMap. So, how do I specify within each Entity1Map, Entity2Map, ... (we have 100+ entity classes all inheriting from BaseObject) what the entity-specific Id is?
Thanks in advance for any insight!
It's not possible to do that in either Fluent NHibernate or NHibernate. Do you actualy want your classes to be mapped as subclasses, or do you just want them to share the common mappings? If you truly want subclasses, then you're going to need to have them share the identity column, no other way around it; if you don't want actual subclasses, create an abstract ClassMap<T> where T : BaseObject and map the common properties in there.
Something like:
public abstract class BaseObjectMap<T> : ClassMap<T> where T : BaseObject
{
public BaseObjectMap()
{
Map(x => x.CommonProperty1);
}
}