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.
Related
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
I have the entity defined below:
public class Foo : Entity<Foo.FooId>
{
public class FooId
{
public virtual String Bar { get; protected internal set; }
public virtual Int32 Buzz { get; protected internal set; }
}
// ...
}
And here's the base class:
public abstract class Entity<T> : IEquatable<Entity<T>>
{
public virtual T Id { get; protected internal set; }
// ...
}
I'm going to map the "Id" property as a "composite key", so I've added the following mapping class:
public class FooMap : ClassMapping<Foo>
{
public FooMap()
{
ComponentAsId(x => x.Id, m =>
{
m.Property(p => p.Bar);
m.Property(p => p.Buzz);
});
}
}
And that's all pretty nice, but I get an error with the following querying attempt:
session.QueryOver<Foo>()
.Where(m => m.Id.Bar == "a" &&
m.Id.Buzz == 2).List();
The error I get is:
NHibernate.QueryException : could not resolve property: Id of: Foo
It's quite strange, because by removing the base class and encapsulating everything within "Foo", it works like a charm.
Thanks in advance.
This was a bug and reported as NH-3105. It is now fixed in the most recent of the source code and will be released as 3.3.3.GA.
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 am pretty new to S#harp architecture and fluent nhibernate. I was trying to build a sample solution using the template.
MappingIntegrationTest fails for me when I try to run it for the following domains
public class Component
{
public virtual string comp { get; set; }
}
public class Parent : Entity
{
public virtual string Type { get; set; }
}
public class Child1: Parent
{
public virtual Component Blah { get; set }
}
The ParentMap looks like following:
public class ParentMap : IAutoMappingOverride<Parent>
{
public void Override(AutoMapping<Parent> mapping)
{
mapping.DiscriminateSubClassesOnColumn("Type")
.SubClass<Child1>(m =>
{
m.Component(c => c.Blah, c =>
{
c.Map(x => x.comp , "comp");
}
}
}
}
The mapping integration tests fail for me
* Database was not configured through Database method.
----> NHibernate.MappingException : An association from the table Parent refers to an unmapped class: Component
Do I need to remove these classes from AutoMapper?