问题似乎很简单但是我在尝试映射这些实体时遇到了很多麻烦。我只是看不出我做错了什么。你能帮助我吗?
我有班级Cliente
:
public class Cliente
{
public Cliente () { }
public virtual int ClienteId { get; set; }
public IList<Medidor> ListaMedidores { get; set; }
public virtual string NumeroMedidor { get; set; }
}
班级Medidor
public class Medidor
{
public Medidor() { }
public virtual string NumeroMedidor { get; set; }
public virtual string MarcaMedidor { get; set; }
public virtual Cliente Cliente { get; set; }
}
我试图像这样映射
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");
}
目标是根据数据库提供我的Medidor
列表。
所以我做了:
Session.Query<Cliente>().Fetch(x => x.ListaMedidores).ToList();
我的列表总是空着。即使有这些表格的数据......我也会感激任何帮助或建议。
此致
编辑我的数据库是这样的:
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) )
给出sql select * from cliente where core_numero_medidor = '3569371'
:
CORE_ID CORE_NUMERO_MEDIDOR
123 3569371
和sql select * from MEDIDOR where numero_medidor = '3569371'
:
NUMERO_MEDIDOR MARCA_MEDIDOR
3569371 general_motors
3569371 kia
3569371 FIAT
所以我想在IList<Medidor> Lista Medidores
课程的Cliente
上获得3个元素..
修改
我改为:
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; }
}
并将ClienteMap
的地图更改为:
Map(x => x.NumeroMedidor).Column("NUMERO_MEDIDOR");
HasMany(x => x.ListaMedid)
.KeyColumns.Add("NUMERO_MEDIDOR")
.Table("MEDID")
.PropertyRef("CoreNumeroCliente")
.Cascade.All();
现在列表获得了预期的记录数,但所有记录都与第一个记录相同。即:
预期
NUMERO_MEDIDOR MARCA_MEDIDOR
3569371 general_motors
3569371 kia
3569371 FIAT
我的结果
NUMERO_MEDIDOR MARCA_MEDIDOR
3569371 general_motors
3569371 general_motors
3569371 general_motors
有什么建议吗?到目前为止,我要感谢@RadimKöhler的帮助。
另一个编辑
我找到了解决方案!
我试图将非唯一列映射为主键...我只是将列更改为真正的主键并且工作正常!
所以现在这是解决方案
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
}
}
这是我的疑问:
Session.Query<CorteReligacao>()
.Fetch(x => x.ListaMedid)
我真的要感谢RadimKöhler的帮助。他的耐心,关注和帮助解决问题的意愿使我缺乏感谢的方式......我只能祝他生活中一切顺利。
我真的希望这个主题可以帮助那些遇到同样问题的人。
问候。
答案 0 :(得分:2)
one-to-many
和many-to-one
始终由一列相关联。这是这样的列,其包含到另一个表/实体的引用ID(外键)。
在我们的情况下,它必须是 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
}
基于扩展问题,当我们可以看到表格的这种结构时
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)
)
数据库引用与C#不同。看起来好像是
表CLIENTE仅引用一个 MEDIDOR,而MEDIDOR有许多CLIENTE。
似乎对象看起来像这样:
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; }
}
,映射应为
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();
}
因为第二个表MEDIDOR没有自己的主键(列NUMERO_MEDIDOR)但它可以包含许多相同的值...来自CLIENT TABLE ...我们应该使用组件映射
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();
}
答案 1 :(得分:1)
毕竟,使用这些SQL脚本(在我的情况下针对SQL Server进行调整)
CREATE TABLE CLIENTE
(
CORE_ID int NOT NULL,
CORE_NUMERO_MEDIDOR VARCHAR(50)
)
CREATE TABLE MEDIDOR
(
NUMERO_MEDIDOR VARCHAR(50),
MARCA_MEDIDOR VARCHAR(50)
)
使用这些实体(所有属性都是虚拟的)
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; }
}
并且只有这一个映射:
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();
}
}
我可以确认,这个查询会起作用:
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);
顺便说一句,这将是 (我的首选) 生成的xml
映射:
<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>
有关文档,请参阅: