fluent NHibernate many to many creates additional table - nhibernate

I have two tables "recall" and "service" and I need many to many between them.
I use fluent NHibernate mapping but it creates additional table with name "servicetorecall"
public class Recall : BaseDomain
{
public virtual string Name { get; set; }
public virtual string PersonPosition { get; set; }
public virtual string RecallText { get; set; }
private ICollection<Service> _services = new List<Service>();
public virtual ICollection<Service> Services
{
get { return _services; }
set { _services = value; }
}
}
public class Service : BaseDomain
{
public virtual string Name { get; set; }
public virtual string Url { get; set; }
public virtual string ImgPath { get; set; }
public virtual string ShortContent { get; set; }
public virtual string Content { get; set; }
public virtual bool ServiceIsVisible { get; set; }
ICollection<Recall> _recalls = new List<Recall>();
public virtual ICollection<Recall> Recalls
{
get { return _recalls; }
set { _recalls = value; }
}
}
Mappings :
class RecallMappingOverride : IAutoMappingOverride<Recall>
{
public void Override(AutoMapping<Recall> mapping)
{
mapping.Cache.ReadWrite();
mapping.HasManyToMany(q => q.Services).Table(MappingNames.RECALLS_RELATIONS)
.ParentKeyColumn(MappingNames.RECALL_ID)
.ChildKeyColumn(MappingNames.SERVICE_ID).Inverse().Cascade.All();
}
}
public class ServiceMappingOverride : IAutoMappingOverride<Service>
{
public void Override(AutoMapping<Service> mapping)
{
mapping.Cache.ReadWrite();
mapping.HasManyToMany(q => q.Recalls).Table(MappingNames.RECALLS_RELATIONS) .ParentKeyColumn(MappingNames.SERVICE_ID).ChildKeyColumn(MappingNames.RECALL_ID)
.Inverse().Cascade.All();
}
}
I tried to change cascades but this didn't help. Also I did the same with other entities and it works correctly what type of magic is it?

How do you define "correct", what do you want to achieve?
I never heard of any clean solution for many to many relations which doesn't use pivot table.
[quick glimpse at your mappings]: only one of the "ManyToMany" should be Inverse

Related

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();

How to map a derived class using an EntityBase class on FluentNHibernate

I have an EntityBase class for FluentNHibernate:
public abstract class EntityBase<T>
{
public EntityBase()
{
}
public static T GetById(int id)
{
return (T)Hibernate.Session.Get<T>(id);
}
public virtual void Save()
{
using (var transaction = Hibernate.Session.BeginTransaction())
{
Hibernate.Session.SaveOrUpdate(this);
transaction.Commit();
}
}
public static IList<T> List()
{
return Hibernate.Session.CreateCriteria(typeof(T)).List<T>();
}
public static IList<T> ListTop(int i)
{
return Hibernate.Session.CreateCriteria(typeof(T)).SetMaxResults(i).List<T>();
}
public virtual void Delete()
{
using (var transaction = Hibernate.Session.BeginTransaction())
{
Hibernate.Session.Delete(this);
transaction.Commit();
}
}
}
I have a base member class also a table in database:
abstract public class BaseMember:EntityBase<BaseMember>
{
public virtual int Id { get; set; }
public virtual string Email { get; set; }
public virtual string Password { get; set; }
public virtual string RecordDate { get; protected set; }
public BaseMember()
{
}
}
I have another Member class that is deriving from BaseMember class:
public class IndividualMember : BaseMember
{
public virtual int Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual string PhoneNumber { get; set; }
public virtual string MobilePhoneNumber { get; set; }
public virtual DateTime BirthDate { get; set; }
public virtual bool Gender { get; set; }
public virtual string ProfileImage { get; set; }
public virtual string AddressDefinition { get; set; }
public virtual string ZipCode { get; set; }
public virtual DateTime RecordDate { get; set; }
public IndividualMember()
{
}
}
How can I map those classes with BaseMember and IndividualMember tables in db?
There are different types of Inheritance mapping strategies in Fluent NHibernate.
You can use SubclassMap mapping for derived class.
Strategies : Table-per-class-hierarchy, Table-per-subclass and Table Per Concrete Class.
For table-per-class-hierarchy strategy, you just need to specify the discriminator column.
For more reference :
http://www.codeproject.com/Articles/232034/Inheritance-mapping-strategies-in-Fluent-Nhibernat
https://github.com/jagregory/fluent-nhibernate/wiki/Fluent-mapping#wiki-subclasses

Fluent NHibernate mapping using component

I have just started working on a project using Fluent NHibernate.
What is the correct way to map the following classes using Fluent NHibernate?
public class DurationUnit
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class Duration
{
public virtual int Value { get; set; }
public virtual DurationUnit Unit { get; set; }
public virtual int DurationInMinutes { get{ throw new NotImplementedException(); } }
}
public class Event
{
public virtual int Id { get; set; }
public virtual String Name { get; set; }
public virtual Duration MaxDuration { get; set; }
public virtual Duration MinDuration { get; set; }
}
My inital approach was to declare a ClassMap for DurationUnit and Event, with Duration as a component of Event. When trying this I received an exception:
NHibernate.MappingException: Could not determine type for:
Entities.DurationUnit
if your mapping looks like this
public EventMap()
{
Component(x => x.MaxDuration, c =>
{
c.Map(x => x.Value, "MaxDurationValue");
c.Reference(x => x.Unit, "MaxDurationUnitId");
});
}
then make sure class DurationUnitMap is public and is added to the configuration

How to model this classes withN Hibernate and Fluent.NHibernate Maps?

I'm using ASP.NET MVC with NHibernate and Fluent.NHibernate Maps.
I would like to know how to map the classes on Fluent and to create the database tables on my MySQL:
public class AgenteDeViagem {
public virtual int Id { get; set; }
public virtual string Email { get; set; }
public virtual AgentePessoa AgentePessoa { get; set; }
}
public interface AgentePessoa {
}
public class AgenteDeViagemPJ:AgentePessoa {
public virtual int Id { get; set; }
public virtual AgenteDeViagem AgenteDeViagem { get; set; }
public virtual string Razao { get; set; }
}
public class AgenteDeViagemPF:AgentePessoa {
public virtual int Id { get; set; }
public virtual AgenteDeViagem AgenteDeViagem { get; set; }
public virtual string Nome { get; set; }
}
Thank you very much!
Looks to me like you're halfway there. You're already using virtual and relations are set, so using the Automapping strategy, you only need to build the session factory:
private static ISessionFactory InitializeNHibernate()
{
var cfg = Fluently.Configure()
.Database(MySQLConfiguration.Standard.ConnectionString(c =>
c.Database("agente").Server("localhost")
.Username("user").Password("password")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<AgenteDeViagem>())
.ExposeConfiguration(configuration =>
{
// Comment to disable schema generation
BuildDatabaseSchema(configuration);
});
return cfg.BuildSessionFactory;
}
private static void BuildDatabaseSchema(Configuration configuration)
{
var schemaExport = new SchemaExport(configuration);
schemaExport.SetOutputFile("mysql_script.sql");
schemaExport.Create(false, true);
}

Mapping a collection of entities in fluent nHibernate

I'm developing a question/answer based application
I have a Post table in the db along the lines of:
ID
Title
Body
DateCreated
AuthorID
AuthorName (in case user not registered)
AutherEmail (as above)
PostType (enum - 1 if question, 2 if reply)
Show (bit field)
Then, there is "PostBase" - which is an abstract class (this has properties common to both Question and Answer - listed below)
I then have an internal "Post" class, which descends from PostBase, and therefore has all the properties listed above.
There is then have a Question class, and an Answer class.
Both use Post as a base class.
Here are the classes:
public abstract class PostBase
{
{
get { return postCreatorEmail; }
//todo: add email address validation here?
set { postCreatorEmail = value; }
} private IList<Attachment> attachments = new List<Attachment>();
public PostBase()
{
//init logic here
}
public virtual DateTime DateCreated { get; set; }
public virtual string ID { get; set; }
public virtual string Body { get; set; }
public virtual DateTime DateLastModified { get; set; }
public virtual string PostCreatorName { get; set; }
public virtual string PostCreatorEmail { get; set; }
public virtual int PostCreatorID { get; set; }
public virtual PostType PostType { get; set; }
public virtual PostSource PostSource { get; set; }
public virtual bool Show { get; set; }
public IEnumerable<Attachment> Attachments { get { return attachments; } }
}
Post
internal class Post : PostBase
{
public virtual List<string> Tags { get; set; }
public virtual string Title { get; set; }
public virtual string ParentPostID { get; set; }
}
Question:
public class Question : PostBase
{
public Question()
{
tags = new List<string>();
}
public string Title { get; set; }
public List<string> Tags { get { return tags; } }
public int NumberOfReplies { get; set; }
}
Answer:
public class Answer : PostBase
{
public string QuestionID { get; set; }
}
I use automapper to map to / from Answer and Post or Question and Post
What I'm trying to do, is create the following class:
public class QuestionWithAnswers
{
public Question Question { get; set; }
public IEnumerable<Answer> Answers { get; set; }
}
Which basically has a "Question" - remember this is just a Post in the db, with a ParentPostID of 0, with a list of Answers (where ParentPostID is equal to Question.ID ... or along those lines)
My question is - how do I map this in fluent nHibernate?
You could use Automapper for QuestionWithAnswers, but Answers has to have an IList and not an IEnumerable:
public class QuestionWithAnswers
{
public virtual Question Question { get; set; }
public virtual IList<Answer> Answers { get; set; }
}
What I don't understand is the existence of QuestionWithAnswers, when the following (I think) should do:
public class Question : PostBase
{
public virtual string Title { get; set; }
public virtual List<string> Tags { get { return tags; } }
public virtual int NumberOfReplies { get; set; }
public virtual IList<Answer> Answers { get; set; }
}
If the question has answers, you'll get them, and if it does not, you don't.