Skip to content

Commit df75d29

Browse files
committed
Merge pull request #62 from msallin/Issue-42
Issue 42
2 parents 1c12d90 + 2896aed commit df75d29

File tree

12 files changed

+165
-12
lines changed

12 files changed

+165
-12
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ Currently the following is supported:
2222
- Not Null constraint
2323
- Auto increment (An int PrimaryKey will automatically be incremented)
2424
- Index (Decorate columns with the `Index` attribute. Indices are automatically created for foreign keys by default. To prevent this you can remove the convetion `ForeignKeyIndexConvention`)
25-
- Unique constraint (Decorate columsn with the `UniqueAttribute` which is part of this library)
25+
- Unique constraint (Decorate columns with the `UniqueAttribute`, which is part of this library)
26+
- Collate constraint (Decorate columns with the `CollateAttribute`, which is part of this library)
2627

2728
I tried to write the code in a extensible way.
2829
The logic is divided into two main parts, Builder and Statement.

SQLite.CodeFirst.Console/Entity/Person.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public abstract class Person : IEntity
77
public int Id { get; set; }
88

99
[MaxLength(50)]
10+
[Collate(CollationFunction.NoCase)]
1011
public string FirstName { get; set; }
1112

1213
[MaxLength(50)]

SQLite.CodeFirst.Test/SQLite.CodeFirst.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
<Compile Include="Statement\ColumnConstraint\MaxLengthConstraint.cs" />
8181
<Compile Include="Statement\ColumnConstraint\ColumnConstraintCollectionTest.cs" />
8282
<Compile Include="Statement\ColumnConstraint\NotNullConstraintTest.cs" />
83+
<Compile Include="Statement\ColumnConstraint\CollateConstraintTest.cs" />
8384
<Compile Include="Statement\ColumnConstraint\UniqueConstraintTest.cs" />
8485
<Compile Include="Statement\ColumnStatementCollectionTest.cs" />
8586
<Compile Include="Statement\PrimaryKeyStatementTest.cs" />
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using SQLite.CodeFirst.Statement.ColumnConstraint;
3+
4+
namespace SQLite.CodeFirst.Test.Statement.ColumnConstraint
5+
{
6+
[TestClass]
7+
public class CollateConstraintTest
8+
{
9+
[TestMethod]
10+
public void CreateStatement_StatementIsCorrect_NoConstraint()
11+
{
12+
var collationConstraint = new CollateConstraint();
13+
collationConstraint.CollationFunction = CollationFunction.None;
14+
string output = collationConstraint.CreateStatement();
15+
Assert.AreEqual(output, "");
16+
}
17+
18+
[TestMethod]
19+
public void CreateStatement_StatementIsCorrect_NoCase()
20+
{
21+
var collationConstraint = new CollateConstraint();
22+
collationConstraint.CollationFunction = CollationFunction.NoCase;
23+
string output = collationConstraint.CreateStatement();
24+
Assert.AreEqual(output, "COLLATE NOCASE");
25+
}
26+
}
27+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
3+
namespace SQLite.CodeFirst
4+
{
5+
/// <summary>
6+
/// When SQLite compares two strings, it uses a collating sequence or collating function (two words for the same thing)
7+
/// to determine which string is greater or if the two strings are equal. SQLite has three built-in collating functions (see <see cref="CollationFunction"/>).
8+
/// </summary>
9+
[AttributeUsage(AttributeTargets.Property)]
10+
public sealed class CollateAttribute : Attribute
11+
{
12+
public CollateAttribute(CollationFunction collation = CollationFunction.None)
13+
{
14+
Collation = collation;
15+
}
16+
17+
public CollationFunction Collation { get; set; }
18+
}
19+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
namespace SQLite.CodeFirst
2+
{
3+
/// <summary>
4+
/// The collation function to use for this column.
5+
/// Is used together with the <see cref="CollateAttribute" />.
6+
/// </summary>
7+
public enum CollationFunction
8+
{
9+
None,
10+
11+
/// <summary>
12+
/// Compares string data using memcmp(), regardless of text encoding.
13+
/// </summary>
14+
RTrim,
15+
16+
/// <summary>
17+
/// The same as binary, except the 26 upper case characters of ASCII are folded to their lower case equivalents before
18+
/// the comparison is performed. Note that only ASCII characters are case folded. SQLite does not attempt to do full
19+
/// UTF case folding due to the size of the tables required.
20+
/// </summary>
21+
NoCase,
22+
23+
/// <summary>
24+
/// The same as binary, except that trailing space characters are ignored.
25+
/// </summary>
26+
Binary
27+
}
28+
}

SQLite.CodeFirst/DbInitializers/SqliteInitializerBase.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using SQLite.CodeFirst.Convention;
55
using System.IO;
66
using System.Linq;
7+
using SQLite.CodeFirst.Extensions;
78
using SQLite.CodeFirst.Utility;
89

910
namespace SQLite.CodeFirst
@@ -37,9 +38,11 @@ protected SqliteInitializerBase(DbModelBuilder modelBuilder)
3738
// See https://github.com/msallin/SQLiteCodeFirst/issues/7 for details.
3839
modelBuilder.Conventions.Remove<TimestampAttributeConvention>();
3940

40-
modelBuilder.Properties()
41-
.Having(x => x.GetCustomAttributes(false).OfType<UniqueAttribute>().FirstOrDefault())
42-
.Configure((config, attribute) => config.HasColumnAnnotation("IsUnique", attribute));
41+
// There is some functionality which is supported by SQLite which can not be covered
42+
// by using the data annotation attributes from the .net framework.
43+
// So there are some custom attributes.
44+
modelBuilder.RegisterAttributeAsColumnAnnotation<UniqueAttribute>();
45+
modelBuilder.RegisterAttributeAsColumnAnnotation<CollateAttribute>();
4346

4447
// By default there is a 'ForeignKeyIndexConvention' but it can be removed.
4548
// And there is no "Contains" and no way to enumerate the ConventionsCollection.

SQLite.CodeFirst/Internal/Builder/ColumnStatementCollectionBuilder.cs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Data.Entity.Core.Metadata.Edm;
33
using System.Globalization;
44
using System.Linq;
5+
using SQLite.CodeFirst.Extensions;
56
using SQLite.CodeFirst.Statement;
67
using SQLite.CodeFirst.Statement.ColumnConstraint;
78

@@ -37,6 +38,7 @@ private IEnumerable<ColumnStatement> CreateColumnStatements()
3738
AdjustDatatypeForAutogenerationIfNecessary(property, columnStatement);
3839
AddNullConstraintIfNecessary(property, columnStatement);
3940
AddUniqueConstraintIfNecessary(property, columnStatement);
41+
AddCollationConstraintIfNecessary(property, columnStatement);
4042

4143
yield return columnStatement;
4244
}
@@ -68,17 +70,21 @@ private static void AddNullConstraintIfNecessary(EdmProperty property, ColumnSta
6870
}
6971
}
7072

73+
private static void AddCollationConstraintIfNecessary(EdmProperty property, ColumnStatement columnStatement)
74+
{
75+
var value = property.GetCustomAnnotation<CollateAttribute>();
76+
if (value != null)
77+
{
78+
columnStatement.ColumnConstraints.Add(new CollateConstraint { CollationFunction = value.Collation });
79+
}
80+
}
81+
7182
private static void AddUniqueConstraintIfNecessary(EdmProperty property, ColumnStatement columnStatement)
7283
{
73-
MetadataProperty item;
74-
bool found = property.MetadataProperties.TryGetValue("http://schemas.microsoft.com/ado/2013/11/edm/customannotation:IsUnique", true, out item);
75-
if (found)
84+
var value = property.GetCustomAnnotation<UniqueAttribute>();
85+
if (value != null)
7686
{
77-
var value = (UniqueAttribute)item.Value;
78-
columnStatement.ColumnConstraints.Add(new UniqueConstraint
79-
{
80-
OnConflict = value.OnConflict
81-
});
87+
columnStatement.ColumnConstraints.Add(new UniqueConstraint { OnConflict = value.OnConflict });
8288
}
8389
}
8490
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Data.Entity;
2+
using System.Linq;
3+
4+
namespace SQLite.CodeFirst.Extensions
5+
{
6+
internal static class DbModelBuilderExtensions
7+
{
8+
public static void RegisterAttributeAsColumnAnnotation<TAttribute>(this DbModelBuilder modelBuilder)
9+
where TAttribute : class
10+
{
11+
modelBuilder.Properties()
12+
.Having(x => x.GetCustomAttributes(false).OfType<TAttribute>().FirstOrDefault())
13+
.Configure((config, attribute) => config.HasColumnAnnotation(typeof(TAttribute).Name, attribute));
14+
}
15+
}
16+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
using System.Data.Entity.Core.Metadata.Edm;
3+
4+
namespace SQLite.CodeFirst.Extensions
5+
{
6+
internal static class EdmPropertyExtensions
7+
{
8+
public static TAttribute GetCustomAnnotation<TAttribute>(this EdmProperty property)
9+
where TAttribute : Attribute
10+
{
11+
MetadataProperty item;
12+
bool found = property.MetadataProperties.TryGetValue("http://schemas.microsoft.com/ado/2013/11/edm/customannotation:" + typeof(TAttribute).Name, true, out item);
13+
if (found)
14+
{
15+
return (TAttribute) item.Value;
16+
}
17+
18+
return null;
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)