使用流利的 nhibernate 映射实体 oneToMany
Mapping entity oneToMany with fluent nhibernate
问题看起来很简单,但是我在尝试映射这些实体时遇到了很多麻烦。我只是看不出我做错了什么。你们能帮帮我吗?
我有 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; }
}
和classMedidor
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
class..
上得到 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
有什么建议吗?我要感谢@Radim Kö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)
非常感谢 Radim Köhler 的帮助。他的耐心、关注和帮助解决问题的意愿让我缺乏感谢的方式。我只能祝他生活中一切顺利。
我真的希望这个帖子可以帮助遇到同样问题的人。
此致。
one-to-many
和 many-to-one
始终由一列相关。这是这样的列,其中包含对另一个 table / 实体的引用 ID(外键)。
在我们的例子中,它必须是 Medidor
的 table 中的列,其名称为 "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
}
延长
基于扩展问题,当我们可以看到 tables
的这种结构时
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)
)
DB 引用与 C# 中的不同。好像
table CLIENTE references just one MEDIDOR, while MEDIDOR has many CLIENTEs.
对象看起来应该是这样的:
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();
}
另一个扩展
因为第二个 table 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();
}
毕竟,使用这些 SQL 脚本 (在我的情况下针对 SQL 服务器进行调整)
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>
有关文档,请参阅:
问题看起来很简单,但是我在尝试映射这些实体时遇到了很多麻烦。我只是看不出我做错了什么。你们能帮帮我吗?
我有 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; }
}
和classMedidor
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
class..
编辑
我改成了这样:
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
有什么建议吗?我要感谢@Radim Kö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)
非常感谢 Radim Köhler 的帮助。他的耐心、关注和帮助解决问题的意愿让我缺乏感谢的方式。我只能祝他生活中一切顺利。
我真的希望这个帖子可以帮助遇到同样问题的人。
此致。
one-to-many
和 many-to-one
始终由一列相关。这是这样的列,其中包含对另一个 table / 实体的引用 ID(外键)。
在我们的例子中,它必须是 Medidor
的 table 中的列,其名称为 "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
}
延长
基于扩展问题,当我们可以看到 tables
的这种结构时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)
)
DB 引用与 C# 中的不同。好像
table CLIENTE references just one MEDIDOR, while MEDIDOR has many CLIENTEs.
对象看起来应该是这样的:
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();
}
另一个扩展
因为第二个 table 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();
}
毕竟,使用这些 SQL 脚本 (在我的情况下针对 SQL 服务器进行调整)
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>
有关文档,请参阅: