fluent-nhibernate
fluent-nhibernate copied to clipboard
Dictionary mapping maps to interfaces instead of implemention
I have a IDictionary<IA, IB> dictionary in my class. I try to map this with FluentNHibernate but it creates a wrong mapping. The application shows that it generates a map using IA and IB instead of classes A and B. This is also clearly visible from the exported *.hbm.xml files. I am using Fluent-nhibernate 1.3.
The following code shows the problem:
using FluentNHibernate.Cfg;
using FluentNHibernate.Mapping;
using NHibernate;
using NHibernate.Cfg;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
public interface IA
{
int Id { get; set; }
string PropA { get; set; }
}
public interface IB
{
int Id { get; set; }
string PropB { get; set; }
}
public interface IC
{
int Id { get; set; }
IDictionary<IA, IB> Dictionary { get; set; }
}
public class A : IA
{
public virtual int Id { get; set;}
public string PropA { get; set; }
}
public class B : IB
{
public virtual int Id { get; set; }
public string PropB { get; set; }
}
public class C : IC
{
public virtual int Id { get; set; }
public virtual IDictionary<IA, IB> Dictionary { get; set; }
}
public class AMapper : ClassMap<A>
{
public AMapper()
{
Id(x => x.Id).GeneratedBy.Identity().Column("id");
Map(x => x.PropA).Column("propa");
}
}
public class BMapper : ClassMap<B>
{
public BMapper()
{
Id(x => x.Id).GeneratedBy.Identity().Column("id");
Map(x => x.PropB).Column("propa");
}
}
public class CMapper : ClassMap<C>
{
public CMapper()
{
Id(x => x.Id).GeneratedBy.Identity().Column("id");
HasMany<C>(x => x.Dictionary).Table("dict_table").AsEntityMap("C_id").KeyColumn("B_id");
}
}
class Program
{
static void Main(string[] args)
{
Configuration conf = new Configuration().Configure();
//configuration.AddAssembly(typeof(Program).Assembly);
var nhConfig = Fluently.Configure(conf)
.Mappings(mapping =>
{
mapping.FluentMappings.AddFromAssembly(typeof(A).Assembly);
mapping.FluentMappings.ExportTo(@"c:\temp\");
})
.ExposeConfiguration(cfg =>{});
Configuration configuration = nhConfig.BuildConfiguration();
ISessionFactory sessionFactory = configuration.BuildSessionFactory();
sessionFactory.OpenSession();
}
}
}
But you declared IDictionary of IA, IB. Fluent doesn't know that only implementations of IA and IB are classes A and B, respectively, neither does he know that you want concrete type Dictionary to be used for the interface. Also, didn't you mean to write HasMany[B] or HasMany[IB] in the mapping?
It is possible to do the same with other 'normal' relations. Using the classic xml files I can get this working. I am currently on holiday. End of next week I can provide some examples.
It may be not a bug, but an incomplete API.
Please provide examples
If I have a reference to an interface in my domain object
public virtual IModel Model { get; set; }
I can specify in my mapping
References<Model>(x => x.Model).Column("model_id");
and this works (since Model implements IModel). I need something similar for Dictionaries.
The implementation of the dictionary is as follows in Angle.cs
public virtual IDictionary<IUser, IUserAngle> AngleUsers
{
get
{
return _angleUsers;
}
set
{
_angleUsers = value;
}
}
The mapping in AngleMap.cs is
HasMany<UserAngle>(x => x.AngleUsers).Table("UserAngle").AsEntityMap("UserId").KeyColumn("AngleId").Cascade.All();
the mapping generated for this relation by FluentNhibernate is the following (intermediate) Angle.hbm.xml
<map cascade="all" name="AngleUsers" table="UserAngle">
<key>
<column name="AngleId" />
</key>
<index-many-to-many class="EveryAngle.Edgar.Domain.User.IUser, EveryAngle.Edgar.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<column name="UserId" />
</index-many-to-many>
<one-to-many class="EveryAngle.Edgar.Domain.User.IUserAngle, EveryAngle.Edgar.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</map>
This should be (this works, tried it by doing the mapping with the Angles.hbm.xml) (Note the use of the class instead of the Interface)
<map cascade="all" name="AngleUsers" table="UserAngle">
<key>
<column name="AngleId" />
</key>
<index-many-to-many class="EveryAngle.Edgar.Domain.User.User, EveryAngle.Edgar.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<column name="UserId" />
</index-many-to-many>
<one-to-many class="EveryAngle.Edgar.Domain.User.UserAngle, EveryAngle.Edgar.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</map>
In short the API does not have a way to specify the classes to use for the dictionary (in my opinion).
Ok, that's more like it, let's see what I can do to help.
2013/8/22 Fennek IT [email protected]
If I have a reference to an interface in my domain object
public virtual IModel Model { get; set; }
I can specify in my mapping
References<Model>(x => x.Model).Column("model_id");
and this works (since Model implements IModel). I need something similar for Dictionaries.
The implementation of the dictionary is as follows in Angle.cs
public virtual IDictionary<IUser, IUserAngle> AngleUsers { get { return _angleUsers; } set { _angleUsers = value; } }
The mapping in AngleMap.cs is
HasMany<UserAngle>(x => x.AngleUsers).Table("UserAngle").AsEntityMap("UserId").KeyColumn("AngleId").Cascade.All();
the mapping generated for this relation by FluentNhibernate is the following (intermediate) Angle.hbm.xml
This should be (this works, tried it by doing the mapping with the Angles.hbm.xml) (Note the use of the class instead of the Interface)
In short the API does not have a way to specify the classes to use for the dictionary (in my optionion).
Reply to this email directly or view it on GitHubhttps://github.com/jagregory/fluent-nhibernate/issues/234#issuecomment-23075367 .
ó Õ×ÁÖÅÎÉÅÍ, þÅÒÍ£ÎÎÏ× çÌÅÂ, ÔÅÌ. (916) 314-9324
Hi, would adding an AsEntityMap function to ManyToManyPart.cs help?
public ManyToManyPart<TChild> AsEntityMap(Type indexType, string indexColumn, Type typeOfValue, string valueColumn)
{
return AsMap(null).AsTernaryAssociation(indexType, indexColumn,typeOfValue, valueColumn);
}
This would allow me to specify the necessary types.
Create a pull request for this issue.