I'm having problems developing a sane set of Fluent NHibernate mappings for the following model structure:
public class BaseLookup
{
public virtual int Id {get; set;}
public virtual string Code {get; set;}
public virtual string Value {get; set;}
public virtual bool Active {get; set;}
}
public class Subdivision : BaseLookup { }
public class AvisCode : BaseLookup { }
public class District : BaseLookup { }
/*etc.*/
These lookups all share properties, but otherwise have no relationship to each other. These tables have special semantic meanings for reports and will be referenced specifically in stored procedures, so I don't wish to mash them into a common 'lookups' table that would require me to use a discriminator. That seems to eliminate Table-per-Hierarchy and Table-per-Sublass strategies in my mappings. I'm also having difficulty employing Table-per-Concrete-Class because each lookup has its own identity column - I do not want to have to assign an Id manually in the application, and there's no requirement for Id's to be unique across all these tables.
My mappings, at the moment, look like this, and are identical for each superclass of BaseLookup:
public class AvisCodeMap : ClassMap<AvisCode>
{
public AvisCodeMap()
{
Schema(Schemas.pva.ToString());
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Code).Not.Nullable();
Map(x => x.Value).Not.Nullable();
}
}
Is there no mapping convention that allows me to extract the repetitive mappings to a block of re-usable code?
If I understand your question right, you might need to create a generic base class map then reuse it in derived maps.
Example as follows:
public class BaseLookupMap<T> : ClassMap<T> where T : BaseLookup
{
public BaseLookupMap()
{
// ... base mapping code goes here ...
}
}
To create that base type:
public class BaseLookupMap : BaseLookupMap<BaseLookup>
{
}
And the derived class map:
public class AvisCodeMap : BaseLookupMap<AvisCode>
{
public AvisCodeMap()
{
Polymorphism.Explicit();
// ... your other mappings here, if needed ...
}
}
HTH.
Related
I have something like the classes below, I'd like to map Foo to a single table with two columns, Id and State with values like 1, "BigState" and 2, "LittleState" but I'm really struggling to find examples of maps for this.
public class Foo
{
public int Id { get; set; }
public State State { get; set; }
}
public abstract class State
{
}
public class BigState : State
{
}
public class LittleState : State
{
}
https://nhibernate.info/doc/nhibernate-reference/inheritance.html
You are interested in table per class hierarchy strategy. Your second column would be discriminator column. When you are using FluentNhibernate you can derive from DefaultAutomappingConfiguration and override methods AbstractClassIsLayerSupertype, IsDiscriminated, GetDiscriminatorColumn. You also need to implement IClassConvention and ISubclassConvention to provide class name as discriminator value, something like that.
public class SubclassConvention : ISubclassConvention
{
public void Apply(ISubclassInstance instance)
{
instance.DiscriminatorValue(instance.EntityType.Name);
}
}
I have two class BookingInfo.cs and BookingTransaction class.
public class BookingInfo
{
public virtual string Code { get; set; }
}
public class BookingTransaction : BookingInfo {
public virtual string CustomerRefNo { get; set; }
}
below is the NHibernate mapping for both classes
public class BookingInfoConfiguration : ClassMap<BookingInfo> {
public BookingInfoConfiguration() {
Table("Bkg_BookingInfo");
LazyLoad();
DynamicUpdate();
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty);
}
}
public class BookingTransactionConfiguration :
ClassMap<BookingTransaction> {
public BookingTransactionConfiguration() {
Table("Bkg_BookingInfo");
LazyLoad();
DynamicUpdate();
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty);
}
}
Now i am querying to get rows from database.
CurrentSession.Query<BookingInfo>().ToList();
I get two items for single row in database table. one for Bookinginfo and another for BookingTransaction. but i want to get only result of type Bookinginfo.
How to remove the items of the child class from the result?
As said in Rabban's answer, this is by design. This is called implicit polymorphism. Rabban propose you to change your class hierarchies, but you can instead disable implicit polymorphism if you prefer.
With hbm mappings (I do not use fluent and do not know it), add the attribute polymorphism="explicit" on your class.
Mapping by code supports it too on class mapper with .Polymorphism(PolymorphismType.Explicit).
You can read more about implicit/explicit polymorphism here:
Implicit polymorphism means that instances of the class will be
returned by a query that names any superclass or implemented interface
or the class and that instances of any subclass of the class will be
returned by a query that names the class itself. Explicit polymorphism
means that class instances will be returned only be queries that
explicitly name that class and that queries that name the class will
return only instances of subclasses mapped inside this <class>
declaration as a <subclass> or <joined-subclass>. For most purposes
the default, polymorphism="implicit", is appropriate. Explicit
polymorphism is useful when two different classes are mapped to the
same table (this allows a "lightweight" class that contains a subset
of the table columns).
Its intended that NHibernate returns you both objects. To prevent this behavior create a abstract base class where both other class derive. Then you don't need to duplicate code and you can query each class separately.
Create the base class:
public abstract class BookingBase
{
public virtual string Code { get; set; }
}
and then derive your classes from it:
public class BookingInfo : BookingBase
{
}
public class BookingTransaction : BookingBase
{
public virtual string CustomerRefNo { get; set; }
}
Your mappings and queries can remain the same. And if you want to query both classes with one query, just query BookingBase.
I am trying to control how Entity Framework 6 maps my class hierarchy into tables so that the properties in an abstract class in the middle of my hierarchy is mapped to the descendant types, not to its base class.
My class hierarchy is quite simple:
public abstract class BaseType
{
public int Id { get; set; }
public DateTime DateField { get; set; }
}
public abstract class DerivedAbstract : BaseType
{
public string MapToChild { get; set; }
}
public class Concrete1 : DerivedAbstract
{
public int Age { get; set; }
}
public class Concrete2 : DerivedAbstract
{
public string Name { get; set; }
}
I have setup a simple table-per-type hierarchy:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<BaseType>();
modelBuilder.Entity<Concrete1>().ToTable("Concrete1");
modelBuilder.Entity<Concrete2>().ToTable("Concrete2");
}
And this gives me three tables: BaseTypes, Concrete1 and Concrete2. So far I am very happy, but my challenge is that the field MapToChild defined in the DerivedAbstract class is mapped down to the BaseTypes table instead of to both of the Concrete1 and Concrete2 tables.
This makes sense in most cases, but not in the project I am working on. So I am looking for a way to tell Entity Framework that I want the property to be mapped to the two tables Concrete1 and Concrete2 instead.
So far I have been unable to find a way to do this. Does Entity Framework even support it?
This is happening because you are telling it to map BaseType. So it is creating base type as a TPH mapping and adding a discriminator.
If you remove the BaseType mapping you will get a Table for concrete1 and a table for concrete2 which I think it was you want. Right?
Ah... sorry, probably what you want. I can't map your classes so that BaseType is a table and have the MapToChild be in each concrete type. I assume you are doing this so you can query BaseType and get back multiple child types.
So, never mind.
Lets say I have two classes:
public class A
{
public virtual int Id { get; set; }
public virtual Object1 Obj { get; set; }
}
public class B : A
{
public new virtual Object2 Obj { get; set; }
}
I use Fluent NHibernate and I have created two different mappings for the two classes. However, when I try to query class A in my repository, FNH finds both class B and A, which kind of makes sense since both are A.
Example (this criteria will query over both A and B):
public List<T> GetByName(string name)
{
return Session.CreateCriteriaOf<A>.Add(Restrictions...);
}
When writing CreateCriteriaOf<A>, I only want to query over A - not B. How can I solve my problem?
I think you better make an inheritance tree where both A and B derive from a common (abstract) base type. Then NHibernate can make the distinction by a discriminator column.
Of course, your data model should accommodate this, so I hope your model is not prescribed in any way.
Is there a way to generate mappings for NHibernate from POCO? This reply to my question makes NHibernate look very interesting. However i have a lot of classes that look like this
public class register_email_job
{
public PK id;
public user_data user;
}
public class user_comment : BaseComment2
{
[IsNullable]
public user_comment parent;
public user_data user;
}
I would like to easily translate this into something compatible with NHibernate. I wouldnbt mind modifying some queries but i prefer not to rewrite each class to use properties and modify class in such a way i need to change how its used everywhere.
-edit- Note that i use inheritance and user_comment has an object to user_comment (thus why it must be nullable. so it doesn't infinitely recurse. null is root).
You may want to take a look at the Auto Mapping abilities of Fluent NHibernate: http://wiki.fluentnhibernate.org/Auto_mapping
In order for NHibernate to construct proxies for your entity classes, you will need to make your non-private members virtual. Public fields will not work with proxy objects, these should be converted to properties.
public class register_email_job
{
public virtual PK id { get; set; }
public virtual user_data user { get; set; }
}
Fluent NHibernate is able to create mapping from classes. It can automap based on conventions, or you can write your own mappers.
Your entities and tables may not match the default conventions, there a several ways to override them.
Using classmap, your mapping might look like this:
public class register_email_job_map : ClassMap<register_email_job>
{
public register_email_job_map()
{
Id( x => x.Id );
References( x=> x.user );
}
}
public class user_comment_map : ClassMap<user_comment>
{
public register_email_job_map()
{
// properties from BaseComment2
References( x=> x.user );
References( x=> x.parent );
}
}