EntityFramework 与 NHibernate 中的关系修复

Posted

技术标签:

【中文标题】EntityFramework 与 NHibernate 中的关系修复【英文标题】:Relationships fixup in EntityFramework vs NHibernate 【发布时间】:2012-11-06 14:47:50 【问题描述】:

我一直在尝试使用 Entity Framework 4.4、NHibernate 3.3.1.4000 和 SQL Server,我注意到在您提交更改时修复关系方面存在差异,我想知道最佳实践是什么,或者如果我做错了什么。

这是我测试的。我有一个经典的父链接到 n 个孩子。我在数据库中有 2 位父母,每人有 20 个孩子。我加载了父母双方,我取了第一个父母的第一个孩子并将那个孩子分配给第二个父母。然后我提交更改。

在EF中,我保存后,我可以看到父母双方的Children集合的计数已经改变,所以它修复了关系。

但是,当我在 NHibernate 中执行相同操作时,计数保持不变。

这是我重现问题的代码设置。

POCO:

public class Parent

    public virtual int ParentId  get; set; 

    public virtual string Name  get; set; 

    public virtual IList<Child> Children  get; set; 

    public Parent()
    
        Children = new List<Child>();
    


public class Child

    public virtual int ChildId  get; set; 

    public virtual int ParentId  get; set; 

    public virtual string Name  get; set; 

    public virtual Parent Parent  get; set; 

NHibernate 父映射:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="ConsoleApplication1"
                   namespace="ConsoleApplication1">
  <class name="Parent" table="Parents">
    <id name="ParentId" column="ParentId" />
    <property name="Name" column="Name" />
    <bag name="Children" cascade="all">
      <key column="ParentId"/>
      <one-to-many class="Child"/>
    </bag>
  </class>
</hibernate-mapping>    

NHibernate 子映射:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="ConsoleApplication1"
                   namespace="ConsoleApplication1">
  <class name="Child" table="Children">
    <id name="ChildId" column="ChildId" />
    <property name="Name" column="Name" />
    <many-to-one name="Parent" class="Parent" column="ParentId" not-null="true" />
  </class>
</hibernate-mapping>    

EF DbContext:

public class Entities : DbContext

    public DbSet<Parent> Parents  get; set; 

    public DbSet<Child> Children  get; set; 

App.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate" />
  </configSections>
  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
      <property name="connection.provider">
        NHibernate.Connection.DriverConnectionProvider
      </property>
      <property name="dialect">
        NHibernate.Dialect.MsSql2005Dialect
      </property>
      <property name="connection.driver_class">
        NHibernate.Driver.SqlClientDriver
      </property>
      <property name="connection.connection_string">
        Data Source=localhost;Initial Catalog=MaintainRelationshipsNH;Integrated Security=True;
      </property>
    </session-factory>
  </hibernate-configuration>
  <connectionStrings>
    <add
      name="Entities"
      providerName="System.Data.SqlClient"
      connectionString="Server=localhost;Database=MaintainRelationshipsNH;Trusted_Connection=true;"/>
  </connectionStrings>
</configuration>

创建表格和数据的脚本:

create table Parents (
   ParentId INT not null,
   Name NVARCHAR(255) null,
   primary key (ParentId)
)

create table Children (
   ChildId INT not null,
   Name NVARCHAR(255) null,
   ParentId INT not null,
   primary key (ChildId)
)

alter table Children
    add constraint FK_Children_Parents
    foreign key (ParentId)
    references Parents

declare @idChild int        
insert into Parents (ParentId, Name) values (0, 'John');
set @idChild = 0
while @idChild < 20
begin
   insert into Children (ChildId, Name, ParentId) values (@idChild, 'Child ' + convert(nvarchar(2), @idChild), 0);
   set @idChild = @idChild + 1
end
insert into Parents (ParentId, Name) values (1, 'Julie');
while @idChild < 40
begin
   insert into Children (ChildId, Name, ParentId) values (@idChild, 'Child ' + convert(nvarchar(2), @idChild), 1);
   set @idChild = @idChild + 1
end

NHibernate 测试代码:

System.Diagnostics.Debug.WriteLine("Test NHibernate:");

Configuration configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof(Parent).Assembly);

ISessionFactory sessionFactory = configuration.BuildSessionFactory();

Parent parent0, parent1;
using (ISession session = sessionFactory.OpenSession())

    using (ITransaction transaction = session.BeginTransaction())
    
        parent0 = session.Load<Parent>(0);
        parent1 = session.Load<Parent>(1);
        System.Diagnostics.Debug.WriteLine("Before modifications and commit");
        System.Diagnostics.Debug.WriteLine("Parent0 number of children: " + parent0.Children.Count);
        System.Diagnostics.Debug.WriteLine("Parent1 number of children: " + parent1.Children.Count);

        parent0.Children[0].Parent = parent1;

        transaction.Commit();
    

System.Diagnostics.Debug.WriteLine("After modifications and commit");
System.Diagnostics.Debug.WriteLine("Parent0 number of children: " + parent0.Children.Count);
System.Diagnostics.Debug.WriteLine("Parent1 number of children: " + parent1.Children.Count);

实体框架测试代码:

System.Diagnostics.Debug.WriteLine("Test Entity Framework:");

Parent parent0, parent1;
using (Entities entities = new Entities())

    parent0 = entities.Parents.Find(0);
    parent1 = entities.Parents.Find(1);
    System.Diagnostics.Debug.WriteLine("Before modifications and commit");
    System.Diagnostics.Debug.WriteLine("Parent0 number of children: " + parent0.Children.Count);
    System.Diagnostics.Debug.WriteLine("Parent1 number of children: " + parent1.Children.Count);
    parent0.Children[0].Parent = parent1;

    entities.SaveChanges();

System.Diagnostics.Debug.WriteLine("After modifications and commit");
System.Diagnostics.Debug.WriteLine("Parent0 number of children: " + parent0.Children.Count);
System.Diagnostics.Debug.WriteLine("Parent1 number of children: " + parent1.Children.Count);

所以基本上通过这个测试,我可以看到计数随 EF 而变化,但不随 NHibernate 变化。我是否对 NH 做错了什么,或者我是否必须手动管理受我的更改影响的关系的每个部分?谢谢!

【问题讨论】:

【参考方案1】:

在 NHibernate 中,您需要手动将它们从一个父集合移动到另一个集合。我通常在父类中使用 Add 或 Remove 方法来执行此操作。以下是这些添加或删除方法的示例:

    public virtual void AddLine(OrderLine orderLine)
    
        orderLine.Order = this;
        this.orderLines.Add(orderLine);
    

    public virtual void RemoveLine(OrderLine orderLine)
    
        this.orderLines.Remove(orderLine);
    

为了让孩子重新成为父母,我会做这样的事情:

    originalParent.RemoveLine(child);

    newParent.AddLine(child);

【讨论】:

我明白你的意思,我看到一个类似的帖子 (***.com/questions/944045/…) 提出了相同的建议。我将尝试使用 NHibernate 和实体框架来实现这一点。谢谢!

以上是关于EntityFramework 与 NHibernate 中的关系修复的主要内容,如果未能解决你的问题,请参考以下文章

EntityFramework 与 NHibernate 中的关系修复

MiniProfiler 与 EntityFramework 6 代码优先

csharp 标准脚手架EntityFramework与异步操作WebAPI控制器

entityframework 已经有一个与此命令关联的打开的 DataReader 必须先关闭

EntityFramework与Ado.net的对比——EF优势何在?

Oracle.DataAccess.EntityFramework, Version=6.121.2.0 定位的程序集的清单定义与程序集引用不匹配