首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何正确地在nHibernate中进行双向多到多的操作

如何正确地在nHibernate中进行双向多到多的操作
EN

Stack Overflow用户
提问于 2013-09-05 00:48:56
回答 1查看 160关注 0票数 0

我正试着思考如何在NHibernate中正确地使用DotNet 4.5中的多到多关系。要使用什么集合类型以及将它们作为什么插入它们。

场景:建模OrgUnits和位置。与以下表格有许多不同的关系:

OrgUnits阵地OrgUnitPositions

我使用双向设置器,这样无论我选择orgUnit.AddPosition(位置)还是position.AddOrgUnit(orgUnit),关系都应该添加到两个集合中。

这是我的示例代码

代码语言:javascript
复制
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.AddOrgUnit: if (!value.Positions.Contains( this ))中的这一行返回false,尽管我可以在调试器中看到包含org单元。这将导致添加两次,然后在保存时出现重复的关键异常。

我尝试过各种各样的东西(我最初的集合列表/ilist),但我怀疑我的集合类型(ilist/iset/ etc )是导致这种情况的原因--希望有人能为我指明使用哪种集合类型、将它们作为什么类型,等等。

如果我调用position.AddOrgUnit(orgUnit);而不是orgUnit.AddPosition,一切都会正常工作。

-更新

作为对评论的回应,我在Position.cs中更改了Position.cs,如下所示:

代码语言:javascript
复制
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只包含一个项,而for-每个项只是为了在调试器中访问该项。

ReferenceEquals(p,这) false

p.GetHashCode() 40148707

this.GetHashCode() 53416668

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

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

p.Description "bob"

this.Description "bob"

p.description = "Jane“

this.Description "Jane"

p.description "Jane"

这就是奇怪的那个!hashCodes是不同的,但它似乎是同一个对象的同一个实例。IE,如果我在"this“版本上更改了一个属性,它就会在"p”版本中更改。

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

哪一个倾向于指示它们来自同一个hibernate会话?(父母是一样的)

下面是我的调用代码,我们将StrctureMap用于IoC,并将ISession注入到repos中。我已经将我的代码更改为在BLL中传递,这保证了相同的Isession,因为存储库被注入其中。

奇怪的是,导致错误的唯一原因是所指示的错误,如果我删除上面的行,它也会完美地工作!

代码语言:javascript
复制
[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);
    }

更奇怪的是,我也能解决问题正在改变。

代码语言:javascript
复制
private void AddPositionToOrgUnit(OrgUnit orgUnit, string positionName, OrgStructureLogic osl)
    {
        orgUnit.AddPosition(GetPositionByName(positionName), osl);
    }

代码语言:javascript
复制
private void AddPositionToOrgUnit(OrgUnit orgUnit, string positionName, OrgStructureLogic osl)
    {       
        Position position = GetPositionByName(positionName, osl);
        position.AddOrgUnit(orgUnit);
    }
EN

回答 1

Stack Overflow用户

发布于 2013-09-09 00:35:32

在堆栈跟踪之后,GetHashCode的值在这里发生变化:

代码语言:javascript
复制
if (!position.OrgUnits.Contains(this))
{
    position.AddOrgUnit(this);
}

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

看着堆栈的痕迹

代码语言:javascript
复制
[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是正确的,解决方案是覆盖等于& GetHashCode。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18626068

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档