Fluent NHibernate-不必要的更新

Fluent NHibernate-不必要的更新,nhibernate,fluent-nhibernate,nhibernate-mapping,fluent-nhibernate-mapping,Nhibernate,Fluent Nhibernate,Nhibernate Mapping,Fluent Nhibernate Mapping,在注册和项之间的单向多对多关系中,注册有一个ISet项,并且项没有对注册的引用(这不是探索对象图的有用方法),当我查看生成的SQL时,我看到 INSERT INTO Registrations_Items (RegistrationId, ItemId) VALUES (@p0, @p1);@p0 = 1 [Type: Int32 (0)], @p1 = 1 [Type: Int32 (0)] UPDATE Items SET Price = @p0, Name = @p1, [...], Li

注册
之间的单向多对多关系中,
注册
有一个
ISet项
,并且
没有对注册的引用(这不是探索对象图的有用方法),当我查看生成的SQL时,我看到

INSERT INTO Registrations_Items (RegistrationId, ItemId) VALUES (@p0, @p1);@p0 = 1 [Type: Int32 (0)], @p1 = 1 [Type: Int32 (0)]
UPDATE Items SET Price = @p0, Name = @p1, [...], ListIndex = @p5, EventId = @p6 WHERE ItemId = @p7
传递给更新的参数是正确的,但该项没有任何更改,因此不需要更新

映射是通过将此覆盖自动映射到
注册
,而对
不进行覆盖。DB模式看起来完全正确。我删除了所有的约定并再次测试,行为仍然存在,所以我的任何映射约定都不会这样做

mapping.hasmanytomy(e=>e.ItemsPurchased).AsSet().Cascade.All().Not.Inverse()

为什么NHibernate要打这个
UPDATE
电话,我能做些什么来阻止它?这并不真的伤害到任何东西,但它表明我做错了什么,所以我想知道是什么

编辑: 根据下面的注释,我创建了一个单元测试,它创建一个
事件
必须属于
事件
),向其中添加两个
项,从会话中退出第一个并刷新会话,然后通过其ID返回第一个

我注意到下面的“选择项目”行中有一些奇怪的东西(从底部算起第二个)

表已正确创建:

create table Items (
    ItemId INT IDENTITY NOT NULL,
   Price NUMERIC(19,5) not null,
   Name NVARCHAR(255) not null,
   StartDate DATETIME null,
   EndDate DATETIME null,
   ExternalID NVARCHAR(255) not null,
   ListIndex INT not null,
   EventId INT not null,
   primary key (ItemId)
)

日期时间故意为空,因为项目可能不需要特定于日期(例如“早起登记”)。

这称为:幻影更新,它通常与对象的映射相关

这是主要原因:

假设我们有一个这样的物体

public class Product
{
   public Guid Id { get; set; }
   public int ReorderLevel { get; set; }
   public decimal UnitPrice { get; set; }
}
和一张地图:

public class ProductMap : ClassMap<Product>
{
   public ProductMap()
   {
      Not.LazyLoad();
      Id(x => x.Id).GeneratedBy.GuidComb();
      Map(x => x.ReorderLevel);
      Map(x => x.UnitPrice).Not.Nullable();
   }
}
如上所述(下面是谁知道呢?看看我在另一个答案上留下的评论),我注意到
CanGenerateDatabaseSchema
单元测试和
CanGetItem
单元测试之间的区别是,一个给我
DECIMAL(6,2)
,另一个给我
DECIMAL(19,0)

我仔细研究了一下,发现
CanGenerateDatabaseSchema
使用的是我的“真实”配置(来自Web项目),而另一个测试使用的是我的“单元测试”配置。我的单元测试正在针对Sql Server CE运行。。。当我更改单元测试以使用与真实数据库(SQLServer2005)相同的配置时,虚拟更新突然消失


所以,如果其他人遇到意外的幻影更新和小数。。。检查您是否正在使用Sql Server CE。由于测试实际上是通过的(说它失败的评论是不正确的,它没有失败,只是做了额外的工作),我想我会接受它,尽管为什么Sql CE忽略我的配置是一个好问题,可能是NH或FNH错误。

要确认一个虚拟更新问题,
获取相同的项目,并检查是否在刷新/提交时发布更新。然后,您可以排除任何多对多级联问题。这可能与具有十进制字段有关吗?谷歌提供了一些幻影更新和十进制的结果,但我还没有弄清他们都说了些什么。我已经有了一个
ColumnNullConvention',它确保任何标记为
DataAnnotations.Required`的字段都声明为非空。我编辑了原始问题,以显示简单的create EXCECT flush get循环的SQL,并包括表映射。问题在于Price
字段
,如您所见,它被插入值100.42,但随后被更新为100.42000,我认为这将实体标记为脏。您是否有自定义逻辑来设置
Price
字段的格式?您是否可以使用
Price
字段及其实体的映射来更新帖子?Price字段是一个C#
decimal?
,具有简单的get/set,没有自定义逻辑。视图负责将其格式化以供显示。它的映射现在是mapping.Map(i=>i.Price)、精度(6)、比例(2);虽然这并没有改变任何事情。如果price是
十进制的,只需观察一次即可。
为什么它在数据库中被标记为
NotNull
public class ProductMap : ClassMap<Product>
{
   public ProductMap()
   {
      Not.LazyLoad();
      Id(x => x.Id).GeneratedBy.GuidComb();
      Map(x => x.ReorderLevel);
      Map(x => x.UnitPrice).Not.Nullable();
   }
}
    mapper.BeforeMapProperty += (ins, memb, cust) =>
    {
        var type = memb.LocalMember.GetPropertyOrFieldType();

        if (type.IsValueType)
        {
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                cust.Column(x => { x.NotNullable(notnull: false); });
            }
            else
            {
                cust.Column(x => { x.NotNullable(notnull: true); });
            }
        }
    }