mapping one-to-many relation with Fluent NHibernate does not contain any child when browsing through one-end - fluent-nhibernate

I've created the following domain classes:
public class Car
{
public virtual int Id { get; set; }
public virtual string Registration { get; set; }
public virtual User ResponsibleContact { get; set; }
protected Car()
{}
public Fahrzeug(User responsibleContact, string registration)
{
ResponsibleContact = responsibleContact;
Registration = registration;
ResponsibleContact.Cars.Add(this);
}
}
public class User
{
public virtual int Id { get; set; }
public virtual byte[] EncryptedUsername { get; set; }
public virtual byte[] EncryptedPassword { get; set; }
public virtual IList<Car> Cars { get; private set; }
public virtual string Username
{
get
{
var decrypter = UnityContainerProvider.GetInstance().UnityContainer.Resolve<IRijndaelCrypting>();
return decrypter.DecryptString(EncryptedUsername);
}
}
protected User()
{ }
public User(byte[] encryptedUser, byte[] encryptedPassword)
{
Cars = new List<Car>();
EncryptedUsername = encryptedUser;
EncryptedPassword = encryptedPassword;
}
}
and the mapping classes:
public class CarMap : ClassMap<Car>
{
public CarMap()
{
Id(c => c.Id).GeneratedBy.Native();
Map(c => c.Registration);
References(c => c.ResponsibleContact).Not.Nullable();
}
}
public class UserMap : ClassMap<User>
{
public UserMap()
{
Id(st => st.Id).GeneratedBy.Native();
Map(st => st.EncryptedUsername).Column("Username");
Map(st => st.EncryptedPassword).Column("Password");
HasMany(st => st.Cars).Inverse().AsBag();
}
}
If I query some Member objects, I get the members, but the cars collection is empty!
If I query some Cars I got all the cars with the right Member. But within the member, the cars collection is also empty!
Is there anybody who has an Idea of what can happened?

you have to make sure the foreign key column of the collection and the reference is the same otherwise there is a mismatch.
References(c => c.ResponsibleContact, "ResponsibleContact_id").Not.Nullable();
and
HasMany(st => st.Cars).Inverse().KeyColumn("ResponsibleContact_id");

Related

AutoMapper error: class maps to a datatype (byte[])

I have two classes, each having a domain and a repo version.
DOMAIN:
public class MusicInfo
{
public string Id { get; set; }
public MusicImage Image { get; set; }
public MusicInfo(byte[] image)
{
this.Image = new MusicImage(this, image);
}
}
public class MusicImage
{
public byte[] Blob { get; set; }
public MusicInfo MusicInfo { get; set; }
public string Id { get; set; }
public MusicImage(MusicInfo musicInfo, byte[] blob)
{
if (musicInfo == null)
throw new ArgumentNullException("musicInfo");
if (blob == null)
throw new ArgumentNullException("blob");
this.MusicInfo = musiscInfo;
this.Blob = blob;
}
}
REPO:
public class MusicInfoRepo
{
public virtual long Id { get; set; }
public virtual MusicImageRepo Image { get; set; }
}
public class MusicImageRepo
{
public virtual byte[] Blob { get; set; }
public virtual MusicInfoRepo MusicInfo { get; set; }
public virtual long Id { get; set; }
}
And here are their mappings:
public class MusicInfoRepoMap : HighLowClassMapping<MusicInfoRepo>
{
public MusicInfoRepoMap()
{
Table("MusicInfo");
Id(f => f.Id, m => m.Generator(Generators.HighLow, HighLowMapper));
OneToOne(f => f.Image, m => m.Cascade(Cascade.All));
}
}
public class MusicImageRepoMap : ClassMapping<MusicImageRepo>
{
public MusicImageRepoMap()
{
Table("MusicImage");
Id(f => f.Id, m => m.Generator(Generators.Foreign<MusicImageRepo>(f => f.MusicInfo)));
Property(f => f.Blob, m =>
{
m.NotNullable(true);
m.Column(c => c.SqlType("VARBINARY(MAX)"));
m.Length(Int32.MaxValue);
m.Update(false);
});
OneToOne(f => f.MusicInfo,
m =>
{
m.Cascade(Cascade.None);
m.Constrained(true);
m.Lazy(LazyRelation.NoLazy);
});
}
}
When I am trying to query for a ClassA that has a one to one relationship with ClassB which also has a one to one relationship with MusicInfo, an error occurs that says:
Missing type map configuration or unsupported mapping.
Mapping types:
MusicImageRepo -> Byte[]
Blah.MusicImageRepo -> System.Byte[]
Destination path:
List`1[0]
Source value:
Blah.MusicImageRepo
but here is how i map them:
Mapper.CreateMap<MusicInfo, MusicInfoRepo>();
Mapper.CreateMap<MusicInfoRepo, MusicInfo>();
Mapper.CreateMap<MusicImage, MusicImageRepo>();
Mapper.CreateMap<MusicImageRepo, MusicImage>();
There are no problems when saving these classes.
I really dont get why the error happens.
Will really appreciate your help.
OneToOne says that the other entity/table has the Reference(column). It should not work when both sides have a onetoone mapping since they bounce the responsiblity back and forth.
Also the classes look a bit overcomplicated when all you need is to store the bytes somewhere else.
public class MusicInfoRepo
{
public virtual long Id { get; private set; }
public virtual MusicImageRepo Image { get; private set; }
public MusicInfo(byte[] image)
{
this.Image = new MusicImageRepo(this, image);
}
}
public class MusicImageRepo
{
public virtual MusicInfoRepo MusicInfo { get; private set; }
public virtual byte[] Blob { get; set; }
}
public class MusicInfoRepoMap : HighLowClassMapping<MusicInfoRepo>
{
public MusicInfoRepoMap()
{
Table("MusicInfo");
Id(f => f.Id, m => m.Generator(Generators.HighLow, HighLowMapper));
OneToOne(f => f.Image, m => m.Cascade(Cascade.All));
}
}
public class MusicImageRepoMap : ClassMapping<MusicImageRepo>
{
public MusicImageRepoMap()
{
Table("MusicImage");
ComposedId(m => m.ManyToOne(x => x.MusicInfo));
Property(f => f.Blob, m =>
{
m.NotNullable(true);
m.Column(c => c.SqlType("VARBINARY(MAX)"));
m.Length(Int32.MaxValue);
m.Update(false);
});
}
}
Note: think about it if the seperation between DomainModel and MappedModel really makes sense. NHibernate goes to great length supporting mapping of DomainModels.

NHibernate JoinQueryOver

Calling all NHibernate gurus out there!
If any one of you brainy folks could help me with the following conundrum I'd be most grateful:
I have some entities that describe RSS feeds from various sources that are grouped together in an entity called FeedList.
I am trying to select only the distinct SourceFeed entities that are linked with a given FeedList. (i.e "WHERE FeedList.name = 'feedlist1' ".
I've been playing around with JoinQueryOver for a while now but I just can't seem to work out how to get the required results.
The entities are related like this:
FeedList > Feed > FeedSource
So a FeedList contains many Feeds and each Feed belongs to a FeedSource.
Here is the code for the entities:
public class Feed
{
public virtual int Id { get; set; }
public virtual string Description { get; set; }
public virtual FeedSource FeedSource { get; set; }
public virtual string URL { get; set; }
}
public class FeedList
{
public virtual int Id{get;set;}
public virtual string Name { get; set; }
public virtual IList<Feed> Feeds { get; set; }
}
public class FeedSource
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
I am using Fluent Automapping with the following overrides:
public class FeedOverride : IAutoMappingOverride<Feed>
{
public void Override(AutoMapping<Feed> mapping)
{
mapping.References<FeedSource>(map => map.FeedSource).Cascade.All();
}
}
public class FeedListOverride : IAutoMappingOverride<FeedList>
{
public void Override(AutoMapping<FeedList> mapping)
{
mapping.HasManyToMany<Feed> (map => map.Feeds).Cascade.All().Table("FeedList_Feed");
}
}
Here is some code that creates some sample data:
private static void CreateSampleData()
{
using (var session = HibernateHelper.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
//Create source 1 and feeds
FeedSource source1 = new FeedSource() { Name = "BBC" };
IList<Feed> feedsForSource1 = new List<Feed>(){
CreateFeed("Sample Feed1",source1,"http://feed1.xml"),
CreateFeed("Sample Feed2",source1,"http://feed2.xml")
};
FeedList feedList1 = CreateFeedList("FeedList1", feedsForSource1);
//Create source 2 and feeds
FeedSource source2 = new FeedSource() { Name = "Sky" };
IList<Feed> feedsForSource2 = new List<Feed>(){
CreateFeed("Sample Feed3",source2,"http://feed3.xml"),
CreateFeed("Sample Feed4",source2,"http://feed4.xml"),
CreateFeed("Sample Feed5",source2,"http://feed5.xml")
};
FeedList feedList2 = CreateFeedList("FeedList2", feedsForSource2);
session.SaveOrUpdate(feedList1);
session.SaveOrUpdate(feedList2);
transaction.Commit();
}
}
}
What am I trying to achieve?
If I were to describe it (very poorly) in SQL, I'm looking to do something like this:
select distinct *
from FeedList as list
LEFT JOIN FeedList_Feed as list_feed
ON list.Id = list_feed.FeedList_id
LEFT JOIN Feed as feed
ON feed.FeedSource_id = list_feed.Feed_id
LEFT JOIN FeedSource as src
ON src.Id = list_feed.Feed_id
WHERE list.Name="a feedlist name"
Thanks very much for your time :)
Ok so I've managed to work this out finally for anyone that's interested:
Entities
public class Feed
{
public virtual int Id { get; set; }
public virtual string Description { get; set; }
public virtual FeedSource FeedSource { get; set; }
public virtual string URL { get; set; }
public virtual FeedList FeedList { get; set; }
}
public class FeedList
{
public virtual int Id{get;set;}
public virtual string Name { get; set; }
public virtual IList<Feed> Feeds { get; set; }
}
public class FeedSource
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
Overrides
public class FeedOverride : IAutoMappingOverride<Feed>
{
public void Override(AutoMapping<Feed> mapping)
{
mapping.References<FeedList>(map => map.FeedList).Cascade.All();
mapping.References<FeedSource>(map => map.FeedSource).Cascade.All();
}
}
public class FeedListOverride : IAutoMappingOverride<FeedList>
{
public void Override(AutoMapping<FeedList> mapping)
{
mapping.HasManyToMany<Feed>(map => map.Feeds).Cascade.All().Table("FeedList_Feed");
//mapping.HasMany<FeedListFeed>(map => map.Feeds).Cascade.All();
}
}
And finally:
The Query
session.QueryOver<FeedList>()
.Inner.JoinAlias(f => f.Feeds, () => feedAlias)
.Where(fl => fl.Name == name)
.Select(x => feedAlias.FeedSource)
.List<FeedSource>().Distinct().ToList();

Table Per Subclass Inheritance mapping by NHibernate Mapping-by-Code

How to write mappings in new NHibernate Mapping-By-Code in Table Per Subclass strategy for this classes:
public class Person
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class JuridicalPerson : Person
{
public virtual int Id { get; set; }
public virtual string LegalName { get; set; }
}
public class PrivatePerson : Person
{
public virtual int Id { get; set; }
public virtual bool Sex { get; set; }
}
Here is a possible mapping in a slighly abbreviated form
public class PersonMapping : ClassMapping<Person>
{
public PersonMapping()
{
Table("person");
Id(x => x.Id, m => m.Generator(Generators.Native));
Property(x => x.Name);
}
}
public class JuridicalPersonMapping : JoinedSubclassMapping<JuridicalPerson>
{
public JuridicalPersonMapping()
{
Table("juridical_person");
Key(m => m.Column("person_id"));
Property(x => x.LegalName);
}
}
public class PrivatePersonMapping : JoinedSubclassMapping<PrivatePerson>
{
public PrivatePersonMapping()
{
Table("private_person");
Key(m => m.Column("person_id"));
Property(x => x.Sex);
}
}
You don't need to duplicate declaration of the Id property in the derived classes. It's inherited from the parent Person class.

How to order a HasMany collection by a child property with Fluent NHibernate mapping

I am using Fluent NHibernate to map the following classes:
public abstract class DomainObject
{
public virtual int Id { get; protected internal set; }
}
public class Attribute
{
public virtual string Name { get; set; }
}
public class AttributeRule
{
public virtual Attribute Attribute { get; set; }
public virtual Station Station { get; set; }
public virtual RuleTypeId RuleTypeId { get; set; }
}
public class Station : DomainObject
{
public virtual IList<AttributeRule> AttributeRules { get; set; }
public Station()
{
AttributeRules = new List<AttributeRule>();
}
}
My Fluent NHibernate mappings look like this:
public class AttributeMap : ClassMap<Attribute>
{
public AttributeMap()
{
Id(o => o.Id);
Map(o => o.Name);
}
}
public class AttributeRuleMap : ClassMap<AttributeRule>
{
public AttributeRuleMap()
{
Id(o => o.Id);
Map(o => o.RuleTypeId);
References(o => o.Attribute).Fetch.Join();
References(o => o.Station);
}
}
public class StationMap : ClassMap<Station>
{
public StationMap()
{
Id(o => o.Id);
HasMany(o => o.AttributeRules).Inverse();
}
}
I would like to order the AttributeRules list on Station by the Attribute.Name property, but doing the following does not work:
HasMany(o => o.AttributeRules).Inverse().OrderBy("Attribute.Name");
I have not found a way to do this yet in the mappings. I could create a IQuery or ICriteria to do this for me, but ideally I would just like to have the AttributeRules list sorted when I ask for it.
Any advice on how to do this mapping?
I think the OrderBy-method takes in the string that it inserts to the generated SQL-clause. So just doing
HasMany(o => o.AttributeRules).Inverse().OrderBy("Name");
Where the "Name" is the name of the column that contains Attribute's name. It should be in the column list because Attribute is joined to the AttributeRule.
Did you solve this other way? Please share.

NHibernate2 query is wired when fetch the collection from the proxy. Is this correct behavior?

This is my class:
public class User
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<UserFriend> Friends { get; protected set; }
}
public class UserFriend
{
public virtual int Id { get; set; }
public virtual User User { get; set; }
public virtual User Friend { get; set; }
}
This is my mapping (Fluent NHibernate):
public class UserMap : ClassMap<User>
{
public UserMap()
{
Id(x => x.Id, "UserId").GeneratedBy.Identity();
HasMany<UserFriend>(x => x.Friends);
}
}
public class UserFriendMap : ClassMap<UserFriend>
{
public UserFriendMap()
{
Id(x => x.Id, "UserFriendId").GeneratedBy.Identity();
References<User>(x => x.User).TheColumnNameIs("UserId").CanNotBeNull();
References<User>(x => x.Friend).TheColumnNameIs("FriendId").CanNotBeNull();
}
}
The problem is when I execute this code:
User user = repository.Load(1);
User friend = repository.Load(2);
UserFriend userFriend = new UserFriend();
userFriend.User = user;
userFriend.Friend = friend;
friendRepository.Save(userFriend);
var friends = user.Friends;
At the last line, NHibernate generate this query for me:
SELECT
friends0_.UserId as UserId1_,
friends0_.UserFriendId as UserFrie1_1_,
friends0_.UserFriendId as UserFrie1_6_0_,
friends0_.FriendId as FriendId6_0_,
friends0_.UserId as UserId6_0_
FROM "UserFriend" friends0_ WHERE friends0_.UserId=#p0; #p0 = '1'
QUESTION: Why the query look very wired? It should select only 3 fields (which are UserFriendId, UserId, FriendId) Am I right? or there is something going on inside NHibernate?
You should have a look at the mapping generated by fluent-nhibernate, maybe that generated something weird.