Nhibernate 持久性规范与逆

Nhibernate 持久性规范与逆,nhibernate,collections,fluent-nhibernate,inverse,Nhibernate,Collections,Fluent Nhibernate,Inverse,很久以前,我已经在Fluent NH小组中发布了这篇文章,但直到今天才得到任何答案。所以,问题是:我定义了一对多关系,并且一侧设置了反向标志。映射代码如下所示: public class MapeamentoReceita : ClassMap<Receita> { public MapeamentoReceita() { Table("Receitas"); Not.LazyLoad(); Id(rec => rec.

很久以前,我已经在Fluent NH小组中发布了这篇文章,但直到今天才得到任何答案。所以,问题是:我定义了一对多关系,并且一侧设置了反向标志。映射代码如下所示:

public class MapeamentoReceita : ClassMap<Receita> {
    public MapeamentoReceita() {
        Table("Receitas");
        Not.LazyLoad();

        Id(rec => rec.Id, "IdReceita")
            .GeneratedBy
            .HiLo("TabelaHilo", "ProximoHi", "1000", "Tabela='receitas'")
            .Default(0);
        Version(rec => rec.Versao);

        //other props go here
        HasMany(rec => rec.Imagens)
            .Access.CamelCaseField((Prefix.Underscore))
            .AsBag()
            .Cascade.All()
            .KeyColumn("IdReceita")
            .Not.LazyLoad()
            .Inverse();
    }
}
 public class MapeamentoImagem : ClassMap<Imagem> {
    public MapeamentoImagem() {
        Table("Imagens");
        Not.LazyLoad();
        Id(img => img.Id, "IdImagem")
            .GeneratedBy
            .HiLo("TabelaHiLo", "ProximoHi", "1000", "Tabela='imagens'")
            .Default(0);
        Map(img => img.Bytes)
            .CustomSqlType("image")
            .CustomType<Byte[]>()
            .LazyLoad()
            .Length(2000000000)
            .Not.Nullable()
            .Not.Update();

        References(img => img.Receita)
            .Column("IdReceita")
            .Cascade.None();
    }
}
public类映射eamentoreceita:ClassMap{
公共地图{
表(“收据”);
不是。懒汉();
Id(记录=>记录Id,“IdReceita”)
.产生于
.HiLo(“TabelaHilo”、“ProximoHi”、“1000”、“Tabela='receitas'))
.违约(0);
版本(rec=>rec.Versao);
//其他道具在这里
HasMany(rec=>rec.Imagens)
.Access.CamelCaseField((前缀.下划线))
.AsBag()
.Cascade.All()
.KeyColumn(“IdReceita”)
.Not.LazyLoad()
.Inverse();
}
}
现在,Imagem的映射如下所示:

public class MapeamentoReceita : ClassMap<Receita> {
    public MapeamentoReceita() {
        Table("Receitas");
        Not.LazyLoad();

        Id(rec => rec.Id, "IdReceita")
            .GeneratedBy
            .HiLo("TabelaHilo", "ProximoHi", "1000", "Tabela='receitas'")
            .Default(0);
        Version(rec => rec.Versao);

        //other props go here
        HasMany(rec => rec.Imagens)
            .Access.CamelCaseField((Prefix.Underscore))
            .AsBag()
            .Cascade.All()
            .KeyColumn("IdReceita")
            .Not.LazyLoad()
            .Inverse();
    }
}
 public class MapeamentoImagem : ClassMap<Imagem> {
    public MapeamentoImagem() {
        Table("Imagens");
        Not.LazyLoad();
        Id(img => img.Id, "IdImagem")
            .GeneratedBy
            .HiLo("TabelaHiLo", "ProximoHi", "1000", "Tabela='imagens'")
            .Default(0);
        Map(img => img.Bytes)
            .CustomSqlType("image")
            .CustomType<Byte[]>()
            .LazyLoad()
            .Length(2000000000)
            .Not.Nullable()
            .Not.Update();

        References(img => img.Receita)
            .Column("IdReceita")
            .Cascade.None();
    }
}
公共类映射eamentoimagem:ClassMap{
公共MapeamentoImagem(){
表(“图像”);
不是。懒汉();
Id(img=>img.Id,“IdImagem”)
.产生于
.HiLo(“TabelaHiLo”、“ProximoHi”、“1000”、“Tabela='imagens'))
.违约(0);
映射(img=>img.Bytes)
.CustomSqlType(“图像”)
.CustomType()
.LazyLoad()
.长度(2000000000)
.Not.Nullable()
.Not.Update();
参考(img=>img.Receita)
.栏(“IdReceita”)
.Cascade.None();
}
}
下面是测试这些类持久性的代码:

 new PersistenceSpecification<Receita>(sess)
    .CheckList(rec => rec.Imagens, 
               _imagens, 
               (receita, imagem) => receita.AdicionaImagem(imagem))
    .VerifyTheMappings();
新的PersistenceSpecification(sess)
.检查表(记录=>记录图像,
_imagens,
(receita,imagem)=>receita.AdicionaImagem(imagem))
.验证应用程序();
即使Inverse处于“打开”状态,PersistenceSpecification也会在插入Receita之前尝试插入Imagem。由于IdReceita是配置为不接受null的外键,因此我最终遇到了一个异常。我尝试过编写使用receita的“真实世界代码”,它可以正常工作(我打开了SQL,我可以看到在这种情况下,receita应该插入到Imagem之前)

由于FH group上没有人回答这个问题,我想知道是否有人可以确认PersistenceSpecification行为是一个bug

谢谢。

试试:

    References(img => img.Receita)
        .Column("IdReceita")
        .Not.Nullable();

我的猜测是,您的真实世界代码首先保存Recieta,以便以正确的顺序发布插入。如果您先更改该代码以保存Imagem,您将得到相同的错误,因为NHibernate将尝试插入Imagem,然后使用外键更新它。

您可以更改
Imagem的映射。

References(img => img.Receita)
            .Column("IdReceita")
            .Cascade.SaveUpdate();
这将在
Imagem

References(img => img.Receita)
            .Column("IdReceita")
            .Cascade.SaveUpdate();
我发现,
PersistanceSpecification
适用于相当直接的关系,但如果您有复杂的对象图,则必须在所有对象上启用级联。不过,您的场景相当简单,因此这一小小的更改应该允许您使用
persistencespecification
对其进行测试

编辑: 还要确保在
AdicionaImagem
功能中设置了图像的父级。以下是一个例子:

public virtual void AdicionaImagem(Imagem newImagem)
{
    newImagem.Receita = this;
    imagems.Add(newImagem);
}

你这样试过吗

var receita = BuildMeAReceita();
var imagems = BuildSomeImagems();
foreach(var imagem in imagems){
    receita.AdicionaImagem(imagem);
}
new PersistenceSpecification<Receita>(sess)
.VerifyTheMappings(receita);
var receita=BuildMeAReceita();
var imagems=BuildSomeImagems();
foreach(imagems中的var imagem){
AdicionaImagem(imagem);
}
新PersistenceSpecification(sess)
.验证申请(收据);

您的代码中可能存在两个问题

  • Imagem.Bytes属性是延迟加载的,但是Imagem的延迟加载 istself已禁用。这意味着没有为Imagem生成代理 实例和字节不能延迟加载:任务不可能完成(至少我现在不确定)。 从数据库(
    session.Get(id);
    )简单加载会导致 例外情况如下:
    无效强制转换(检查映射是否存在属性类型不匹配);照排机。
    解决方案是在Imagem上启用延迟加载,或在字节属性上禁用延迟加载
  • PersistenceSpecification从数据库加载测试的实体。这意味着默认的相等比较器不可用 工作顺利。您需要提供自己的相等比较器来解决 此问题(有关更多详细信息,请查看此问题)

  • 下面是和实体、和代码段的实现。该代码在NH3.1和FNH1.2中运行良好。请告诉我您的代码是否与这些代码片段有所不同。

    你好,杰米。尝试了它,但它不起作用(最终使用非null属性引用null或瞬时值Receita)。这是否意味着PersistenceSpecification不是测试映射的好方法???您可以发布测试中填充
    \u imagens
    字段的代码吗?还有
    Receita.AdicionalImagem(Imagem)
    ?谢谢,你好,科尔。完成了,但它仍然在插入Receita之前插入imagem。我相信问题在于PersistenceSpecification运行插入的方式(因为我启用了SQL跟踪,很容易看出在我的应用程序中使用它最终会做正确的事情,即在每个Imagem实例之前插入Receita)。您使用的是哪种版本的Fluent NH?如果您将映射更改为上述内容并尝试保存
    Imagen
    对象(在PersistanceSpecification之外),它是否会创建
    Receita
    <代码>会话.保存(testImagen)
    同样在您的
    AdicionaImagem
    函数中,您是否在此处设置父引用?请看我的编辑为例。你好,科尔。是的,当我打开一个事务并保存一个Receita时,它将首先插入Receita,然后才插入Imagem实例。哦,是的,我正在这样做:public void AdicionaImagem(Imagem Imagem){Contract.Requires(Imagem!=null);Contract.Requires(image