1

我使用 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 将尝试更新 Commodity 表,将 ID = 1 的商品的列设置为空。

所以实际上我必须在保存 Lob 之前获取整个对象:

var lob = new Lob();
lob.Commodities = new [] { repostitory.GetCommodit(1) };
repository.SaveLob(lob);

而且我知道商品存在,因为用户刚刚选择了它们。

有可能完成我的任务吗?

4

2 回答 2

3

我假设您的存储库正在幕后调用session.Get<T>(id)。还有session.Load<T>(id).

lob.Commodities = new [] { session.Load<Commodity>(1) };

NHibernate 文档中Load()...

如果该类使用代理进行映射,则 Load() 返回一个对象,该对象是一个未初始化的代理,并且在您调用该对象的方法之前实际上不会访问数据库。如果您希望在不实际从数据库中加载对象的情况下创建与对象的关联,则此行为非常有用。

于 2013-08-28T02:38:00.540 回答
0

Daniel 的回答听起来很有希望,如果在 Save 中代理不会命中数据库来填充实体的所有属性,请告诉我。

另一个答案在 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() 也不会因此而影响数据库:)

编辑:可以使用任何类型的 ID 完成

于 2013-08-28T05:06:57.027 回答