Mapping oneToMany object to smooth nhibernate

The problem seems simple, but I'm having so many problems trying to match these objects. I just can't see what I am doing wrong. Can you guys help me?

I have a class Cliente

:

public class Cliente
{    
    public Cliente () { }
    public virtual int ClienteId { get; set; }  
    public IList<Medidor> ListaMedidores { get; set; }   
    public virtual string NumeroMedidor { get; set; }       
}

      

And class Medidor

public class Medidor
{
    public Medidor() { }
    public virtual string NumeroMedidor { get; set; }
    public virtual string MarcaMedidor { get; set; }
    public virtual Cliente Cliente { get; set; }
}

      

I tried to display like this

public ClienteMap()
{
    Map(x => x.NumeroMedidor).Column("CORE_NUMERO_MEDIDOR");
    HasMany(x => x.ListaMedidores)
        .KeyColumn("NUMERO_MEDIDOR").Inverse().Cascade.All();
}


public MedidorMap()
{
    Table("medidor");
    LazyLoad();

    Id(x => x.NumeroMedidor).Column("NUMERO_MEDIDOR");
    Map(x => x.TipoMedidor).Column("TIPO_MEDIDOR");
    References(x => x.Cliente).Column("CORE_NUMERO_MEDIDOR");
}

      

The target is my list Medidor

according to the database. So I did:

Session.Query<Cliente>().Fetch(x => x.ListaMedidores).ToList();

      

And I get the list always empty. Even with the data on these tables ... I would appreciate any help or suggestion.

Hello

EDIT

My database is like this:

CREATE TABLE CLIENTE
(
  CORE_ID NUMBER NOT NULL,
  CORE_NUMERO_MEDIDOR VARCHAR2 (50 BYTE)
)

CREATE TABLE MEDIDOR
(
  NUMERO_MEDIDOR VARCHAR2 (50 BYTE),
  MARCA_MEDIDOR VARCHAR2 (50 BYTE)
)

Given sql select * from cliente where core_numero_medidor = '3569371'

:

CORE_ID CORE_NUMERO_MEDIDOR
123     3569371

      

and sql select * from MEDIDOR where numero_medidor = '3569371'

:

NUMERO_MEDIDOR MARCA_MEDIDOR
3569371        general_motors
3569371        kia
3569371        FIAT

      

So, I have to get 3 elements in class IList<Medidor> Lista Medidores

on Cliente

..

EDIT

I changed to this:

public class Cliente
{    
    public Cliente () { }
    public virtual int ClienteId { get; set; }  
    public IList<Medidor> ListaMedidores { get; set; }   
    public virtual string NumeroMedidor { get; set; }       
}
public class Medidor
{
    public Medidor() { }
    public virtual string NumeroMedidor { get; set; }
    public virtual string MarcaMedidor { get; set; }
}

      

And changed the map ClienteMap

to:

Map(x => x.NumeroMedidor).Column("NUMERO_MEDIDOR");    
HasMany(x => x.ListaMedid)
            .KeyColumns.Add("NUMERO_MEDIDOR")
            .Table("MEDID")
            .PropertyRef("CoreNumeroCliente")
            .Cascade.All();

      

and now the list gets the expected number of entries, but they are all the same as the first ones. i.e:

Expected

NUMERO_MEDIDOR MARCA_MEDIDOR
3569371        general_motors
3569371        kia
3569371        FIAT

      

My result

NUMERO_MEDIDOR MARCA_MEDIDOR
3569371        general_motors
3569371        general_motors
3569371        general_motors

      

Any suggestions? I'd like to thank @Radim Köhler for the help.

OTHER IMAGE

I found a solution!

I was trying to map a non-unique column as the primary key ... I just changed the column to a real primary key and it works!

So now the solution

public class Cliente
{    
    public Cliente () { }
    public virtual int ClienteId { get; set; }  
    public IList<Medidor> ListaMedidores { get; set; }   
    public virtual string NumeroMedidor { get; set; }       
}
public class Medidor
{
    public Medidor() { }
    public virtual string NumeroMedidor { get; set; }
    public virtual string MarcaMedidor { get; set; }
}

public class ClienteMap : ClassMap<Cliente>
{
    public ClienteMap()
    {
        Map(x => x.NumeroMedidor).Column("NUMERO_MEDIDOR");    
        HasMany(x => x.ListaMedid)
            .KeyColumns.Add("NUMERO_MEDIDOR")
            .Table("MEDID")
            .PropertyRef("CoreNumeroCliente")
            .Cascade.All();
    }
}

public class MedidorMap : ClassMap<Medidor>
{
    public MedidorMap()
    {
        LazyLoad();

        Id(x => x.NumeroMedidor).Column("NUMERO_MEDIDOR");
        Map(x => x.MarcaMedidor).Column("MARCA_MEDIDOR");
        [...] //Other properties
    }
}

      

And here is my request:

Session.Query<CorteReligacao>()
                .Fetch(x => x.ListaMedid)

      

I would really like to thank Radim Köhler for his help. His patience, attention and willingness to help solve a problem leave me with a lack of gratitude. I can only wish him all the best in life.

And I really hope this thread can help people with the same problem.

Sincerely.

+3


source to share


2 answers


In the end, with these SQL scripts (adjust for SQL Server in my case)

CREATE TABLE CLIENTE
(
  CORE_ID                      int           NOT NULL,
  CORE_NUMERO_MEDIDOR          VARCHAR(50)
)

CREATE TABLE MEDIDOR
(
  NUMERO_MEDIDOR  VARCHAR(50),
  MARCA_MEDIDOR   VARCHAR(50)
)

      

With these entities (all properties are virtual)

public class Cliente
{    
    public virtual int ClienteId { get; set; }  
    public virtual IList<Medidor> ListaMedidores { get; set; }   
    public virtual string NumeroMedidor { get; set; }       
}
public class Medidor
{
    public virtual string NumeroMedidor { get; set; }
    public virtual string MarcaMedidor { get; set; }
    public virtual Cliente Cliente { get; set; }
}

      

and only this :

public class ClienteMap: ClassMap<Cliente>
{
    public ClienteMap()
    {
        Table("CLIENTE");
        Id(x => x.ClienteId, "CORE_ID");
        Map(x => x.NumeroMedidor).Column("CORE_NUMERO_MEDIDOR");
        HasMany(x => x.ListaMedidores)
            .KeyColumn("NUMERO_MEDIDOR")
            .Component(com =>
            {
                com.ParentReference(y => y.Cliente);
                com.Map(y => y.MarcaMedidor, "MARCA_MEDIDOR");
            })
            .PropertyRef("NumeroMedidor")
            .Table("MEDIDOR")
            // .Inverse() // NO INVERSE, won't work
            .Cascade.All();
    }
}

      



I can confirm that this query will work:

var list = session.Query<Cliente>().Fetch(x => x.ListaMedidores).ToList();
var firt = list.First().ListaMedidores.First();
var last = list.First().ListaMedidores.Last();
Assert.IsTrue(firt.MarcaMedidor != last.MarcaMedidor);

      

By the way, this would be the (my preferred) generated xml

mapping:

<class xmlns="urn:nhibernate-mapping-2.2" name="Cliente" table="CLIENTE">
    <id name="ClienteId" type="System.Int32">
      <column name="CORE_ID" />
      <generator class="identity" />
    </id>
    <bag cascade="all" name="ListaMedidores" table="MEDIDOR">
      <key property-ref="NumeroMedidor">
        <column name="NUMERO_MEDIDOR" />
      </key>
      <composite-element class="Medidor">
        <parent name="Cliente" />
        <property name="MarcaMedidor" type="System.String">
          <column name="MARCA_MEDIDOR" />
        </property>
      </composite-element>
    </bag>
    <property name="NumeroMedidor" type="System.String">
      <column name="CORE_NUMERO_MEDIDOR" />
    </property>
</class>

      

For documentation see:

7.2. Collections of dependent objects

+1


source


one-to-many

and are many-to-one

always linked by one column. It is such a column that contains the reference identifier (foreign key) for another table / object.

In our case, this is a column in the table , and its name will be . The display should look like this: Medidor

"CORE_NUMERO_MEDIDOR"

public ClienteMap()
{
    ...
    HasMany(x => x.ListaMedidores)
       //.KeyColumn("NUMERO_MEDIDOR")
       .KeyColumn("CORE_NUMERO_MEDIDOR") // column in other table
       .Inverse().Cascade.All();
}


public MedidorMap()
{
    ...
    References(x => x.Cliente)
        .Column("CORE_NUMERO_MEDIDOR");  // column in this table
}

      

OUTGOING

Based on the extended question, when can we see this table structure

CREATE TABLE CLIENTE
(
  CORE_ID                      NUMBER           NOT NULL,
  CORE_NUMERO_MEDIDOR          VARCHAR2(50 BYTE)
)

CREATE TABLE MEDIDOR
(
  NUMERO_MEDIDOR  VARCHAR2(50 BYTE),
  MARCA_MEDIDOR   VARCHAR2(50 BYTE)
)

      

That the DB link is different from C #. It seems as if

the CLIENTE table only refers to one MEDIDOR, while the MEDIDOR has many CLIENTEs.



It seems that the objects should look like this:

public class Cliente
{    
    ...
    //public IList<Medidor> ListaMedidores { get; set; }    
    //public Medidor Medidor { get; set; }    
}

public class Medidor
{
    ...
    //public virtual Cliente Cliente { get; set; }
    public virtual IList<Cliente> Clientes { get; set; }
}

      

and the display should be

public ClienteMap()
{
    ...
    References(x => x.Medidor, "CORE_NUMERO_MEDIDOR");
}


public MedidorMap()
{
    ...
    Id(x => x.NumeroMedidor).Column("NUMERO_MEDIDOR")
                               // column in this table to be compared
    HasMany(x => x.Clientes)
       .KeyColumn("CORE_NUMERO_MEDIDOR") // with column in other table
       .Inverse().Cascade.All();
}

      

ANOTHER EXTEND

Since the second MEDIDOR table does not have its own primary key (NUMERO_MEDIDOR column), but can contain many of the same values ​​... based on CLIENT TABLE ... we have to use component mapping

public ClienteMap()
{
    ...
    Map(x => x.NumeroMedidor).Column("CORE_NUMERO_MEDIDOR");
    HasMany(x => x.ListaMedidores)
        .Component(com =>
        {
            com.Parent(y => y.Cliente, "NUMERO_MEDIDOR")
               .PropertyRef("NumeroMedidor")
               ;
            com.Map(y => y.MarcaMedidor, "MARCA_MEDIDOR");
        })
        .PropertyRef("NumeroMedidor")
        .Table("MEDIDOR")
       // .Inverse() // NO INVERSE, won't work
       .Cascade.All();

}

      

+2


source







All Articles