Nhibernate 中 select 之后的意外批量更新命令
Unexpected batch update commands after select in Nhibernate
我发现 NHibernate 在 select 之后进行了意外更新。
实体:
public class BasePriceRule : BaseEntity
{
public virtual string Name { get; set; }
public virtual string RuleString { get; set; }
public virtual TypePriceRule Type { get; }
public virtual DateTime Date { get; set; } = DateTime.Now;
}
public class ProductGroupRule : BasePriceRule
{
public virtual ProductGroup ProductGroup { get; set; }
public override TypePriceRule Type => TypePriceRule.ProductGroup;
}
public class ProductGroup : BaseEntity
{
public virtual string Code { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual UoM UoM { get; set; }
public virtual CustomProductType Type { get; set; }
}
映射:
public class BasePriceRuleMap : ClassMap<BasePriceRule>
{
public BasePriceRuleMap()
{
Table("PriceRule");
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.RuleString).Length(4096);
DiscriminateSubClassesOnColumn("Type");
Map(x => x.Type).CustomType<TypePriceRule>().ReadOnly().Access.None().Not.Nullable();
Map(x => x.Date).Not.Nullable().Default("CURRENT_TIMESTAMP");
}
}
public ProductGroupRuleMap()
{
KeyColumn("Id");
References(x => x.ProductGroup).Fetch.Join()/*.Not.Update()*/;
DiscriminatorValue((int)TypePriceRule.ProductGroup);
}
public ProductGroupMap()
{
Id(x => x.Id);
Map(x => x.Code).Unique();
Map(x => x.Name);
Map(x => x.Description);
Map(x => x.Type).CustomType<int>();
References(x => x.UoM);
}
所以当我 运行 这个最简单的查询时:
_session.QueryOver<ProductGroupRule>();
或者这样:
_session.QueryOver<ProductGroupRule>().Fetch(x => x.ProductGroup).Eager.List();
我收到这个生成的 sql:
2016-11-18 17:17:39.3103 NHibernate.SQL SELECT this_.Id as Id62_1_, this_.Name as Name62_1_, this_.RuleString as RuleString62_1_, this_.Type as Type62_1_, this_.ProductGroup_id as ProductG6_62_1_, productgro2_.Id as Id66_0_, productgro2_.Code as Code66_0_, productgro2_.Name as Name66_0_, productgro2_.Description as Descript4_66_0_, productgro2_.Type as Type66_0_, productgro2_.UoM_id as UoM6_66_0_ FROM PriceRule this_ left outer join [ProductGroup] productgro2_ on this_.ProductGroup_id=productgro2_.Id WHERE this_.Type='2'
2016-11-18 17:17:39.4474 NHibernate.SQL Batch commands:
command 0:UPDATE [ProductGroup] SET Code = @p0, Name = @p1, Description = @p2, Type = @p3, UoM_id = @p4 WHERE Id = @p5;
command 1:UPDATE [ProductGroup] SET Code = @p0, Name = @p1, Description = @p2, Type = @p3, UoM_id = @p4 WHERE Id = @p5;
--Numbers of commands are equal to the amount of records in PriceRule table
我试过:
- Enable/disable延迟加载
- 将级联更改为 None,逐出
- 为产品组参考设置 Not.Update()
- 使用未来<>
但还是摆脱不了。
谁能解释为什么会出现这些更新命令?
我的猜测是发生了自动刷新,NH 认为那些 ProductGroup
对象出于某种原因是脏的。恕我直言,最好的做法是通过 log4net enable logging 并获得一些详细的诊断信息。 NH 的日志记录非常好。你应该能够通过那个找到它的底部。
在ProductGroup
定义中,有一个属性,不能为null - CustomProductType Type
public class ProductGroup : BaseEntity
{
public virtual string Code { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual UoM UoM { get; set; }
// this cannot be null
public virtual CustomProductType Type { get; set; }
}
C# 会将其设置为默认值(通常是第一个 enum
)
但似乎在数据库中,相关列包含空值。对于 NHibernate,它是一个标志:1) 加载的是 NULL,但在检查对象时 - 2) 它已分配了一个值。
所以,对象是脏的,因为 Flush 模式默认为 AUTO ...它试图使 DB 和 C# 实例保持同步
只需更改映射
public virtual CustomProductType? Type { get; set; }
我发现 NHibernate 在 select 之后进行了意外更新。
实体:
public class BasePriceRule : BaseEntity
{
public virtual string Name { get; set; }
public virtual string RuleString { get; set; }
public virtual TypePriceRule Type { get; }
public virtual DateTime Date { get; set; } = DateTime.Now;
}
public class ProductGroupRule : BasePriceRule
{
public virtual ProductGroup ProductGroup { get; set; }
public override TypePriceRule Type => TypePriceRule.ProductGroup;
}
public class ProductGroup : BaseEntity
{
public virtual string Code { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual UoM UoM { get; set; }
public virtual CustomProductType Type { get; set; }
}
映射:
public class BasePriceRuleMap : ClassMap<BasePriceRule>
{
public BasePriceRuleMap()
{
Table("PriceRule");
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.RuleString).Length(4096);
DiscriminateSubClassesOnColumn("Type");
Map(x => x.Type).CustomType<TypePriceRule>().ReadOnly().Access.None().Not.Nullable();
Map(x => x.Date).Not.Nullable().Default("CURRENT_TIMESTAMP");
}
}
public ProductGroupRuleMap()
{
KeyColumn("Id");
References(x => x.ProductGroup).Fetch.Join()/*.Not.Update()*/;
DiscriminatorValue((int)TypePriceRule.ProductGroup);
}
public ProductGroupMap()
{
Id(x => x.Id);
Map(x => x.Code).Unique();
Map(x => x.Name);
Map(x => x.Description);
Map(x => x.Type).CustomType<int>();
References(x => x.UoM);
}
所以当我 运行 这个最简单的查询时:
_session.QueryOver<ProductGroupRule>();
或者这样:
_session.QueryOver<ProductGroupRule>().Fetch(x => x.ProductGroup).Eager.List();
我收到这个生成的 sql:
2016-11-18 17:17:39.3103 NHibernate.SQL SELECT this_.Id as Id62_1_, this_.Name as Name62_1_, this_.RuleString as RuleString62_1_, this_.Type as Type62_1_, this_.ProductGroup_id as ProductG6_62_1_, productgro2_.Id as Id66_0_, productgro2_.Code as Code66_0_, productgro2_.Name as Name66_0_, productgro2_.Description as Descript4_66_0_, productgro2_.Type as Type66_0_, productgro2_.UoM_id as UoM6_66_0_ FROM PriceRule this_ left outer join [ProductGroup] productgro2_ on this_.ProductGroup_id=productgro2_.Id WHERE this_.Type='2'
2016-11-18 17:17:39.4474 NHibernate.SQL Batch commands:
command 0:UPDATE [ProductGroup] SET Code = @p0, Name = @p1, Description = @p2, Type = @p3, UoM_id = @p4 WHERE Id = @p5;
command 1:UPDATE [ProductGroup] SET Code = @p0, Name = @p1, Description = @p2, Type = @p3, UoM_id = @p4 WHERE Id = @p5;
--Numbers of commands are equal to the amount of records in PriceRule table
我试过:
- Enable/disable延迟加载
- 将级联更改为 None,逐出
- 为产品组参考设置 Not.Update()
- 使用未来<>
但还是摆脱不了。
谁能解释为什么会出现这些更新命令?
我的猜测是发生了自动刷新,NH 认为那些 ProductGroup
对象出于某种原因是脏的。恕我直言,最好的做法是通过 log4net enable logging 并获得一些详细的诊断信息。 NH 的日志记录非常好。你应该能够通过那个找到它的底部。
在ProductGroup
定义中,有一个属性,不能为null - CustomProductType Type
public class ProductGroup : BaseEntity
{
public virtual string Code { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual UoM UoM { get; set; }
// this cannot be null
public virtual CustomProductType Type { get; set; }
}
C# 会将其设置为默认值(通常是第一个 enum
)
但似乎在数据库中,相关列包含空值。对于 NHibernate,它是一个标志:1) 加载的是 NULL,但在检查对象时 - 2) 它已分配了一个值。
所以,对象是脏的,因为 Flush 模式默认为 AUTO ...它试图使 DB 和 C# 实例保持同步
只需更改映射
public virtual CustomProductType? Type { get; set; }