i have the following class:
public class Worker
{
public int WorkerID {get;set;}
public string Name { get;set;}
}
public class TransferOrder
{
public int TransferOrderID { get;set;}
public Worker workerTobeTransfered{get;set;}
}
how do i automap this classes in fluent nhibernate.
ok, after a few googling, i figured out the solution:
this is a many-to-one relation and it is mapped using Reference() Method, and the auto mapping already do that:
References<Worker>(m => m.Worker);
there is also a great article provide many examples of mapping situations which can be found
Here.
Related
We are using Fluent NH with convention based mapping. I have the following:
public class Foo() : Entity
{
public BarComponent PrimaryBar { get; set; }
public BarComponent SecondaryBar { get; set; }
}
public class BarComponent
{
public string Name { get; set; }
}
I have it to the point where it will create the foo table with a single name field. I've tried the following Override and it doesn't work.
public class FooOverride : IAutoMappingOverride<Foo>
{
public void Override(AutoMapping<Foo> mapping)
{
mapping.Component(x => x.PrimaryBar).ColumnPrefix("primary");
mapping.Component(x => x.SecondaryBar).ColumnPrefix("secondary");
}
}
Do I really need to do a full override mapping or can what I have here be made to work somehow?
I ran into this a couple of years ago when I started with FNH. It's one of the few scenarios I've seen where FNH Automapping does not "just work".
The approach that was suggested to me at the time, which I've used successfully (with entities however, not components) is to create empty, intermediate entities, and reference them in the descendant class.
In your case, you could create two new, empty classes that inherit from BarComponent (say, PrimaryBarComponent and SecondaryBarComponent).
Then, in your Foo class, declare them as:
public PrimaryBarComponent PrimaryBar { get; set; }
public SecondaryBarComponent SecondaryBar { get; set; }
This is a kluge, in my opinion, but it works fine with entities and lists of entities, and does not require any overrides or conventions.
I've never used components with FNH, so I don't know if a similar approach will work, but it might be worth investigating.
I ended up getting the way I have described in the question working. It turned out to be a problem with our AutoMappingConfiguration which inherits from DefaultAutomappingConfiguration. We weren't identifying Components properly.
i have the following scenario
public abstract class BaseClass
{
public virtual int Id {get; set};
public virtual string Name {get; set;}
}
public class FirstSubClass : BaseClass
{
//properties and behaviour here
}
public class SecondSubClass : BaseClass
{
//properties of SecondSubclass Here
}
public class ProcessStep
{
public virtual IList<BaseClass> ContentElements {get; set;}
}
for mapping i have used following code snippet :-
this._sessionFactory =
Fluently.Configure().Database(SQLiteConfiguration.Standard
.ConnectionString(#"Data Source=SqliteTestSqlDataAccess.s3db; Version=3; New=True; Pooling=True; Max Pool Size=1;"))
.Mappings(m => m.AutoMappings.Add(AutoMap.Assembly(assemblyWithDomainClasses).Conventions.Add(DefaultCascade.All())))
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();
By default fluent will ignore the abstract base class that is BaseClass.
But as in the class ProcessStep there is property ContentElements which returns IList , i am getting an exception:-
NHibernate.MappingException : Association references unmapped class: BaseClass
If i include the base class using the IncludeBase(typeof(BaseClass)) then it works fine but it creates a table for BaseClass and Derived classes and the records are linked with FK-PK relationship(table per subclass).
What i want to achieve is table per concrete class. that is each derive class will have it's own table where there will all properties of derived class + properties in the base class.
Any idea how to achieve it?
Since I haven't seen your mapping, let me provide mine. You could achieve this by doing like this
public class BaseClassMap:ClassMap<BaseClass>
{
public BaseClassMap()
{
/*
* Identity generator can't be native because subclass objects should be unique
* So use HiLo or Guid or other generators which will generate unique id on the child tables
*/
Id(x => x.Id).GeneratedBy.Guid();
Map(x => x.Name);
UseUnionSubclassForInheritanceMapping(); // This is important - uses union-subclass mappings for the derived classes
}
}
public class FirstSubClassMap : SubclassMap<FirstSubClass>
{
public FirstSubClassMap()
{
Table("FirstSubClassTable");
// Map properties for FirstSubClass
}
}
public class SecondSubClassMap : SubclassMap<SecondSubClass>
{
public SecondSubClassMap()
{
Table("SecondSubClassTable");
// Map properties for SecondSubClass
}
}
It caused me headache to implement the "Table per Concrete Class" inheritance strategy with an abstract base class with nhibernate automapping. But I think, I've finally found a solution and want to share it with you. I also think, it's not added to the automapping docs, because it's maybe considered as a "weak" database design.
First here are some resources I found about this topic:
https://www.codeproject.com/Articles/232034/Inheritance-mapping-strategies-in-Fluent-Nhibernat
Example implementation of inheritance strategies in fluent nhibernate (!automapping).
https://github.com/jagregory/fluent-nhibernate/wiki/Automapping-inheritance
Documentation of inheritance strategies in fluent nhibernate with automapping.
(can't add another link) https : // github . com /jagregory/fluent-nhibernate/pull/25/commits/2984c8c4e89aa4cec8625538f763c5931121a4e7
Bug-Fix Union-SubClass implementation (Table per Concrete Class)
These resources basically describe how you need to do it:
As you already mentioned fluent nhibernate ignores abstract base classes. So you need to add them explicitly.
// abstractBaseTypes is just a simple enumeration of base types
// model is the AutoPersistenceModel
abstractBaseTypes.ForEach(m => model = model.IncludeBase(m));
a) If you know the abstract base types at compile time you can use
//sets the union subclass strategy for the known base model
model.Override<SuperType>(m => m.UseUnionSubclassForInheritanceMapping()))
b) If you don't know the concrete types you can create a mapping override for each base type:
public class AbstractRightEntryMappingOverride : IAutoMappingOverride<AbstractRightEntry>
{
public void Override(AutoMapping<AbstractRightEntry> mapping)
{
mapping.UseUnionSubclassForInheritanceMapping();
}
}
// You need to tell nhibernate where to find the overriden mappings.
// You simply can add the assemblies again.
modelAssemblies.ForEach(a => model = model.UseOverridesFromAssembly(a));
I'm trying to learn some NHibernate after diving into EF4. Is the equivalent of the EF4 ObjectContext (or DbContext) the NHibernate Session?
Specifically, in EF4, you derive from ObjectContext (or DbContext) and your class contains explicit ObjectSet's of each entity, for example:
public class EcommerceContext : ObjectContext {
public ObjectSet<Customer> Customers {get; set;}
public ObjectSet<Product> Products {get; set;}
// etc.
}
In the NHib examples I've seen so far, the Session object isn't used this way. Am I missing something?
If you're using NHibernate 3 it's fairly trivial to implement a data context.
public class YourDataContext
{
public ISession Session { get; private set; }
public YourDataContext(ISession session)
{
Session = session;
}
public IQueryable<Customer> Customers
{
get
{
return Session.Query<Customer>();
}
}
}
The same thing is possible in NHibernate 2 but slightly different. You will need the NHibernate.Linq library which is in the contrib modules.
public class YourDataContext:NHibernateContext
{
public YourDataContext(ISession session)
: base(session){}
public IOrderedQueryable<Customer> Customers
{
get
{
return Session.Linq<Customer>();
}
}
}
I'm guessing since you're asking about a datacontext that you're looking to use Linq, and if that's the case, you should definitely use NH3 as the linq provider is much improved.
It should be noted that a datacontext in EF and a datacontext in NH are going to behave differently because NH does not do objectracking and EF does, among other things. You'll see other differences as you learn about it.
I'm using two class NiceCustomer & RoughCustomer which implment the interface ICustomer.
The ICustomer has four properties. They are:
Property Id() As Integer
Property Name() As String
Property IsNiceCustomer() As Boolean
ReadOnly Property AddressFullText() As String
I don't know how to map the interface ICustomer, to the database.
I get an error like this in the inner exception.
An association refers to an unmapped class: ICustomer
I'm using Fluent and NHibernate.
You can map directly to interfaces in NHibernate, by plugging in an EmptyInterceptor during the configuration stage. The job of this interceptor would be to provide implementations to the interfaces you are defining in your mapping files.
public class ProxyInterceptor : EmptyInterceptor
{
public ProxyInterceptor(ITypeHandler typeHandler) {
// TypeHandler is a custom class that defines all Interface/Poco relationships
// Should be written to match your system
}
// Swaps Interfaces for Implementations
public override object Instantiate(string clazz, EntityMode entityMode, object id)
{
var handler = TypeHandler.GetByInterface(clazz);
if (handler == null || !handler.Interface.IsInterface) return base.Instantiate(clazz, entityMode, id);
var poco = handler.Poco;
if (poco == null) return base.Instantiate(clazz, entityMode, id);
// Return Poco for Interface
var instance = FormatterServices.GetUninitializedObject(poco);
SessionFactory.GetClassMetadata(clazz).SetIdentifier(instance, id, entityMode);
return instance;
}
}
After this, all relationships and mappings can be defined as interfaces.
public Parent : IParent {
public int ID { get; set; }
public string Name { get; set; }
public IChild Child { get; set; }
}
public Child : IChild {
public int ID { get; set; }
public string Name { get; set; }
}
public class ParentMap : ClassMap<IParent>
{
public ParentMap()
{
Id(x => x.ID).GeneratedBy.Identity().UnsavedValue(0);
Map(x => x.Name)
}
}
...
This type of technique is great if you want to achieve true decoupling of your ORM, placing all configuration/mappings in a seperate project and only referencing interfaces. Your domain layer is then not being polluted with ORM, and you can then replace it at a later stage if you need to.
how are you querying? If you're using HQL you need to import the interface's namespace with an HBM file with this line:
<import class="name.space.ICustomer, Customers" />
If you're using Criteria you should just be able to query for ICustomer and it'll return both customer types.
If you're mapping a class that has a customer on it either through a HasMany, HasManyToMany or References then you need to use the generic form:
References<NiceCustomer>(f=>f.Customer)
If you want it to cope with either, you'll need to make them subclasses
Subclassmap<NiceCustomer>
In which case I think you'll need the base class Customer and use that for the generic type parameter in the outer class:
References<Customer>(f=>f.Customer)
Regardless, you shouldn't change your domain model to cope with this, it should still have an ICustomer on the outer class.
I'm not sure if the 1.0RTM has the Generic form working for References but a quick scan of the changes should show the change, which I think is a two line addition.
It is not possible to map an interface in nhibernate. If your goal is to be able to query using a common type to retrieve both types of customers you can use a polymorphic query. Simply have both your classes implement the interface and map the classes normally. See this reference:
https://www.hibernate.org/hib_docs/nhibernate/html/queryhql.html (section 11.6)
In the project I'm working on now, we have base Entity class that looks like this:
public abstract class Entity<T> where T : Entity<T>
{
public virtual object Id { get; protected set }
// Equals, GetHashCode overrides, etc...
}
Most classes inheriting from Entity should map Id to int column in SQL Server database, but at least one will need to map to long (bigint).
Is it possible to create FluentNH Auto Mapping convention to map those object Ids to int by default? Then we could use another convention or IAutoMappingOverride to handle long Ids.
Thanks!
To answer my own question... It's possible.
You can define convention like this:
internal class PrimaryKeyConvention : IIdConvention
{
public bool Accept(IIdentityPart id)
{
return true;
}
public void Apply(IIdentityPart id)
{
if (<ID should be long>)
id.SetAttribute("type", "Int64");
else
id.SetAttribute("type", "Int32");
}
}