繁体   English   中英

在nHibernate中如何正确进行双向多对多

[英]How correctly do a bi-directional many-to-many in nHibernate

我试图弄清楚如何正确使用DotNet 4.5的NHibernate中的多对多关系。 使用什么集合类型以及如何初始化它们。

场景:建模OrgUnit和位置。 下表之间存在多对多关系:

OrgUnits位置OrgUnitPositions

我使用双向设置器,因此无论我转到orgUnit.AddPosition(position)还是position.AddOrgUnit(orgUnit),都应将关系添加到两个集合中。

这是我的示例代码

public class Position 
    {
        public Position()
        {
            OrgUnits = new List<OrgUnit>(); 
        }

        public virtual ICollection<OrgUnit> OrgUnits { get; set; }

        public virtual void AddOrgUnit(OrgUnit orgUnit)
        {
            if (!OrgUnits.Contains(orgUnit))
            {
                OrgUnits.Add(orgUnit);
                if (!orgUnit.Positions.Contains(this))
                    orgUnit.AddPosition(this);
            }
        }


        public class PositionMap : ClassMap<Position>
        {
            public PositionMap()
            {
                    HasManyToMany(x => x.OrgUnits)
                    .ChildKeyColumn("OrgUnitID")
                    .ParentKeyColumn("PositionID")
                    .Table("OrgUnitPositions")
                    .Fetch.Select()
                    .Cascade.AllDeleteOrphan()
                    .AsBag()
                    .Inverse();
            }

        }

        public class OrgUnit
        {
            public OrgUnit()
            {
                Positions = new HashSet<Position>();
            }

            public virtual ICollection<Position> Positions { get; set; }

            public virtual void AddPosition(Position value)
            {
                if (!Positions.Contains(value))
                {
                    Positions.Add(value);
                    if (!value.OrgUnits.Contains(this))
                        value.AddOrgUnit(this);
                }
            }
        }
        public class OrgUnitMap : ClassMap<OrgUnit>
        {
        public OrgUnitMap()
        {
            HasManyToMany(x => x.Positions)
            .ChildKeyColumn("PositionID")
            .ParentKeyColumn("OrgUnitID")
            .Table("OrgUnitPositions")
            .Fetch.Select()
            .Cascade.AllDeleteOrphan()
            .AsSet()
            ;
        }
    }

我的问题是,当我打电话给orgUnit.AddPosition(position))时,在某些情况下,Position.AddOrgUnit中的这一行:if(!value.Positions.Contains(this))返回false,即使我在调试器中看到是包含组织单位。 这导致将其添加两次,然后在保存时发生重复的密钥异常。

我已经尝试了各种方法(我的原始收藏集列出了列表/ ILists),但我怀疑我的收藏集类型(ilist / iset / etc)是造成这种情况的原因-希望有人可以向我指出要使用的收藏集类型的方向,将它们初始化为什么,等等。

如果我打电话给position.AddOrgUnit(orgUnit); 而不是orgUnit.AddPosition,一切正常。

-更新

为了回应评论,我对Position.cs中的AddOrgUnit进行了如下更改:

public virtual void AddOrgUnit(OrgUnit orgUnit)
    {
        if (!OrgUnits.Contains(orgUnit))
        {
            OrgUnits.Add(orgUnit);
            foreach (Position p in orgUnit.Positions)
            {
                System.Console.WriteLine(string.Format("{0}", ReferenceEquals(p, this)));
            }

            if (!value.Positions.Contains(this))
            {
                value.AddPosition(this);
            }
        }
    }

这就是我发现的-记住orgUnit.positions只包含1个项目,for-each只是为了在调试器中访问该项目。

ReferenceEquals(p,this) false

p.GetHashCode() 40148707

this.GetHashCode() 53416668

this.ID {8386857d-a52e-4f17-8094-a231003299b5}

p.ID {8386857d-a52e-4f17-8094-a231003299b5}

p。描述“鲍勃”

this.Description “鲍勃”

p.description =“简”

this.Description “简”

p。描述“简”

这是奇怪的一个! hashCodes不同,但看起来是同一对象的相同实例。 IE,如果我更改“ this”版本的属性,则它会更改“ p”版本。

最后,ReferenceEquals(p.ReportsToPosition,this.ReportsToPosition) true

哪些趋向于表明它们来自同一休眠会话? (即父母是相同的)


这是我的调用代码,我们将StrctureMap用于IoC,并将ISession注入到回购协议中。 我更改了代码以传递BLL,以保证具有相同的Isession,因为将存储库注入了它。

奇怪的是,导致错误的唯一一行是指示的错误,如果我删除上面的行,它也可以正常工作!

[TestMethod]
    public void CreateExampleOrgStructure()
    {
        OrgStructureLogic osl = (OrgStructureLogic)ObjectFactory.GetInstance(typeof(OrgStructureLogic));
        Domain domain = osl.GetNewDomain(DomainTypeEnum.ReportingLines);
        domain.Name = string.Format("blah.Net - {0} {1}", DateTime.Now.ToLongDateString(), DateTime.Now.ToLongTimeString());

        OrgUnit ouGlobal = domain.RootOrgUnit;
        ouGlobal.Name = "Global";

        OrgUnit ouTech = GetNewOrgUnit(ouGlobal, "Technology", osl);
        AddPositionToOrgUnit(ouTech, "Chief Technology Officer", osl);
        AddPositionToOrgUnit(ouTech, "General Manager Technology", osl);

        OrgUnit ouFeatureDevelopers = GetNewOrgUnit(ouTech, "Feature Dev", osl);
        AddPositionToOrgUnit(ouFeatureDevelopers, "Senior Feature Developer", osl);
        AddPositionToOrgUnit(ouFeatureDevelopers, "Feature Developer", osl);

        OrgUnit ouSupportDevelopers = GetNewOrgUnit(ouTech, "Support Dev", osl);
        AddPositionToOrgUnit(ouSupportDevelopers, "Senior Support Developer", osl);
        AddPositionToOrgUnit(ouSupportDevelopers, "Support Developer", osl);

        OrgUnit ouDevManagement = GetNewOrgUnit(ouTech, "Management", osl);
        AddPositionToOrgUnit(ouDevManagement, "Dev Manager", osl); /* This is the problem!!!!*/
        AddPositionToOrgUnit(ouDevManagement, "Application Architect", osl);

        osl.SaveDomain(domain);
    }

甚至陌生人是我也可以解决问题的改变

private void AddPositionToOrgUnit(OrgUnit orgUnit, string positionName, OrgStructureLogic osl)
    {
        orgUnit.AddPosition(GetPositionByName(positionName), osl);
    }

private void AddPositionToOrgUnit(OrgUnit orgUnit, string positionName, OrgStructureLogic osl)
    {       
        Position position = GetPositionByName(positionName, osl);
        position.AddOrgUnit(orgUnit);
    }

跟踪堆栈后,GetHashCode的值在此处更改:

if (!position.OrgUnits.Contains(this))
{
    position.AddOrgUnit(this);
}

IE,position.GetHashCode()=“ a”,但是当我进入position.AddOrgUnit时,this.GetHashCode()为“ b”。

查看堆栈跟踪,

[Native to Managed Transition]      NHibernate.dll!NHibernate.Proxy.DefaultLazyInitializer.Intercept(NHibernate.Proxy.DynamicProxy.InvocationInfo info = {NHibernate.Proxy.DynamicProxy.InvocationInfo}) + 0x14d bytes  
PositionProxyModule.mod!PositionProxy.AddOrgUnit() + 0x1f2 bytes    

看来nHibernate代理正在妨碍您。 因此,– sl3dg3是正确的,解决方案是覆盖Equals&GetHashCode。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM