0
我看到一些意外的查詢行爲與一對一的映射,其中「子」記錄可能爲空。當看起來像左連接更合適時,Nhibernate似乎生成內連接。鑑於以下模式:NHibernate與唯一外鍵的一對一映射
CREATE TABLE [dbo].[Customer](
[CustomerId] [int] IDENTITY(1,1) NOT NULL,
[PersonId] [int] NOT NULL,
[AccountNumber] [int] NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED
(
[CustomerId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[Employee](
[EmployeeId] [int] IDENTITY(1,1) NOT NULL,
[PersonId] [int] NOT NULL,
[Title] [varchar](50) NOT NULL,
CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED
(
[EmployeeId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[Person](
[PersonId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED
(
[PersonId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[Customer] WITH CHECK ADD CONSTRAINT [FK_Customer_Person] FOREIGN KEY([PersonId])
REFERENCES [dbo].[Person] ([PersonId])
GO
ALTER TABLE [dbo].[Customer] CHECK CONSTRAINT [FK_Customer_Person]
GO
ALTER TABLE [dbo].[Employee] WITH CHECK ADD CONSTRAINT [FK_Employee_Person] FOREIGN KEY([PersonId])
REFERENCES [dbo].[Person] ([PersonId])
GO
ALTER TABLE [dbo].[Employee] CHECK CONSTRAINT [FK_Employee_Person]
GO
與以下類:
namespace OneToOneMapping.Model
{
public class Person
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Customer Customer { get; set; }
public virtual Employee Employee { get; set; }
}
public class Employee
{
public virtual System.Int32 Id { get; set; }
public virtual Person Person { get; set; }
public virtual string Title { get; set; }
}
public class Customer
{
public virtual System.Int32 Id { get; set; }
public virtual Person Person { get; set; }
public virtual int AccountNumber { get; set; }
}
}
和映射:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="OneToOneMapping"
namespace="OneToOneMapping.Model">
<class name="Person" table="Person" lazy="true" >
<id name="Id" column="PersonId">
<generator class="identity"/>
</id>
<one-to-one name="Customer" cascade="all-delete-orphan" property-ref="Person" class="OneToOneMapping.Model.Customer" />
<one-to-one name="Employee" cascade="all-delete-orphan" property-ref="Person" class="OneToOneMapping.Model.Employee" />
<property name="Name"/>
</class>
<class name="OneToOneMapping.Model.Customer, OneToOneMapping" table="Customer">
<id name="Id" column="CustomerId">
<generator class="identity"/>
</id>
<property name="AccountNumber"/>
<many-to-one name="Person" class="Person" column="PersonId" unique="true" cascade="save-update"/>
</class>
<class name="OneToOneMapping.Model.Employee, OneToOneMapping" table="Employee" lazy="true" mutable="true">
<id name="Id" column="EmployeeId">
<generator class="identity"/>
</id>
<property name="Title"/>
<many-to-one name="Person" class="Person" column="PersonId" unique="true" cascade="save-update"/>
</class>
</hibernate-mapping>
我無法創建LINQ查詢在那裏我可以返回一個投影指示是否客戶也是員工(反之亦然)。運行像下面的語句:
var t = Session.Query<Customer>().Select(c => new { AccountNumber = c.AccountNumber, Name= c.Person.Name, IsEmployee = c.Person.Employee.Id != null }).ToList();
生成以下SQL(注意「其中」條款阻止不也有客戶的任何記錄都無法返回所有相關的員工記錄):
SELECT customer0_.AccountNumber AS col_0_0_
,person1_.NAME AS col_1_0_
,employee2_.EmployeeId AS col_2_0_
FROM Customer customer0_
LEFT JOIN Person person1_ ON customer0_.PersonId = person1_.PersonId
,Employee employee2_
WHERE person1_.PersonId = employee2_.PersonId
我希望它產生類似下面只返回一個空僱員時,記錄不存在:
SELECT customer0_.AccountNumber AS col_0_0_
,person1_.NAME AS col_1_0_
,employee2_.EmployeeId AS col_2_0_
FROM Customer customer0_
LEFT JOIN Person person1_ ON customer0_.PersonId = person1_.PersonId
Left Join Employee employee2_ on person1_.PersonId = employee2_.PersonId
我缺少的東西或者這是「一對一」映射的已知問題?
我有點困惑你的域模型。你是說一個人有一個客戶或一個員工,或者你是否想說一個人是一個客戶還是一個員工?如果是後者,則需要使用繼承映射,而不是一對一映射。 – Fran
理想情況下,這將是一種繼承模式,但這不起作用,因爲一個人既可以是員工又可以是**客戶。這將打破多態查詢,如Session.Get(id)。相反,我們認爲_person_是員工和客戶共同的屬性_have_。 –
Riggins
這將是任何映射和基類查詢將返回兩個子類。 – Fran