Skip to content

Commit f263df5

Browse files
authored
Merge pull request #85 from DataObjects-NET/ignorehint-path-gets-invalid
Skips hints which paths became irrelevant during schema diff processing
2 parents 81333f5 + dd4a06e commit f263df5

File tree

2 files changed

+139
-11
lines changed

2 files changed

+139
-11
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Copyright (C) 2020 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+
// Created by: Alexey Kulakov
5+
// Created: 2020.03.04
6+
7+
using NUnit.Framework;
8+
using System;
9+
using System.Collections.Generic;
10+
using System.Linq;
11+
using System.Reflection;
12+
using System.Text;
13+
using Xtensive.Orm.Configuration;
14+
using Xtensive.Orm.Tests.Issues.IssueJira0796_IgnoreHintPathGetsInvalidModel;
15+
using Xtensive.Orm.Validation;
16+
using Xtensive.Sql;
17+
using Xtensive.Sql.Dml;
18+
using Xtensive.Caching;
19+
using Xtensive.Orm.Upgrade;
20+
using Xtensive.Modelling.Comparison.Hints;
21+
using Xtensive.Orm.Upgrade.Model;
22+
using Xtensive.Orm.Services;
23+
24+
namespace Xtensive.Orm.Tests.Issues
25+
{
26+
[TestFixture]
27+
public class IssueJira0796_IgnoreHintPathGetsInvalid
28+
{
29+
private const string CreateIndexQuery = @"
30+
CREATE NONCLUSTERED INDEX [custom_NonClusteredIndex-20200304-164347] ON [dbo].[SomeEntity2] (
31+
[FirstName] ASC,
32+
[LastName] ASC)
33+
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF,
34+
DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)";
35+
36+
[Test]
37+
public void MainTest()
38+
{
39+
Require.ProviderIs(StorageProvider.SqlServer);
40+
41+
var configuration = DomainConfigurationFactory.Create();
42+
configuration.UpgradeMode = DomainUpgradeMode.Recreate;
43+
configuration.Types.Register(typeof (SomeEntity1));
44+
configuration.Types.Register(typeof (SomeEntity2));
45+
46+
using (var domain = Domain.Build(configuration))
47+
using (var session = domain.OpenSession())
48+
using (var transaction = session.OpenTransaction()) {
49+
var accessor = session.Services.Get<DirectSqlAccessor>();
50+
using (var command = accessor.CreateCommand()) {
51+
command.CommandText = CreateIndexQuery;
52+
_ = command.ExecuteNonQuery();
53+
}
54+
transaction.Complete();
55+
}
56+
57+
configuration = DomainConfigurationFactory.Create();
58+
configuration.UpgradeMode = DomainUpgradeMode.Perform;
59+
configuration.Types.Register(typeof(SomeEntity1));
60+
configuration.Types.Register(typeof(CustomUpgradeHandler));
61+
62+
Assert.DoesNotThrow(() => Domain.Build(configuration).Dispose());
63+
}
64+
}
65+
}
66+
67+
namespace Xtensive.Orm.Tests.Issues.IssueJira0796_IgnoreHintPathGetsInvalidModel
68+
{
69+
[HierarchyRoot]
70+
public class SomeEntity1 : Entity
71+
{
72+
[Field, Key]
73+
public int Id { get; set; }
74+
75+
[Field]
76+
public string FirstName { get; set; }
77+
78+
[Field]
79+
public string LastName { get; set; }
80+
}
81+
82+
[HierarchyRoot]
83+
public class SomeEntity2 : Entity
84+
{
85+
[Field, Key]
86+
public int Id { get; set; }
87+
88+
[Field]
89+
public string FirstName { get; set; }
90+
91+
[Field]
92+
public string LastName { get; set; }
93+
}
94+
95+
public class CustomUpgradeHandler : UpgradeHandler
96+
{
97+
private class KeepCustomIndicesMarkerHint : Hint
98+
{
99+
public override IEnumerable<HintTarget> GetTargets() => Enumerable.Empty<HintTarget>();
100+
}
101+
102+
private const string CustomIndexPrefix = "custom_";
103+
104+
public override void OnSchemaReady()
105+
{
106+
if (UpgradeContext.Stage == UpgradeStage.Upgrading) {
107+
var schemaHints = UpgradeContext.SchemaHints;
108+
var storageModel = (StorageModel) schemaHints.SourceModel;
109+
110+
foreach (var table in storageModel.Tables) {
111+
foreach (var index in table.SecondaryIndexes) {
112+
var name = index.Name;
113+
if (!name.StartsWith(CustomIndexPrefix)) {
114+
continue;
115+
}
116+
var ignoreHint = new IgnoreHint(index.Path);
117+
schemaHints.Add(ignoreHint);
118+
}
119+
}
120+
}
121+
}
122+
}
123+
}

Orm/Xtensive.Orm/Modelling/Comparison/Upgrader.cs

Lines changed: 16 additions & 11 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-2020 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: Alex Yakunin
55
// Created: 2009.04.07
66

@@ -122,20 +122,23 @@ public ReadOnlyList<NodeAction> GetUpgradeSequence(Difference difference, HintSe
122122
{
123123
ArgumentValidator.EnsureArgumentNotNull(hints, "hints");
124124
ArgumentValidator.EnsureArgumentNotNull(comparer, "comparer");
125-
if (difference == null)
125+
if (difference == null) {
126126
return new ReadOnlyList<NodeAction>(Enumerable.Empty<NodeAction>().ToList());
127+
}
127128

128129
TemporaryRenames = new Dictionary<string, Node>(StringComparer.OrdinalIgnoreCase);
129130
SourceModel = (IModel) difference.Source;
130131
TargetModel = (IModel) difference.Target;
131132
Hints = hints ?? new HintSet(SourceModel, TargetModel);
132133
Comparer = comparer;
133-
if (Hints.SourceModel!=SourceModel)
134+
if (Hints.SourceModel != SourceModel) {
134135
throw new ArgumentOutOfRangeException("hints.SourceModel");
135-
if (Hints.TargetModel!=TargetModel)
136+
}
137+
if (Hints.TargetModel != TargetModel) {
136138
throw new ArgumentOutOfRangeException("hints.TargetModel");
139+
}
137140

138-
CurrentModel = (IModel)SourceModel.Clone(null, SourceModel.Name);
141+
CurrentModel = (IModel) SourceModel.Clone(null, SourceModel.Name);
139142
Difference = difference;
140143
var previous = currentAsync.Value;
141144
currentAsync.Value = this;
@@ -152,15 +155,17 @@ public ReadOnlyList<NodeAction> GetUpgradeSequence(Difference difference, HintSe
152155
ProcessStage(UpgradeStage.Cleanup, actions);
153156

154157
var validationHints = new HintSet(CurrentModel, TargetModel);
155-
Hints.OfType<IgnoreHint>().ForEach(validationHints.Add);
158+
Hints.OfType<IgnoreHint>()
159+
.Where(h => CurrentModel.Resolve(h.Path, false) != null && SourceModel.Resolve(h.Path, false) != null)
160+
.ForEach(validationHints.Add);
156161
var diff = comparer.Compare(CurrentModel, TargetModel, validationHints);
157-
if (diff!=null) {
162+
if (diff != null) {
158163
CoreLog.InfoRegion(Strings.LogAutomaticUpgradeSequenceValidation);
159164
CoreLog.Info(Strings.LogValidationFailed);
160165
CoreLog.Info(Strings.LogItemFormat, Strings.Difference);
161166
CoreLog.Info("{0}", diff);
162-
CoreLog.Info(Strings.LogItemFormat+"\r\n{1}", Strings.UpgradeSequence,
163-
new ActionSequence() {actions});
167+
CoreLog.Info(Strings.LogItemFormat + "\r\n{1}", Strings.UpgradeSequence,
168+
new ActionSequence() { actions });
164169
CoreLog.Info(Strings.LogItemFormat, Strings.ExpectedTargetModel);
165170
TargetModel.Dump();
166171
CoreLog.Info(Strings.LogItemFormat, Strings.ActualTargetModel);

0 commit comments

Comments
 (0)