I accessing a pre-existing database (actually DB2 on an IBM i), and have an issue with the mappings for the following (simple) structure in Fluent NHibernate. I have had to construct an artificial example, so forgive any ommissions.

Job ...

public class Job
{
    public virtual string JobCode { get; set; }

    public virtual string Owner{ get; set; }

    public virtual IList<Deliverable> Deliverables { get; set; }

    public Job()
    {
        Deliverables = new List<Deliverable>();
    }
}

Deliverable ..

public class Deliverable
{
    public virtual string JobCode { get; set; }

    public virtual int Package { get; set; }

    public virtual string Owner { get; set; }

    public virtual string Reference { get; set; }

    public virtual Job Job { get; set; }
}

I am trying to map a 'HasMany' relationship between Job and Deliverable, as follows ..

public class JobMap : ClassMap<Job>
{
    public JobMap()
    {
        Table("JOB");

        Id(x => x.JobCode).Column("CODE");

        Map(x => x.Owner).Column("WHODO");

        HasMany(x => x.Deliverables)
            .KeyColumn("CODE");
    }
}

public class DeliverableMap : ClassMap<Deliverable>
{
    public DeliverableMap()
    {
        Table("DELIVERABLE");

        Id(x => x.JobCode).Column("CODE");

        Map(x => x.Reference).Column("UNQREF");

        Map(x => x.Owner).Column("WHODO");

        References( x => x.Job) 
            .Column("CODE") ;
    }
}

This seems to work, and if you take the SQL that is produced, and run it directly, the correct results are returned (in this case 11 records, all unique). BUT when I do the following, the list of Deliverables has 11 entries all identical.

IList results = session .CreateCriteria(typeof(Job)) .Add(Expression.Eq("Code", "206171")) .List();

foreach (var job in results)
{
   Console.WriteLine("job.JobCode" + job.JobCode);
   Console.WriteLine("job.Owner" + job.Owner);

   foreach (var deliverable in job.Deliverables)
   {

     **// These are all identical!**

     Console.WriteLine(deliverable.Reference);
     Console.WriteLine("deliverable.Owner" + deliverable.Owner);
     Console.WriteLine(deliverable.JobNumber);
     Console.WriteLine(deliverable.DeliverableTyoe);
     Console.WriteLine(deliverable.Description);
   }
}

So, are the mappings incorrect, or is there something up with the way that I am using them?

Many thanks in advance, I have been staring at this all day.

有帮助吗?

解决方案

I seem to have fixed it. I added CompositeID to the Deliverables mapping

 CompositeId()
     .KeyProperty(x => x.JobCode, "CODE")
     .KeyProperty(x => x.Reference, "UNQREF");

This meant that I had to override the following in the Deliverable class

public override bool Equals(object obj)
{
  if (obj == null)
    return false;

  var t = obj as Deliverable;
  if (t == null)
    return false;

  if (JobCode == t.JobCode && Reference == t.Reference)
    return true;

  return false;
 }

  public override int GetHashCode()
  {
    return (JobCode + "|" + Reference).GetHashCode();
  }

and then also changed the Job mapping as below

 HasMany(x => x.Deliverables)
   .KeyColumn("Codex")
   .Inverse()
   .Cascade.All();

I am not sure which of these has corrected the situation (I suspect the .Inverse() in the Job mapping.

I am not sure what the generated SQL now looks like, but the answers look correct.

其他提示

In many-to-one relations (in our case Delivarable and Job), the relation itself is expressed with exactly one DB column. The child table (Deliverable) has (must have) a reference column with the Job ID (Code).

So, what we need for our mapping, is the column inside the Delivarable table, containing the relation to the Job. The JobCode column. (Not sure if there is any, from example above)

And this must be used on both sides:

Delivarable:

public DeliverableMap()
{
    ...
    // References( x => x.Deliverable) ... I guess it is typo in the question snippet
    References( x => x.Job) 
        .Column("JobCode") ; // column of table Deliverable
}

Job:

public JobMap()
{
    ...
    HasMany(x => x.Deliverables)
        .KeyColumn("JobCode");  // column of table Deliverable
}

Other words, both column names in this mapping, are in fact the names of one column. Both are mapped to child (Deliverable) table's column.

EXTENDED: based on mapping changes in the question

The Deliverable object, has its ID (column CODE) the same as the reference to Job (column CODE). This seems to be weird.

That's also explaining the fact, that all the Deliverable items inside the JOB collection are the same (identical). Unique Deliverable (defined by its CODE) can be only one. The Job in this scenario cannot have more then one Deliverable (because it's referenced by unique CODE column). It seems like the one-to-one scenario.

The reason why there are more items same is harder to judge. It would be good to see the query you are using.

But I would really twice check the column mapping. Deliverable, should have reference to Job in a column called "JobCODE"... supporting more Delivrables to be related...

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top