【问题标题】:How to map and test a "Many to Many Relationship" in NHibernate using Fluent NHibernate如何使用 Fluent NHibernate 在 NHibernate 中映射和测试“多对多关系”
【发布时间】:2009-11-25 10:23:00
【问题描述】:

当我测试我的多对多类时发生错误:

System.ApplicationException:实际 计数不等于预期计数。

实体:

    public interface IEntity
    {
        int Id { get; set; }
    }

    public abstract class Entity : IEntity
    {
        public virtual int Id { get; set; }

        public virtual bool IsPersistent
        {
            get { return isPersistentObject(); }
        }

        public override bool Equals(object obj)
        {
            if (isPersistentObject())
            {
                var persistentObject = obj as Entity;
                return (persistentObject != null) && (Id == persistentObject.Id);
            }

            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return isPersistentObject() ? Id.GetHashCode() : base.GetHashCode();
        }

        private bool isPersistentObject()
        {
            return (Id != 0);
        }
    }

    public class Team : Entity
    {
        public virtual string Name { get; set; }
        public virtual ISet<Employee> Employees { get; set; }

        public Team()
        {
            Employees = new HashedSet<Employee>();
        }
    }

    public class Employee : Entity
    {
        public virtual string LastName { get; set; }
        public virtual string FirstName { get; set; }
        public virtual ISet<Team> Teams { get; set; }
        public virtual string EMail { get; set; }

        public Employee()
        {
            Teams = new HashedSet<Team>();
        }
    }

映射:

public class TeamMap : ClassMap<Team>
{
    public TeamMap()
    {
        // identity mapping
        Id(p => p.Id).Column("TeamID");

        // column mapping
        Map(p => p.Name);

        // relationship mapping
        HasManyToMany(m => m.Employees)
            .Table("EmployeeTeam")
            .LazyLoad()
            .Cascade.SaveUpdate()
            .AsSet()
            .ParentKeyColumn("TeamID")
            .ChildKeyColumn("EmployeeID");
    }
}

public class EmployeeMap : ClassMap<Employee>
{
    public EmployeeMap()
    {
        // identifier mapping
        Id(p => p.Id).Column("EmployeeID");

        // column mapping
        Map(p => p.EMail);
        Map(p => p.LastName);
        Map(p => p.FirstName);

        // relationship mapping
        HasManyToMany(m => m.Teams).Table("EmployeeTeam")
            .Inverse()
            .Cascade.SaveUpdate()
            .AsSet()
            .LazyLoad()
            .ParentKeyColumn("EmployeeID")
            .ChildKeyColumn("TeamID");
    }
}

测试:

[TestMethod]
public  void  CanCorrectlyMapEmployee()
{
    var team = new List<Team> {new Team() {Name = "Team1"}};

    new PersistenceSpecification<Employee>(_session)
        .CheckProperty(p => p.EMail, "Mail")
        .CheckProperty(p => p.FirstName, "Firstname")
        .CheckProperty(p => p.Id, 1)
        .CheckProperty(p => p.LastName, "Lastname")
        .CheckList(p => p.Teams,team )
        .VerifyTheMappings();
}

无论我添加员工还是团队,我的 EmployeeTeam 表始终为空。

我已经使用 FNH 对 SQLLite 进行了测试,并针对 SQL Server 2008 手动对其进行了测试。

你们中有人有解决这个问题的想法吗?

编辑:

我惊讶地发现,当我创建一个 Employee 并将 2 个 Teams 添加到 Employee 并加载创建的 Employee 时,他有 2 个 Teams。所以它工作正常。但是当我查看我的关系表 EmployeeTeam 时,一切都是空的。谁能解释一下为什么?

有人知道我如何使用 Fluent NHibernate 来测试我的多对多关系吗?

提前致谢!

【问题讨论】:

    标签: unit-testing fluent-nhibernate many-to-many relationship


    【解决方案1】:

    员工地图具有反向属性。您可能知道,这意味着当您保存员工时,关系表(EmployeeTeam)不会被更新。要添加/删除新的关系信息,您必须将员工添加到团队并保存团队。

    因此,就您而言 - 不要在员工方面进行多对多的测试,而是在团队方面进行测试。 (如果您希望 NHibernate 在将团队添加到员工时添加记录,则必须反转“反向”属性 - 将其提供给团队,而不是员工,然后 - 与团队实体相同)。

    为什么您能够为 Employee 加载团队?因为会话级缓存。您可能已经在同一个 ISession 中保存并加载了 Employee - 这意味着 NHibernate 返回您对同一对象的完全引用,而不是从数据库加载它。尝试在两个不同的会话中保存和加载,您将在 Employee.Teams 集中看到没有团队。

    旁注:创建将强制多对多关系之间保持一致性的方法被认为是一种很好的做法,即 - 当您将团队添加到员工时,员工会添加到团队中,......像这样:

    class Employee 
    {
      // ...
      public void AddTeam(Team team)
      {
         // check for null, etc. 
    
         Teams.Add(team);
         team.Employees.Add(this);
      }
    }
    

    和Team类中非常相似的方法。

    【讨论】:

    • 好吧,我错过了 stackoverflow 上的引用函数 ...“[...] 因为会话级缓存。您可能已经在同一个 ISession 中保存和加载了 Employee - 这意味着 NHibernate 返回你完全引用了同一个对象,而不是从数据库中加载它。”这是不正确的。我对此进行了测试,是的,NHibernate 缓存了我的对象,但我清除了缓存并加载了我的对象。此外,我使用了 SQL Server Profiler,在那里我看到了一个带有 LEFT OUTER JOIN 的选择查询。因此,奇怪的是检索和保存工作。但我会试试你的建议。现在谢谢。
    • 关系为空的问题是因为我没有刷新会话。现在可以正确保存员工和团队。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 2012-06-12
    • 1970-01-01
    相关资源
    最近更新 更多