Repository navigation
Expand file tree
/
Copy pathSqliteForeignKeyIndexConvention.cs
More file actions
98 lines (86 loc) · 4.23 KB
/
Copy pathSqliteForeignKeyIndexConvention.cs
File metadata and controls
98 lines (86 loc) · 4.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
using SQLite.CodeFirst.Extensions;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Infrastructure.Annotations;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;
using SQLite.CodeFirst.Builder.NameCreators;
namespace SQLite.CodeFirst.Convention
{
/// <summary>
/// Renames the indicies, generated by the
/// <see cref="ForeignKeyIndexConvention"/>-Convention, to match the scheme: "IX_{TableName}_{PropertyName}".
/// This is necessary because in SQLite an index-name must be unique.
/// Must be added right after the <see cref="ForeignKeyIndexConvention"/>-Convention.
/// </summary>
internal class SqliteForeignKeyIndexConvention : IStoreModelConvention<AssociationType>
{
private const string IndexAnnotationName = "http://schemas.microsoft.com/ado/2013/11/edm/customannotation:Index";
public virtual void Apply(AssociationType item, DbModel model)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
if (model == null)
{
throw new ArgumentNullException("model");
}
if (item.Constraint == null)
{
return;
}
foreach (var edmProperty in item.Constraint.ToProperties)
{
var annotation = GetAnnotation(edmProperty.MetadataProperties, IndexAnnotationName);
if (annotation == null)
{
continue;
}
string tableName = item.Constraint.ToRole.GetEntityType().GetTableName();
string propertyName = edmProperty.Name;
// The original attribute is removed. The none-ForeignKeyIndicies will be remained and readded without any modification
// and the foreignKeyIncidies will be readded with the correct name.
edmProperty.RemoveAnnotation(IndexAnnotationName);
// The schema for the automatically generated index name is "IX_{TableName}_{PropertyName}"
var noneForeignKeyIndicies = annotation.Indexes.Where(index => index.Name != "IX_" + propertyName);
var newIndexAnnotation = new IndexAnnotation(noneForeignKeyIndicies);
// The schema for a FK index, which is generated by the Entity Framework, is "IX_{PropertyName}"
var foreignKeyIndicies = annotation.Indexes.Where(index => index.Name == "IX_" + propertyName);
for (int i = 0; i < foreignKeyIndicies.Count(); i++)
{
IndexAnnotation foreignKeyIndexAnnotation = CreateIndexAnnotation(tableName, propertyName, i);
newIndexAnnotation = (IndexAnnotation)newIndexAnnotation.MergeWith(foreignKeyIndexAnnotation);
}
edmProperty.AddAnnotation(IndexAnnotationName, newIndexAnnotation);
}
}
private static IndexAnnotation CreateIndexAnnotation(string tableName, string propertyName, int count)
{
var indexName = IndexNameCreator.CreateIndexName(tableName, propertyName);
// If there are two Indicies on the same property, the count is added.
// In SQLite an Index name must be global unique.
// To be honest, it should never happen. But because its possible by using the API, it should be covered.
if (count > 0)
{
indexName = String.Format("{0}_{1}", indexName, count);
}
var indexAttribute = new IndexAttribute(indexName);
return new IndexAnnotation(indexAttribute);
}
private static IndexAnnotation GetAnnotation(IEnumerable<MetadataProperty> metadataProperties, string name)
{
foreach (MetadataProperty metadataProperty in metadataProperties)
{
if (metadataProperty.Name.Equals(name, StringComparison.Ordinal))
{
return (IndexAnnotation)metadataProperty.Value;
}
}
return null;
}
}
}