I have been spinning around in the same place trying to figure this issue with a many-to-many table with extra columns. I am swallowing my pride and asking more experienced Fluent NHibernate experts if you can help out here.
I have been trying to use a component for a many-to-many table but I don't seem to find where to point the component to cause a join on a specific column. I guess as long as I populate the completion information object, the presence and usage of a component is not a requirement for me.
This is my simplified schema.
User
...................
Id
Name
Task
...................
Id
Name
Job
...................
Id
Name
JobTask
...................
JobId
TaskId
CompletedByUserId
CompletionDate
CompletionNotes
Then I have objects like so:
public class Job
{
long Id { get; set; }
IList<Task> Tasks { get; set; }
}
public class Task
{
long Id { get; set; }
string Name { get; set; }
CompletionInfo CompletionInfo { get; set; }
}
public class CompletionInfo
{
User User { get; set; }
DateTime CompletionDate { get; set; }
}
Can you help with your ideas how to implement this in fluent nhibernate?
I had this mapping before on the JobMap and it would work but only for the many-to-many columns ( TaskId, JobId). I need the extra information related to that relationship(dateCompleted, userCompleted,etc)
HasManyToMany<Task>(job => job.Tasks)
.Table(ManyToManyTable)
.ParentKeyColumn("JobId")
.ChildKeyColumn("TaskId")
.Not.LazyLoad()
.Cascade.Delete();
In order to simplify things with the many-to many I thought to create an object to represent the relationship and encapsulate a task. Like so: And I would add a proxy in the Job task to modify the actual Task properties. But that is not going anywhere.
This must be something common out there, I am very surprised there not much regarding this issue. Naturally I would have loved a way to extend the HasManyToMany but not sure how, hence this post.
public class JobTask : Entity<long, JobTask>
{
public virtual Job ParentJob { get; set; }
public virtual Task Task { set;set; }
public virtual TaskCompletionDetails CompletionInformation
{
get
{
if (this.Task == null)
return null;
return Task.CompletionInformation;
}
set
{
if (this.Task == null)
return;
this.Task.CompletionInformation = value;
}
}
public virtual string CompletionNotes
{
get
{
if (this.Task == null || this.Task.CompletionInformation == null)
return null;
return Task.CompletionInformation.Notes;
}
set
{
if (this.Task == null)
return;
this.Task.CompletionInformation.Notes = value;
}
}
public virtual DateTime? CompletionDate
{
get
{
if (this.Task == null || this.Task.CompletionInformation == null)
return null;
return Task.CompletionInformation.Date;
}
set
{
if (this.Task == null)
return;
this.Task.CompletionInformation.Date = value;
}
}
public virtual IUser User
{
get
{
if (this.Task == null || this.Task.CompletionInformation == null)
return null;
return Task.CompletionInformation.User;
}
set
{
if (this.Task == null || value == null)
return;
if (this.Task.CompletionInformation != null)
this.Task.CompletionInformation.User = value;
}
}
}
}
This would be the map direction I have started for it:
public class JobTaskMap : ClassMap<JobTask>
{
private const string ModelTable = "[JobTasks]";
public JobTaskMap()
{
Table(ModelTable);
Id(jobTask => jobTask.Id)
.Column("Id")
.GeneratedBy.Identity();
References<Job>( jobTask => jobTask.ParentJob)
.Column("JobId")
.Fetch.Join();
Component<Task>( jobTask => (Task) jobTask.Task,
// This is the task
comp =>
{
// This is the task completion information
comp.Component<TaskCompletionDetails>(
task => (TaskCompletionDetails)task.CompletionInformation,
compInfo =>
{
compInfo.Map(info => info.Date)
.Column("CompletionDate")
.Nullable();
compInfo.Map(info => info.Notes)
.Column("CompletionNotes")
.Nullable();
compInfo.References<User>(info => info.User)
.Column("CompletedByUserId")
.Nullable()
.Fetch.Join();
});
});
}
These are some other related reading I have followed without success:
Reference: