Skip to content

Commit b681f8e

Browse files
authored
Merge pull request #228 from DataObjects-NET/7.0-oracle-schemas-fix
Oracle: schemas extraction fix
2 parents 6f00508 + 32721b3 commit b681f8e

File tree

7 files changed

+161
-10
lines changed

7 files changed

+161
-10
lines changed

ChangeLog/7.0.3_dev.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
[sqlserver] Fixed TimeSpan.Ticks extraction problem
1+
[main] NodeCollection supports different equality comparers for internal name index
2+
[sqlserver] Fixed TimeSpan.Ticks extraction problem
3+
[oracle] Fixed scheme extraction for case-sensitive schema names

Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/v09/Extractor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,9 @@ protected virtual string ToUpperInvariantIfNeeded(string schemaName)
142142

143143
private ExtractionContext CreateContext(string catalogName, string[] schemaNames)
144144
{
145-
var catalog = new Catalog(catalogName);
145+
var catalog = new Catalog(catalogName, true);
146146
for(var i = 0; i < schemaNames.Length; i++) {
147-
schemaNames[i] = schemaNames[i].ToUpperInvariant();
147+
schemaNames[i] = ToUpperInvariantIfNeeded(schemaNames[i]);
148148
}
149149

150150
var replacements = new Dictionary<string, string>();

Orm/Xtensive.Orm.Tests.Framework/StorageTestHelper.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
1+
// Copyright (C) 2009-2022 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44
// Created by: Denis Krjuchkov
55
// Created: 2009.12.17
66

@@ -51,13 +51,16 @@ public static void DemandSchemas(ConnectionInfo connectionInfo, params string[]
5151
var extractionResult = driver.Extract(connection, new[] {extractionTask});
5252
var catalog = extractionResult.Catalogs.Single();
5353
var existingSchemas = catalog.Schemas.Select(s => s.Name);
54-
var schemasToCreate = schemas.Except(existingSchemas, StringComparer.OrdinalIgnoreCase);
5554

5655
// Oracle does not support creating schemas, user should be created instead.
57-
if (connectionInfo.Provider==WellKnown.Provider.Oracle)
56+
if (connectionInfo.Provider == WellKnown.Provider.Oracle) {
57+
var schemasToCreate = schemas.Except(existingSchemas, StringComparer.Ordinal);
5858
CreateUsers(connection, schemasToCreate);
59-
else
59+
}
60+
else {
61+
var schemasToCreate = schemas.Except(existingSchemas, StringComparer.OrdinalIgnoreCase);
6062
CreateSchemas(connection, catalog, schemasToCreate);
63+
}
6164

6265
connection.Close();
6366
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright (C) 2022 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
4+
5+
using System.Linq;
6+
using NUnit.Framework;
7+
using Xtensive.Orm.Configuration;
8+
using M = Xtensive.Orm.Tests.Storage.Multimapping.CaseSensitiveSchemasTestModel;
9+
10+
namespace Xtensive.Orm.Tests.Storage.Multimapping.CaseSensitiveSchemasTestModel
11+
{
12+
namespace Schema1
13+
{
14+
[HierarchyRoot]
15+
public class Entity1 : Entity
16+
{
17+
[Field, Key]
18+
public int Id { get; private set; }
19+
20+
[Field]
21+
public string OriginalSchemaName { get; set; }
22+
}
23+
}
24+
25+
namespace Schema2
26+
{
27+
[HierarchyRoot]
28+
public class Entity2 : Entity
29+
{
30+
[Field, Key]
31+
public int Id { get; private set; }
32+
33+
[Field]
34+
public string OriginalSchemaName { get; set; }
35+
}
36+
}
37+
}
38+
39+
namespace Xtensive.Orm.Tests.Storage.Multimapping
40+
{
41+
public sealed class CaseSensitiveSchemasTest : MultimappingTest
42+
{
43+
private const string Schema1Name = WellKnownSchemas.Schema1;
44+
45+
private readonly string schema1UpperCaseName = Schema1Name.ToUpperInvariant();
46+
47+
protected override void CheckRequirements() => Require.ProviderIs(StorageProvider.Oracle);
48+
49+
protected override DomainConfiguration BuildConfiguration()
50+
{
51+
var configuration = base.BuildConfiguration();
52+
configuration.DefaultSchema = Schema1Name;
53+
configuration.Types.Register(typeof(M.Schema1.Entity1));
54+
configuration.Types.Register(typeof(M.Schema2.Entity2));
55+
var rules = configuration.MappingRules;
56+
rules.Map(typeof(M.Schema1.Entity1).Namespace).ToSchema(Schema1Name);
57+
rules.Map(typeof(M.Schema2.Entity2).Namespace).ToSchema(schema1UpperCaseName);
58+
return configuration;
59+
}
60+
61+
[Test]
62+
public void MainTest()
63+
{
64+
BuildInitialDomain();
65+
BuildUpgradedDomain();
66+
}
67+
68+
private void BuildInitialDomain()
69+
{
70+
var config = BuildConfiguration();
71+
PrepareSchema(config.ConnectionInfo);
72+
var domain = Domain.Build(config);
73+
using (domain) {
74+
using (var session = domain.OpenSession())
75+
using (var tx = session.OpenTransaction()) {
76+
_ = new M.Schema1.Entity1 { OriginalSchemaName = Schema1Name };
77+
_ = new M.Schema2.Entity2 { OriginalSchemaName = schema1UpperCaseName };
78+
tx.Complete();
79+
}
80+
}
81+
}
82+
83+
private void BuildUpgradedDomain()
84+
{
85+
var config = BuildConfiguration();
86+
config.UpgradeMode = DomainUpgradeMode.PerformSafely;
87+
var domain = Domain.Build(config);
88+
using (domain) {
89+
using (var session = domain.OpenSession())
90+
using (var tx = session.OpenTransaction()) {
91+
var e1 = session.Query.All<M.Schema1.Entity1>().Single();
92+
var e2 = session.Query.All<M.Schema2.Entity2>().Single();
93+
Assert.That(e1.OriginalSchemaName, Is.EqualTo(Schema1Name));
94+
Assert.That(e2.OriginalSchemaName, Is.EqualTo(schema1UpperCaseName));
95+
tx.Complete();
96+
}
97+
}
98+
}
99+
100+
private void PrepareSchema(ConnectionInfo connectionInfo)
101+
{
102+
StorageTestHelper.DemandSchemas(
103+
connectionInfo, Schema1Name, schema1UpperCaseName);
104+
}
105+
}
106+
}

Orm/Xtensive.Orm/Sql/Model/Catalog.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,20 @@ internal string GetActualDbName(IDictionary<string, string> catalogNameMap)
198198

199199
// Constructors
200200

201-
public Catalog(string name) : base(name)
201+
public Catalog(string name)
202+
: base(name)
202203
{
203204
schemas =
204205
new PairedNodeCollection<Catalog, Schema>(this, "Schemas", 1);
205206
}
207+
208+
public Catalog(string name, bool caseSensitiveNames = false)
209+
: base(name)
210+
{
211+
schemas = caseSensitiveNames
212+
? new PairedNodeCollection<Catalog, Schema>(this, "Schemas", 1, StringComparer.Ordinal)
213+
: new PairedNodeCollection<Catalog, Schema>(this, "Schemas", 1, StringComparer.OrdinalIgnoreCase);
214+
}
215+
206216
}
207217
}

Orm/Xtensive.Orm/Sql/Model/NodeCollection.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,5 +84,16 @@ public NodeCollection(int capacity)
8484
{
8585
nameIndex = new Dictionary<string, TNode>(capacity, Comparer);
8686
}
87+
88+
/// <summary>
89+
/// Initializes new instance of this type.
90+
/// </summary>
91+
/// <param name="capacity">The initial collection capacity.</param>
92+
/// <param name="comparer">Comparer for inner name index.</param>
93+
public NodeCollection(int capacity, IEqualityComparer<string> comparer)
94+
: base(capacity)
95+
{
96+
nameIndex = new Dictionary<string, TNode>(capacity, comparer);
97+
}
8798
}
8899
}

Orm/Xtensive.Orm/Sql/Model/PairedNodeCollection.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System;
66
using System.Collections;
7+
using System.Collections.Generic;
78
using Xtensive.Core;
89

910
namespace Xtensive.Sql.Model
@@ -73,6 +74,24 @@ public PairedNodeCollection(TOwner owner, string property, int capacity)
7374
this.property = property;
7475
}
7576

77+
/// <summary>
78+
/// Initializes a new instance of the <see cref="PairedNodeCollection{TOwner,TNode}"/> class.
79+
/// </summary>
80+
/// <param name="owner">The collection owner.</param>
81+
/// <param name="property">Owner collection property.</param>
82+
/// <param name="capacity">The initial collection capacity.</param>
83+
/// <param name="equalityComparer">Comparer for inner name index.</param>
84+
public PairedNodeCollection(TOwner owner, string property, int capacity, IEqualityComparer<string> equalityComparer)
85+
: base(capacity, equalityComparer)
86+
{
87+
ArgumentValidator.EnsureArgumentNotNull(owner, nameof(owner));
88+
ArgumentValidator.EnsureArgumentNotNullOrEmpty(property, nameof(property));
89+
ArgumentValidator.EnsureArgumentNotNull(equalityComparer, nameof(equalityComparer));
90+
91+
this.owner = owner;
92+
this.property = property;
93+
}
94+
7695
#endregion
7796
}
7897
}

0 commit comments

Comments
 (0)