我是Fluent NHibernate的新手。我按照https://github.com/jagregory/fluent-nhibernate/wiki/Getting-started
上的示例进行了操作该示例显示了如何创建和读取实体。在运行时,它创建了2个商店。
我在此示例代码中添加了 DeleteByStoreId()方法。
public static void DeleteByStoreId(int StoreId)
{
var sessionFactory = CreateSessionFactory();
using (var session = sessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var store = session.Get<Store>(StoreId);
if (store != null)
{
session.Delete(store);
}
transaction.Commit();
}
}
}
当我通过提供两个现有StoreId之一执行DeleteByStoreId时,以某种方式删除BOTH商店。我会希望它只删除具有给定StoreId的一个商店。你能告诉我我做错了什么吗?
以下是实体的定义方式:
using System.Collections.Generic;
namespace FluentNHibernateDemo.Entities
{
public class Employee
{
public virtual int Id { get; protected set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual Store Store { get; set; }
}
public class Product
{
public virtual int Id { get; protected set; }
public virtual string Name { get; set; }
public virtual double Price { get; set; }
public virtual Location Location { get; set; }
public virtual IList<Store> StoresStockedIn { get; set; }
public Product()
{
StoresStockedIn = new List<Store>();
}
}
public class Location
{
public virtual int Aisle { get; set; }
public virtual int Shelf { get; set; }
}
public class Store
{
public virtual int Id { get; protected set; }
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
public virtual IList<Employee> Staff { get; set; }
public Store()
{
Products = new List<Product>();
Staff = new List<Employee>();
}
public virtual void AddProduct(Product product)
{
product.StoresStockedIn.Add(this);
Products.Add(product);
}
public virtual void AddEmployee(Employee employee)
{
employee.Store = this;
Staff.Add(employee);
}
}
}
以下是映射的定义方式:
using FluentNHibernate.Mapping;
using FluentNHibernateDemo.Entities;
namespace FluentNHibernateDemo.Mappings
{
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Id(x => x.Id);
Map(x => x.FirstName);
Map(x => x.LastName);
References(x => x.Store);
}
}
public class LocationMap : ComponentMap<Location>
{
public LocationMap()
{
Map(x => x.Aisle);
Map(x => x.Shelf);
}
}
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.Price);
HasManyToMany(x => x.StoresStockedIn)
.Cascade.All()
.Inverse()
.Table("StoreProduct");
Component(x => x.Location);
}
}
public class StoreMap : ClassMap<Store>
{
public StoreMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.Products)
.Cascade.All()
.Table("StoreProduct");
HasMany(x => x.Staff)
.Cascade.All()
.Inverse();
}
}
}
以下是数据库表的定义方式:
CREATE TABLE [dbo].[Employee](
[Id] [int] IDENTITY(1,1) NOT NULL,
[LastName] [varchar](255) NULL,
[FirstName] [varchar](255) NULL,
[Store_id] [int] NULL,
CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED
(
[Id] 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].[Product](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Price] [money] NULL,
[Name] [varchar](255) NULL,
[Aisle] [int] NULL,
[Shelf] [int] NULL,
CONSTRAINT [PK_Product] PRIMARY KEY CLUSTERED
(
[Id] 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].[Store](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](255) NULL,
CONSTRAINT [PK_Store] PRIMARY KEY CLUSTERED
(
[Id] 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].[StoreProduct](
[Product_id] [int] NULL,
[Store_id] [int] NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Employee] WITH CHECK ADD CONSTRAINT [FK_Employee_Store] FOREIGN KEY([Store_id])
REFERENCES [dbo].[Store] ([Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Employee] CHECK CONSTRAINT [FK_Employee_Store]
GO
ALTER TABLE [dbo].[StoreProduct] WITH CHECK ADD CONSTRAINT [FK_StoreProduct_Product] FOREIGN KEY([Product_id])
REFERENCES [dbo].[Product] ([Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[StoreProduct] CHECK CONSTRAINT [FK_StoreProduct_Product]
GO
ALTER TABLE [dbo].[StoreProduct] WITH CHECK ADD CONSTRAINT [FK_StoreProduct_Store] FOREIGN KEY([Store_id])
REFERENCES [dbo].[Store] ([Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[StoreProduct] CHECK CONSTRAINT [FK_StoreProduct_Store]
GO
更多信息。我使用SQL事件探查器来监视SQL调用。假设当我执行此示例程序时,会创建Store_id = 105和106。
我已经捕获了执行DeleteByStoreId(105)后发生的SQL调用序列:
********************************************************************************
SELECT store0_.Id as Id10_0_, store0_.Name as Name10_0_ FROM [Store] store0_ WHERE store0_.Id=@p0;
@p0 = 105 [Type: Int32 (0)]
********************************************************************************
SELECT products0_.Store_id as Store2_1_, products0_.Product_id as Product1_1_, product1_.Id as Id8_0_, product1_.Name as Name8_0_, product1_.Price as Price8_0_, product1_.Aisle as Aisle8_0_, product1_.Shelf as Shelf8_0_ FROM StoreProduct products0_ left outer join [Product] product1_ on products0_.Product_id=product1_.Id WHERE products0_.Store_id=@p0;
@p0 = 105 [Type: Int32 (0)]
********************************************************************************
SELECT storesstoc0_.Product_id as Product1_1_, storesstoc0_.Store_id as Store2_1_, store1_.Id as Id10_0_, store1_.Name as Name10_0_ FROM StoreProduct storesstoc0_ left outer join [Store] store1_ on storesstoc0_.Store_id=store1_.Id WHERE storesstoc0_.Product_id=@p0;
@p0 = 307 [Type: Int32 (0)]
********************************************************************************
SELECT storesstoc0_.Product_id as Product1_1_, storesstoc0_.Store_id as Store2_1_, store1_.Id as Id10_0_, store1_.Name as Name10_0_ FROM StoreProduct storesstoc0_ left outer join [Store] store1_ on storesstoc0_.Store_id=store1_.Id WHERE storesstoc0_.Product_id=@p0;
@p0 = 308 [Type: Int32 (0)]
********************************************************************************
SELECT storesstoc0_.Product_id as Product1_1_, storesstoc0_.Store_id as Store2_1_, store1_.Id as Id10_0_, store1_.Name as Name10_0_ FROM StoreProduct storesstoc0_ left outer join [Store] store1_ on storesstoc0_.Store_id=store1_.Id WHERE storesstoc0_.Product_id=@p0;
@p0 = 309 [Type: Int32 (0)]
********************************************************************************
SELECT storesstoc0_.Product_id as Product1_1_, storesstoc0_.Store_id as Store2_1_, store1_.Id as Id10_0_, store1_.Name as Name10_0_ FROM StoreProduct storesstoc0_ left outer join [Store] store1_ on storesstoc0_.Store_id=store1_.Id WHERE storesstoc0_.Product_id=@p0;
@p0 = 310 [Type: Int32 (0)]
********************************************************************************
SELECT products0_.Store_id as Store2_1_, products0_.Product_id as Product1_1_, product1_.Id as Id8_0_, product1_.Name as Name8_0_, product1_.Price as Price8_0_, product1_.Aisle as Aisle8_0_, product1_.Shelf as Shelf8_0_ FROM StoreProduct products0_ left outer join [Product] product1_ on products0_.Product_id=product1_.Id WHERE products0_.Store_id=@p0;
@p0 = 106 [Type: Int32 (0)]
********************************************************************************
SELECT storesstoc0_.Product_id as Product1_1_, storesstoc0_.Store_id as Store2_1_, store1_.Id as Id10_0_, store1_.Name as Name10_0_ FROM StoreProduct storesstoc0_ left outer join [Store] store1_ on storesstoc0_.Store_id=store1_.Id WHERE storesstoc0_.Product_id=@p0;
@p0 = 311 [Type: Int32 (0)]
********************************************************************************
SELECT storesstoc0_.Product_id as Product1_1_, storesstoc0_.Store_id as Store2_1_, store1_.Id as Id10_0_, store1_.Name as Name10_0_ FROM StoreProduct storesstoc0_ left outer join [Store] store1_ on storesstoc0_.Store_id=store1_.Id WHERE storesstoc0_.Product_id=@p0;
@p0 = 312 [Type: Int32 (0)]
********************************************************************************
SELECT staff0_.Store_id as Store4_1_, staff0_.Id as Id1_, staff0_.Id as Id7_0_, staff0_.FirstName as FirstName7_0_, staff0_.LastName as LastName7_0_, staff0_.Store_id as Store4_7_0_ FROM [Employee] staff0_ WHERE staff0_.Store_id=@p0;
@p0 = 106 [Type: Int32 (0)]
********************************************************************************
SELECT staff0_.Store_id as Store4_1_, staff0_.Id as Id1_, staff0_.Id as Id7_0_, staff0_.FirstName as FirstName7_0_, staff0_.LastName as LastName7_0_, staff0_.Store_id as Store4_7_0_ FROM [Employee] staff0_ WHERE staff0_.Store_id=@p0;
@p0 = 105 [Type: Int32 (0)]
********************************************************************************
DELETE FROM StoreProduct WHERE Store_id = @p0;
@p0 = 105 [Type: Int32 (0)]
********************************************************************************
DELETE FROM StoreProduct WHERE Store_id = @p0;
@p0 = 106 [Type: Int32 (0)]
********************************************************************************
Batch commands:
command 0:DELETE FROM [Product] WHERE Id = @p0;
@p0 = 307 [Type: Int32 (0)]
command 1:DELETE FROM [Product] WHERE Id = @p0;
@p0 = 308 [Type: Int32 (0)]
command 2:DELETE FROM [Product] WHERE Id = @p0;
@p0 = 309 [Type: Int32 (0)]
command 3:DELETE FROM [Product] WHERE Id = @p0;
@p0 = 311 [Type: Int32 (0)]
command 4:DELETE FROM [Product] WHERE Id = @p0;
@p0 = 312 [Type: Int32 (0)]
********************************************************************************
Batch commands:
command 0:DELETE FROM [Employee] WHERE Id = @p0;
@p0 = 256 [Type: Int32 (0)]
command 1:DELETE FROM [Employee] WHERE Id = @p0;
@p0 = 257 [Type: Int32 (0)]
********************************************************************************
Batch commands:
command 0:DELETE FROM [Store] WHERE Id = @p0;
@p0 = 106 [Type: Int32 (0)]
********************************************************************************
Batch commands:
command 0:DELETE FROM [Product] WHERE Id = @p0;
@p0 = 310 [Type: Int32 (0)]
********************************************************************************
Batch commands:
command 0:DELETE FROM [Employee] WHERE Id = @p0;
@p0 = 258 [Type: Int32 (0)]
command 1:DELETE FROM [Employee] WHERE Id = @p0;
@p0 = 259 [Type: Int32 (0)]
command 2:DELETE FROM [Employee] WHERE Id = @p0;
@p0 = 260 [Type: Int32 (0)]
********************************************************************************
Batch commands:
command 0:DELETE FROM [Store] WHERE Id = @p0;
@p0 = 105 [Type: Int32 (0)]
********************************************************************************
当我在DeleteByStoreId()中放置一个断点时,我可以看到
var store = session.Get<Store>(StoreId);
仅返回 Store_Id = 105 的元素。那么,为什么会删除 Store_id = 106 以及
我必须向我的老板证明Fluent NHibernate能够进行CRUD操作,以便我可以在我的新项目中使用它。希望你能尽快回答我。
答案 0 :(得分:0)
问题似乎出现在映射中。看看this other answer which talks to a similar issue and how the inverse/cascading relationships can work。
如果您将其应用于您的情况,那么唯一的缺点就是您最终得到的产品未分配给任何商店。如果您有一般产品目录可以不时处理任何商店中没有库存产品的维护,可以安全地从目录中删除。
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
HasManyToMany(x => x.StoresStockedIn)
.Table("StoreProduct")
.ParentKeyColumn("Product_Id")
.ChildKeyColumn("Store_Id")
.Inverse()
.Cascade.SaveUpdate();
}
}
public class StoreMap : ClassMap<Store>
{
public StoreMap()
{
HasManyToMany(x => x.Products)
.Table("StoreProduct")
.ParentKeyColumn("Store_Id")
.ChildKeyColumn("Product_Id")
.Cascade.SaveUpdate();
}
}