流利的NHibernate和具有单列名称的复合ID [英] Fluent NHibernate and composite ID with single column name
问题描述
我已经在FNH Google Group中发布了这个消息,但是这里是独家新闻:
我有一个包含复合ID的旧数据库中的表。那么,
PK是隐含的,因为表中实际上没有定义PK,但
自然PK是WORKORDERID和IMAGEPATH
列的组合:
CREATE TABLE [WORKORDERIMG](
[WORKORDERID] [varchar](50)NULL,
[IMAGEPATH] [varchar]( 250)NULL,
[WOTASKID] [numeric](10,0)NULL,
[ATTACHEDBY] [nvarchar](100)NULL,
[COMMENTS] [nvarchar](256)NULL ,
[DATETIMEATTACHED] [datetime] NULL
)ON [PRIMARY]
我定义了这个类映射:
///< summary>
///工作订单附件的NHibernate映射
///< / summary>
public class AttachmentMap:ClassMap< Attachment>
{
Public AttachmentMap()
{
SchemaIs(Resources.DatabaseSchema);
WithTable(ObjectNames.TableWorkorderAttachment);
UseCompositeId()
.WithKeyProperty(x => x.ParentId,WORKORDERID)
.WithKeyProperty(x => x.FileLocation,IMAGEPATH);
Map(x => x.AttachedByUser,ATTACHEDBY)。WithLengthOf(100).Nullable();
Map(x => x.AttachedOn,DATETIMEATTACHED)。Nullable();
Map(x => x.Comments).Nullable()。WithLengthOf(256);
引用(x => x.ParentWorkorder).FetchType.Join();
$ b $ p $对于这个类:
public class Attachment
{
public virtual string ParentId {get;组; }
公共虚拟字符串FileLocation {get;组; }
public virtual Workorder ParentWorkorder {get;组; }
公共虚拟字符串AttachedByUser {get;组; }
公共虚拟字符串评论{get;组; }
公共虚拟DateTime? AttachedOn {get;组; }
$ b $ public override bool Equals(object obj)
{
return this.IsEqual(obj);
$ b $ public override int GetHashCode()
{
return HashCodeGenerator.GenerateHashCode(new object [] {FileLocation,ParentId});
$ b现在我知道我应该定义WORKORDERID列也在References行的
classmap中。有了它,我得到了
的预期错误:
NHibernate:INSERT INTO azteca.WorkOrderImg(ATTACHEDBY,
@ DATETIMEATTACHED,注释,ParentWorkorder_id,WORKORDERID,
IMAGEPATH)VALUES(@ p0,@ p1,@ p2,@ p3,@ p4,@ p5); @ p0 ='SYSTEM',@ p1 = 3/15 / @ p2 ='Some comment',@ p3 = NULL,@ p4 = NULL,@ p5 ='some ile''location'
System.Data.SqlClient。 SqlException:列名'ParentWorkorder_id'无效。
然而,当我包含它时,我得到Fluent NHibernate尝试添加
WORKORDERID列查询两次:
System.IndexOutOfRangeException:对于此Count = 5的SqlParameterCollection,索引5无效。
我一直在尝试所有我能想到的组合。我是
测试这个代码的映射:
pre $ [$]
public void Can_persist_an_attachment()
{
var sf = ObjectFactory.GetNamedInstance< ISessionFactory> (ObjectMother.Datasource);
using(ISession session = sf.OpenSession())
{
new PersistenceSpecification< Attachment>(session)
.CheckProperty(x => x.AttachedByUser ,SYSTEM)
.CheckProperty(x => x.AttachedOn,new DateTime(2009,3,15))
.CheckProperty(x => x.Comments,Some comment)
.CheckProperty(x => x.FileLocation,some \\\\\ location)
.VerifyTheMappings();
$ p
$ b
解决方案想通了。您不需要为父级添加引用属性。注意调整后的映射中多对一的缺失:
public AttachmentMap()
{
SchemaIs(Resources.CityworksDatabaseSchema);
WithTable(ObjectNames.TableWorkorderAttachment);
UseCompositeId()
.WithKeyReference(x => x.ParentWorkorder,WORKORDERID)
.WithKeyProperty(x => x.FileLocation,IMAGEPATH);
Map(x => x.AttachedByUser,ATTACHEDBY)。WithLengthOf(100).Nullable();
Map(x => x.AttachedOn,DATETIMEATTACHED)。Nullable();
Map(x => x.Comments).Nullable()。WithLengthOf(256);
//引用(x => x.ParentWorkorder,WORKORDERID)。FetchType.Join();
}
这将导致以下HBM映射文件。解决的办法是让composite-id有一个key-many-to-one行指向父类。现在我可以坚持我的Attachment类。
< hibernate-mapping xmlns =urn:nhibernate-mapping-2.2存取= >
< class name =Woolpert.Cityworks.Core.Entities.Azteca.Attachment,Woolpert.Cityworks.Core,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = nulltable =WorkOrderImgxmlns = urn:nhibernate-mapping-2.2schema =azteca>
< composite-id>
< key-property type =Stringname =FileLocationcolumn =IMAGEPATH/>
< / composite-id>
< property name =AttachedByUsertype =String>
< column name =ATTACHEDBYlength =100not-null =false/>
< / property>
< property name =AttachedOntype =System.Nullable`1 [[System.DateTime,mscorlib,Version = 2.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]]>
< column name =DATETIMEATTACHEDnot-null =false/>
< / property>
< property name =Commentstype =String>
< column name =Commentslength =256not-null =false/>
< / property>
< / class>
< / hibernate-mapping>
I've crossed posted this in the FNH Google Group but here's the scoop:
I have a table in a legacy database that has a composite ID. Well, the
PK is implied since the table doesn't actually have a PK defined, but
the natural PK is the combination of the WORKORDERID and IMAGEPATH
columns:
CREATE TABLE [WORKORDERIMG](
[WORKORDERID] [varchar](50) NULL,
[IMAGEPATH] [varchar](250) NULL,
[WOTASKID] [numeric](10, 0) NULL,
[ATTACHEDBY] [nvarchar](100) NULL,
[COMMENTS] [nvarchar](256) NULL,
[DATETIMEATTACHED] [datetime] NULL
) ON [PRIMARY]
I have this class map defined:
/// <summary>
/// NHibernate mapping for workorder attachments
/// </summary>
public class AttachmentMap : ClassMap<Attachment>
{
public AttachmentMap()
{
SchemaIs(Resources.DatabaseSchema);
WithTable(ObjectNames.TableWorkorderAttachment);
UseCompositeId()
.WithKeyProperty(x => x.ParentId, "WORKORDERID")
.WithKeyProperty(x => x.FileLocation, "IMAGEPATH");
Map(x => x.AttachedByUser, "ATTACHEDBY").WithLengthOf(100).Nullable();
Map(x => x.AttachedOn, "DATETIMEATTACHED").Nullable();
Map(x => x.Comments).Nullable().WithLengthOf(256);
References(x => x.ParentWorkorder).FetchType.Join();
}
}
For this class:
public class Attachment
{
public virtual string ParentId { get; set; }
public virtual string FileLocation { get; set; }
public virtual Workorder ParentWorkorder { get; set; }
public virtual string AttachedByUser { get; set; }
public virtual string Comments { get; set; }
public virtual DateTime? AttachedOn { get; set; }
public override bool Equals(object obj)
{
return this.IsEqual(obj);
}
public override int GetHashCode()
{
return HashCodeGenerator.GenerateHashCode(new object[] { FileLocation, ParentId });
}
}
Now I know that I should be defining the WORKORDERID column in the
classmap for the References line as well. With it excluded I get the
expected error:
NHibernate: INSERT INTO azteca.WorkOrderImg (ATTACHEDBY,
DATETIMEATTACHED, Comments, ParentWorkorder_id, WORKORDERID,
IMAGEPATH) VALUES (@p0, @p1, @p2, @p3, @p4, @p5);@p0 = 'SYSTEM', @p1 = 3/15/2009 12:00:00 AM, @p2 = 'Some comment', @p3 = NULL, @p4 = NULL, @p5 = 'some ile\location'
System.Data.SqlClient.SqlException: Invalid column name 'ParentWorkorder_id'.
However, when I include it I get Fluent NHibernate trying to add the
WORKORDERID column to the query twice:
System.IndexOutOfRangeException: Invalid index 5 for this SqlParameterCollection with Count=5.
I've been trying every combination I can think of to no avail. I'm
testing the mapping with this code:
[Test]
public void Can_persist_an_attachment()
{
var sf = ObjectFactory.GetNamedInstance<ISessionFactory> (ObjectMother.Datasource);
using (ISession session = sf.OpenSession())
{
new PersistenceSpecification<Attachment>(session)
.CheckProperty(x => x.AttachedByUser, "SYSTEM")
.CheckProperty(x => x.AttachedOn, new DateTime(2009, 3, 15))
.CheckProperty(x => x.Comments, "Some comment")
.CheckProperty(x => x.FileLocation, "some\file\\location")
.VerifyTheMappings();
}
}
Any help appreciated.
解决方案 Figured it out. You don't need to add the reference property for the parent. Notice how the many-to-one is missing in the adjusted mapping:
public AttachmentMap()
{
SchemaIs(Resources.CityworksDatabaseSchema);
WithTable(ObjectNames.TableWorkorderAttachment);
UseCompositeId()
.WithKeyReference(x => x.ParentWorkorder, "WORKORDERID")
.WithKeyProperty(x => x.FileLocation, "IMAGEPATH");
Map(x => x.AttachedByUser, "ATTACHEDBY").WithLengthOf(100).Nullable();
Map(x => x.AttachedOn, "DATETIMEATTACHED").Nullable();
Map(x => x.Comments).Nullable().WithLengthOf(256);
//References(x => x.ParentWorkorder, "WORKORDERID").FetchType.Join();
}
This results in the following HBM mapping file. The fix is to have the composite-id have a key-many-to-one line pointing back to the parent class. Now I can persist my Attachment class.
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="">
<class name="Woolpert.Cityworks.Core.Entities.Azteca.Attachment, Woolpert.Cityworks.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="WorkOrderImg" xmlns="urn:nhibernate-mapping-2.2" schema="azteca">
<composite-id>
<key-many-to-one class="Woolpert.Cityworks.Core.Entities.Azteca.Workorder, Woolpert.Cityworks.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="ParentWorkorder" column="WORKORDERID" />
<key-property type="String" name="FileLocation" column="IMAGEPATH" />
</composite-id>
<property name="AttachedByUser" type="String">
<column name="ATTACHEDBY" length="100" not-null="false" />
</property>
<property name="AttachedOn" type="System.Nullable`1[[System.DateTime, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]">
<column name="DATETIMEATTACHED" not-null="false" />
</property>
<property name="Comments" type="String">
<column name="Comments" length="256" not-null="false" />
</property>
</class>
</hibernate-mapping>
这篇关于流利的NHibernate和具有单列名称的复合ID的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!