Skip to content

Commit 775877c

Browse files
committed
NH-1452 - Add support for property-ref keys in join table
Original patch by Daniel Guenter was applied with code cleanup and minor fixes
1 parent d229631 commit 775877c

File tree

11 files changed

+399
-19
lines changed

11 files changed

+399
-19
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
using NHibernate.Cfg;
2+
using NHibernate.Criterion;
3+
using NUnit.Framework;
4+
5+
namespace NHibernate.Test.NHSpecificTest.NH1452
6+
{
7+
[TestFixture]
8+
public class Fixture : BugTestCase
9+
{
10+
protected override void Configure(Configuration configuration)
11+
{
12+
base.Configure(configuration);
13+
configuration.SetProperty(Environment.FormatSql, "false");
14+
}
15+
16+
/// <summary>
17+
/// push some data into the database
18+
/// Really functions as a save test also
19+
/// </summary>
20+
protected override void OnSetUp()
21+
{
22+
using (var session = OpenSession())
23+
using (var tran = session.BeginTransaction())
24+
{
25+
session.Save(new Product
26+
{
27+
ProductId = "XO1234",
28+
Id = 1,
29+
Name = "Some product",
30+
Description = "Very good"
31+
});
32+
33+
session.Save(new Product
34+
{
35+
ProductId = "XO54321",
36+
Id = 2,
37+
Name = "Other product",
38+
Description = "Very bad"
39+
});
40+
41+
tran.Commit();
42+
}
43+
}
44+
45+
protected override void OnTearDown()
46+
{
47+
base.OnTearDown();
48+
49+
using (var session = OpenSession())
50+
using (var tran = session.BeginTransaction())
51+
{
52+
session.Delete("from Product");
53+
tran.Commit();
54+
}
55+
}
56+
57+
[Test]
58+
public void Delete_single_record()
59+
{
60+
using (var session = OpenSession())
61+
{
62+
var product = new Product
63+
{
64+
ProductId = "XO1111",
65+
Id = 3,
66+
Name = "Test",
67+
Description = "Test"
68+
};
69+
70+
session.Save(product);
71+
72+
session.Flush();
73+
74+
session.Delete(product);
75+
session.Flush();
76+
77+
session.Clear();
78+
79+
//try to query for this product
80+
product = session.CreateCriteria(typeof (Product))
81+
.Add(Restrictions.Eq("ProductId", "XO1111"))
82+
.UniqueResult<Product>();
83+
84+
Assert.That(product, Is.Null);
85+
}
86+
}
87+
88+
[Test]
89+
public void Query_records()
90+
{
91+
using (var sqlLog = new SqlLogSpy())
92+
using (var session = OpenSession())
93+
{
94+
var product = session.CreateCriteria(typeof (Product))
95+
.Add(Restrictions.Eq("ProductId", "XO1234"))
96+
.UniqueResult<Product>();
97+
98+
Assert.That(product, Is.Not.Null);
99+
Assert.That(product.Description, Is.EqualTo("Very good"));
100+
101+
var log = sqlLog.GetWholeLog();
102+
//needs to be joining on the Id column not the productId
103+
Assert.That(log.Contains("inner join ProductLocalized this_1_ on this_.Id=this_1_.Id"), Is.True);
104+
}
105+
}
106+
107+
[Test]
108+
public void Update_record()
109+
{
110+
using (var session = OpenSession())
111+
{
112+
var product = session.CreateCriteria(typeof (Product))
113+
.Add(Restrictions.Eq("ProductId", "XO1234"))
114+
.UniqueResult<Product>();
115+
116+
Assert.That(product, Is.Not.Null);
117+
118+
product.Name = "TestValue";
119+
product.Description = "TestValue";
120+
121+
session.Flush();
122+
session.Clear();
123+
124+
//pull again
125+
product = session.CreateCriteria(typeof (Product))
126+
.Add(Restrictions.Eq("ProductId", "XO1234"))
127+
.UniqueResult<Product>();
128+
129+
Assert.That(product, Is.Not.Null);
130+
Assert.That(product.Name, Is.EqualTo("TestValue"));
131+
Assert.That(product.Description, Is.EqualTo("TestValue"));
132+
}
133+
}
134+
}
135+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test"
3+
namespace="NHibernate.Test.NHSpecificTest.NH1452">
4+
<class name="Product" table="Products">
5+
<id name="ProductId" column="ProductId" type="String" generator="assigned" />
6+
<property name="Name" column="Name" />
7+
<property name="Id" column="Id" unique="true"/>
8+
<join table="ProductLocalized">
9+
<key column="Id" property-ref="Id"/>
10+
<property name="Description" column="Description"/>
11+
</join>
12+
</class>
13+
</hibernate-mapping>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace NHibernate.Test.NHSpecificTest.NH1452
2+
{
3+
public class Product
4+
{
5+
public virtual string ProductId { get; set; }
6+
7+
public virtual int Id { get; set; }
8+
9+
public virtual string Name { get; set; }
10+
11+
public virtual string Description { get; set; }
12+
}
13+
}

src/NHibernate.Test/NHibernate.Test.csproj

+3
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,8 @@
847847
<Compile Include="NHSpecificTest\NH3160\FixtureByCode.cs" />
848848
<Compile Include="NHSpecificTest\NH3037\Entity.cs" />
849849
<Compile Include="NHSpecificTest\NH3037\FixtureByCode.cs" />
850+
<Compile Include="NHSpecificTest\NH1452\Fixture.cs" />
851+
<Compile Include="NHSpecificTest\NH1452\Product.cs" />
850852
<Compile Include="NHSpecificTest\NH2347\Entity.cs" />
851853
<Compile Include="NHSpecificTest\NH2347\Fixture.cs" />
852854
<Compile Include="NHSpecificTest\NH2664\Product.cs" />
@@ -3142,6 +3144,7 @@
31423144
<EmbeddedResource Include="NHSpecificTest\NH3139\Mappings.hbm.xml" />
31433145
<EmbeddedResource Include="NHSpecificTest\NH2812\Mappings.hbm.xml" />
31443146
<EmbeddedResource Include="NHSpecificTest\NH3141\Mappings.hbm.xml" />
3147+
<EmbeddedResource Include="NHSpecificTest\NH1452\Mappings.hbm.xml" />
31453148
<EmbeddedResource Include="NHSpecificTest\NH2664\Mappings.hbm.xml" />
31463149
<EmbeddedResource Include="NHSpecificTest\NH2214\Mappings.hbm.xml" />
31473150
<EmbeddedResource Include="NHSpecificTest\NH2960\Mappings.hbm.xml" />

src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs

+27-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,33 @@ private void BindJoin(HbmJoin joinMapping, Join join, IDictionary<string, MetaAt
195195
log.InfoFormat("Mapping class join: {0} -> {1}", persistentClass.EntityName, join.Table.Name);
196196

197197
// KEY
198-
SimpleValue key = new DependantValue(table, persistentClass.Identifier);
198+
SimpleValue key;
199+
if (!String.IsNullOrEmpty(joinMapping.key.propertyref))
200+
{
201+
string propertyRef = joinMapping.key.propertyref;
202+
var propertyRefKey = new SimpleValue(persistentClass.Table)
203+
{
204+
IsAlternateUniqueKey = true
205+
};
206+
var property = persistentClass.GetProperty(propertyRef);
207+
join.RefIdProperty = property;
208+
//we only want one column
209+
var column = (Column) property.ColumnIterator.First();
210+
if (!column.Unique)
211+
throw new MappingException(
212+
string.Format(
213+
"Property {0}, on class {1} must be marked as unique to be joined to with a property-ref.",
214+
property.Name,
215+
persistentClass.ClassName));
216+
propertyRefKey.AddColumn(column);
217+
propertyRefKey.TypeName = property.Type.Name;
218+
key = new ReferenceDependantValue(table, propertyRefKey);
219+
}
220+
else
221+
{
222+
key = new DependantValue(table, persistentClass.Identifier);
223+
}
224+
199225
key.ForeignKeyName = joinMapping.key.foreignkey;
200226
join.Key = key;
201227
key.IsCascadeDeleteEnabled = joinMapping.key.ondelete == HbmOndelete.Cascade;

src/NHibernate/Mapping/Join.cs

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public void AddProperty(Property prop)
3737
prop.PersistentClass = PersistentClass;
3838
}
3939

40+
//if we are joining to a non pk, this is the property of the class that serves as id
41+
public Property RefIdProperty { get; set; }
42+
4043
public bool ContainsProperty(Property prop)
4144
{
4245
return properties.Contains(prop);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace NHibernate.Mapping
5+
{
6+
/// <summary>
7+
///
8+
/// </summary>
9+
[Serializable]
10+
public class ReferenceDependantValue : DependantValue
11+
{
12+
private readonly SimpleValue _prototype;
13+
14+
public ReferenceDependantValue(Table table, SimpleValue prototype)
15+
: base(table, prototype)
16+
{
17+
_prototype = prototype;
18+
}
19+
20+
public IEnumerable<Column> ReferenceColumns
21+
{
22+
get { return _prototype.ConstraintColumns; }
23+
}
24+
25+
public override void CreateForeignKeyOfEntity(string entityName)
26+
{
27+
if (!HasFormula && !string.Equals("none", ForeignKeyName, StringComparison.InvariantCultureIgnoreCase))
28+
{
29+
var referencedColumns = new List<Column>(_prototype.ColumnSpan);
30+
foreach (Column column in _prototype.ColumnIterator)
31+
{
32+
referencedColumns.Add(column);
33+
}
34+
35+
ForeignKey fk = Table.CreateForeignKey(ForeignKeyName, ConstraintColumns, entityName, referencedColumns);
36+
fk.CascadeDeleteEnabled = IsCascadeDeleteEnabled;
37+
}
38+
}
39+
}
40+
}

src/NHibernate/Mapping/SimpleValue.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public virtual bool IsComposite
7373

7474
#region IKeyValue Members
7575

76-
public void CreateForeignKeyOfEntity(string entityName)
76+
public virtual void CreateForeignKeyOfEntity(string entityName)
7777
{
7878
if (!HasFormula && ! "none".Equals(ForeignKeyName, StringComparison.InvariantCultureIgnoreCase))
7979
{

src/NHibernate/NHibernate.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@
526526
<Compile Include="Mapping\PrimaryKey.cs" />
527527
<Compile Include="Mapping\PrimitiveArray.cs" />
528528
<Compile Include="Mapping\Property.cs" />
529+
<Compile Include="Mapping\ReferenceDependantValue.cs" />
529530
<Compile Include="Mapping\RootClass.cs" />
530531
<Compile Include="Mapping\Set.cs" />
531532
<Compile Include="Mapping\SimpleValue.cs" />

0 commit comments

Comments
 (0)