使用流畅的nhibernate映射实体oneToMany
问题似乎很简单但是我在尝试映射这些实体时遇到了很多麻烦。 我只是看不出我做错了什么。 你们能帮助我吗?
我有课堂Cliente
:
public class Cliente { public Cliente () { } public virtual int ClienteId { get; set; } public IList 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().Fetch(x => x.ListaMedidores).ToList();
而且我的列表总是空着的。 即使有这些表格的数据……我将不胜感激任何forms的帮助或建议。
问候
编辑
我的数据库是这样的:
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
和select * from MEDIDOR where numero_medidor = '3569371'
的sql select * from MEDIDOR where numero_medidor = '3569371'
:
NUMERO_MEDIDOR MARCA_MEDIDOR 3569371 general_motors 3569371 kia 3569371 FIAT
所以我想在IList Lista Medidores
上的IList Lista Medidores
上获得3个元素。
编辑
我改为:
public class Cliente { public Cliente () { } public virtual int ClienteId { get; set; } public IList 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
地图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 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 { 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 { public MedidorMap() { LazyLoad(); Id(x => x.NumeroMedidor).Column("NUMERO_MEDIDOR"); Map(x => x.MarcaMedidor).Column("MARCA_MEDIDOR"); [...] //Other properties } }
这是我的查询:
Session.Query() .Fetch(x => x.ListaMedid)
我真的很感谢RadimKöhler的帮助。 他的耐心,关注和帮助解决问题的意愿使我缺乏感谢的方式……我只能祝他生活中一切顺利。
我真的希望这个主题可以帮助有同样问题的人。
问候。
毕竟,使用这些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 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 { 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().Fetch(x => x.ListaMedidores).ToList(); var firt = list.First().ListaMedidores.First(); var last = list.First().ListaMedidores.Last(); Assert.IsTrue(firt.MarcaMedidor != last.MarcaMedidor);
顺便说一句,这将是(我的首选)生成的xml
映射:
有关文档,请参阅
7.2。 依赖对象的集合
one-to-many
和many-to-one
总是由一列相关联。 这是这样的列,其中包含对另一个表/实体的引用ID(外键)。
在我们的例子中,它必须是Medidor
表中的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#不同。 似乎,好像
table CLIENTE只引用一个 MEDIDOR,而MEDIDOR只有一个 CLIENTE。
似乎对象应该如下所示:
public class Cliente { ... //public IList ListaMedidores { get; set; } //public Medidor Medidor { get; set; } } public class Medidor { ... //public virtual Cliente Cliente { get; set; } public virtual IList 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(); }