Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Table mapping for UniqueColumn uses unstable GetHashCode() method #1769

Closed
Scooletz opened this issue Jun 22, 2018 · 5 comments
Closed

Table mapping for UniqueColumn uses unstable GetHashCode() method #1769

Scooletz opened this issue Jun 22, 2018 · 5 comments

Comments

@Scooletz
Copy link

Scooletz commented Jun 22, 2018

The snippet below presents the way how Table class generates UniqueColumn name. This value is used in several code paths, like CreateForeignKey and/or generating an unique column name itself.

public string UniqueColumnString(IEnumerable iterator, string referencedEntityName)
{
// NH Different implementation (NH-1399)
int result = 37;
if (referencedEntityName != null)
{
result ^= referencedEntityName.GetHashCode();
}
foreach (object o in iterator)
{
result ^= o.GetHashCode();
}
return (name.GetHashCode().ToString("X") + result.GetHashCode().ToString("X"));

string.GetHashCode is not a stable hashing function, according to the documentation

The hash code itself is not guaranteed to be stable. Hash codes for identical strings can differ across versions of the .NET Framework and across platforms (such as 32-bit and 64-bit) for a single version of the .NET Framework. In some cases, they can even differ by application domain. This implies two subsequent runs of the same program may return different hash codes.

Creating the script then, can have a different outcome when run in two different environments, like .NET Core 2.1 and net461 or even across 32/64 bits.

@fredericDelaporte
Copy link
Member

fredericDelaporte commented Jun 22, 2018

Anyway using a hashcode for attempting getting something unique is a bug on its own, since hashcodes are never guaranteed unique. Another naming algorithm has to be put in place.

@ramonsmits
Copy link
Contributor

Alternatively use something like https://github.com/LogosBible/Logos.Utility/blob/master/src/Logos.Utility/GuidUtility.cs to generate a cross platform stable uuid

@maca88
Copy link
Contributor

maca88 commented Jun 24, 2018

Hibernate fixed this problem by postponing the generation until the reference table is known, after that they generate the name by concatenating the table and the columns names and hashing the result with the MD5 algorithm in order to avoid too long names.

@fredericDelaporte
Copy link
Member

We should likely do the postponing. But then, the hashing part can be troublesome, since collisions may occur, even if it is quite unlikely. Moreover it guarantees a name only shorter than thirty characters, while we have dialects having MaxAliasLength as small as eighteen.

@fredericDelaporte
Copy link
Member

fredericDelaporte commented Jul 16, 2018

Worse for the .Net Core case, as written in #1791, the generated names change at each run under .Net Core. So .Net Core is in the following case:

In some cases, they can even differ by application domain. This implies two subsequent runs of the same program may return different hash codes.

The following code yields different strings at each run under netcoreapp2.0:

[Test]
public void UniqueName()
{
	var tbl = new Table { Name = "name" };
	Console.Write(tbl.UniqueColumnString(new[] { "col1", "col2" }, "ent1"));
}

fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this issue Jul 16, 2018
fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this issue Jul 16, 2018
fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this issue Jul 16, 2018
fredericDelaporte added a commit to fredericDelaporte/nhibernate-core that referenced this issue Jul 17, 2018
@fredericDelaporte fredericDelaporte added this to the 5.2 milestone Jul 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants