我使用Fluent NHibernate有一个简单的多对多关系,它工作得非常好。
这是我的第一个类映射:
public LobMapping()
{
...
HasManyToMany(x => x.Commodities)
.Table("PPBSYS.LOB_COMMODITY")
.ParentKeyColumn("LOB_ID")
.ChildKeyColumn("COMMODITY_ID")
.Cascade.SaveUpdate()
.LazyLoad();
...
}
这是我的第二个类映射:
public CommodityMapping()
{
...
HasManyToMany(x => x.Lobs)
.Table("PPBSYS.LOB_COMMODITY")
.ParentKeyColumn("COMMODITY_ID")
.ChildKeyColumn("LOB_ID")
.Inverse()
.Cascade.All()
.LazyLoad();
...
}
最后,我的Lob对象有一个商品清单:
public class Lob
{
...
public virtual IEnumerable<Commodity> Commodities { get; set; }
...
}
但是我不满意我必须在Lob类中引用整个商品。我真的很想做:
var lob = new Lob();
lob.Commodities = new [] { new Commodity { CommodityId = 1 }};
repository.SaveLob(lob);
但是如果我运行上面的代码,NHibernate将尝试更新商品表,将ID设置为1的商品的列为空。
所以实际上我必须在保存Lob之前得到整个对象:
var lob = new Lob();
lob.Commodities = new [] { repostitory.GetCommodit(1) };
repository.SaveLob(lob);
我知道商品存在,因为用户只是选择了它们。
有可能完成我的任务吗?
答案 0 :(得分:3)
我假设您的存储库正在调用session.Get<T>(id)
。还有session.Load<T>(id)
。
lob.Commodities = new [] { session.Load<Commodity>(1) };
来自NHibernate documentation on Load()
...
如果使用代理映射类,则Load()将返回一个未初始化的代理对象,并且在调用对象的方法之前不会实际访问数据库。如果您希望创建与对象的关联而不实际从数据库加载它,则此行为非常有用。
答案 1 :(得分:0)
丹尼尔的回答听起来很有希望,请告诉我如果在保存代理中不会命中数据库来填充实体的所有属性。
另一个答案是对Nhibernate有点强有力,我测试了它并且它正在工作, 工作代码:
public class Com
{
public virtual Guid ID { get; set; }
public virtual string Name { get; set; }
public virtual IList<Lob> Lobs { get; set; }
}
public class Lob
{
public virtual Guid ID { get; set; }
public virtual string Name { get; set; }
public virtual IList<Com> Coms { get; set; }
}
class LobMap : ClassMap<Lob>
{
public LobMap()
{
Id(x => x.ID).GeneratedBy.GuidComb();
Map(x => x.Name);
HasManyToMany(x => x.Coms)
.Table("LOB_COM")
.ParentKeyColumn("LOB_ID")
.ChildKeyColumn("COM_ID")
.Cascade.SaveUpdate()
.LazyLoad();
}
}
class ComMap : ClassMap<Com>
{
public ComMap()
{
Id(x => x.ID).GeneratedBy.GuidComb();
Map(x => x.Name);
HasManyToMany(x => x.Lobs)
.Table("LOB_COM")
.ParentKeyColumn("COM_ID")
.ChildKeyColumn("LOB_ID")
.Inverse()
.Cascade.All()
.LazyLoad();
}
}
现在 - 我设置了一个虚拟实体来模仿连接表并映射它:
public class ComLobConnection
{
public virtual Guid ComID { get; set; }
public virtual Guid LobID { get; set; }
}
public class ComLobConnectionMap : ClassMap<ComLobConnection>
{
public ComLobConnectionMap()
{
Table("LOB_COM");
Id();
Map(x => x.ComID,"COM_ID");
Map(x => x.LobID,"LOB_ID");
}
}
请注意,我正在映射到与ManyToMany完全相同的字段和表,没有设置ID(这是空的Id()调用)
现在剩下的就是保存一个ComLobConnection,它将被添加到Com.Lobs和Lob.Coms
保存了一些测试Com,Lob
var testCom = new Com() { Name = "TestCom" };
var testLob = new Lob() { Name = "TestLob" };
session.SaveOrUpdate(testCom);
session.SaveOrUpdate(testLob);
保存后 - 获取其ID并保存连接以进行测试
var testConnection = new ComLobConnection()
{
ComID = Guid.Parse("D3559F53-8871-45E9-901D-A22800806567"),
LobID = Guid.Parse("D372D430-2E61-44F2-BA89-A228008065F1")
};
session.SaveOrUpdate(testConnection);
这在很多人的桌子上取得了新纪录,并且在获得Lob和Com之后工作。
我不推荐这个:),它只是让我感兴趣,如果它可以做到,它可以。 这样,您就不会点击数据库来加载您知道存在的Coms或Lobs来保存它们的连接。
希望Load()也不会因此而命中DB:)
编辑:可以使用任何类型的ID
完成