我正试着思考如何在NHibernate中正确地使用DotNet 4.5中的多到多关系。要使用什么集合类型以及将它们作为什么插入它们。
场景:建模OrgUnits和位置。与以下表格有许多不同的关系:
OrgUnits阵地OrgUnitPositions
我使用双向设置器,这样无论我选择orgUnit.AddPosition(位置)还是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.AddOrgUnit: if (!value.Positions.Contains( this ))中的这一行返回false,尽管我可以在调试器中看到包含org单元。这将导致添加两次,然后在保存时出现重复的关键异常。
我尝试过各种各样的东西(我最初的集合列表/ilist),但我怀疑我的集合类型(ilist/iset/ etc )是导致这种情况的原因--希望有人能为我指明使用哪种集合类型、将它们作为什么类型,等等。
如果我调用position.AddOrgUnit(orgUnit);而不是orgUnit.AddPosition,一切都会正常工作。
-更新
作为对评论的回应,我在Position.cs中更改了Position.cs,如下所示:
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,因为存储库被注入其中。
奇怪的是,导致错误的唯一原因是所指示的错误,如果我删除上面的行,它也会完美地工作!
[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);
}发布于 2013-09-09 00:35:32
在堆栈跟踪之后,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是正确的,解决方案是覆盖等于& GetHashCode。
https://stackoverflow.com/questions/18626068
复制相似问题