Car*_*ema 7 nhibernate nhibernate-mapping fluent-nhibernate fluent-nhibernate-mapping
在这两者之间单向许多一对多的关系,Registration和Item,其中Registration有ISet<Item> ItemsPurchased和Item没有回头参考注册(它不是探索对象图的有效方式),当我看着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
Run Code Online (Sandbox Code Playgroud)
传递给更新的参数是正确的,但没有关于Item的更改,因此不需要更新.
映射是通过使用此覆盖自动执行Registration而不是覆盖Item.DB Schema看起来完全正确.我删除了所有约定并再次测试,并且行为仍然存在,因此我的映射约定并不是这样做的.
mapping.HasManyToMany(e => e.ItemsPurchased).AsSet().Cascade.All().Not.Inverse();
为什么NHibernate会打这个UPDATE电话,我该怎么做才能阻止它呢?它并没有真正伤害任何东西,但它表明我做错了什么,所以我想弄明白什么.
编辑:
根据下面的评论,我创建了一个单元测试,它创建了一个Event(Item必须属于一个Event),Items向它添加两个,从会话中清除第一个并刷新会话,然后通过其ID获取第一个返回.
我在下面的SELECT项目行中注意到一些奇怪的东西(从下到下)
INSERT INTO Events (blah blah blah...)
select @@IDENTITY
INSERT INTO Items (Price, Name, StartDate, EndDate, ExternalID, ListIndex, EventId) VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6);@p0 = 100.42 [Type: Decimal (0)], @p1 = 'Item 1' [Type: String (0)], @p2 = NULL [Type: DateTime (0)], @p3 = NULL [Type: DateTime (0)], @p4 = '123' [Type: String (0)], @p5 = 0 [Type: Int32 (0)], @p6 = 1 [Type: Int32 (0)]
select @@IDENTITY
SELECT blah blah blah FROM Events event0_ WHERE event0_.EventId=@p0;@p0 = 1 [Type: Int32 (0)]
SELECT itemsforsa0_.EventId as EventId1_, itemsforsa0_.ItemId as ItemId1_, itemsforsa0_.ListIndex as ListIndex1_, itemsforsa0_.ItemId as ItemId3_0_, itemsforsa0_.Price as Price3_0_, itemsforsa0_.Name as Name3_0_, itemsforsa0_.StartDate as StartDate3_0_, itemsforsa0_.EndDate as EndDate3_0_, itemsforsa0_.ExternalID as ExternalID3_0_, itemsforsa0_.ListIndex as ListIndex3_0_, itemsforsa0_.EventId as EventId3_0_ FROM Items itemsforsa0_ WHERE itemsforsa0_.EventId=@p0;@p0 = 1 [Type: Int32 (0)]
UPDATE Items SET Price = @p0, Name = @p1, StartDate = @p2, EndDate = @p3, ExternalID = @p4, ListIndex = @p5, EventId = @p6 WHERE ItemId = @p7;@p0 = 100.42000 [Type: Decimal (0)], @p1 = 'Item 1' [Type: String (0)], @p2 = NULL [Type: DateTime (0)], @p3 = NULL [Type: DateTime (0)], @p4 = '123' [Type: String (0)], @p5 = 0 [Type: Int32 (0)], @p6 = 1 [Type: Int32 (0)], @p7 = 1 [Type: Int32 (0)]
Run Code Online (Sandbox Code Playgroud)
表格已正确创建:
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)
)
Run Code Online (Sandbox Code Playgroud)
DateTimes是故意可以为空的,因为一个项目可能不需要特定于日期(一个例子就是"早鸟注册").
Jup*_*aol 10
这称为:幻像更新,它通常与对象的映射有关
这是主要原因:
想象一下,我们有一个像这样的对象
public class Product
{
public Guid Id { get; set; }
public int ReorderLevel { get; set; }
public decimal UnitPrice { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
和地图:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,ReorderLevel它将接受空值
如果保存此实体而不指定ReorderLevel它将保存一个null值,但是当您从数据库中加载它时,由于ReorderLevel类型是int,将添加一个0将导致该实体被标记为脏,因此它将导致更新
这些错误很难检测和跟踪,我建议你Nullable<>在数据库中真正想要null时使用类型
我通常做到这一点的方法是创建一个惯例,将自动设置我Value Types来null,如果他们与声明Nullable<>,否则该字段将被标记为NotNullable
只是为了补充,这是我的惯例的样子:
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); });
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1128 次 |
| 最近记录: |