Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Currently the following is supported:
- Not Null constraint
- Auto increment (An int PrimaryKey will automatically be incremented)
- 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`)
- Unique constraint (Decorate columsn with the `UniqueAttribute` which is part of this library)

I tried to write the code in a extensible way.
The logic is divided into two main parts, Builder and Statement.
Expand Down
1 change: 1 addition & 0 deletions SQLite.CodeFirst.Console/Entity/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace SQLite.CodeFirst.Console.Entity
public class Player : Person
{
[Index] // Automatically named 'IX_TeamPlayer_Number'
[Unique(OnConflictAction.Fail)]
public int Number { get; set; }

public virtual Team Team { get; set; }
Expand Down
1 change: 1 addition & 0 deletions SQLite.CodeFirst.Test/SQLite.CodeFirst.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
<Compile Include="Statement\ColumnConstraint\MaxLengthConstraint.cs" />
<Compile Include="Statement\ColumnConstraint\ColumnConstraintCollectionTest.cs" />
<Compile Include="Statement\ColumnConstraint\NotNullConstraintTest.cs" />
<Compile Include="Statement\ColumnConstraint\UniqueConstraintTest.cs" />
<Compile Include="Statement\ColumnStatementCollectionTest.cs" />
<Compile Include="Statement\PrimaryKeyStatementTest.cs" />
<Compile Include="Statement\CreateDatabaseStatementTest.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SQLite.CodeFirst.Statement.ColumnConstraint;

namespace SQLite.CodeFirst.Test.Statement.ColumnConstraint
{
[TestClass]
public class UniqueConstraintTest
{
[TestMethod]
public void CreateStatement_StatementIsCorrect_NoConstraint()
{
var uniqueConstraint = new UniqueConstraint();
uniqueConstraint.OnConflict = OnConflictAction.None;
string output = uniqueConstraint.CreateStatement();
Assert.AreEqual(output, "UNIQUE");
}

[TestMethod]
public void CreateStatement_StatementIsCorrect_WithConstraint()
{
var uniqueConstraint = new UniqueConstraint();
uniqueConstraint.OnConflict = OnConflictAction.Rollback;
string output = uniqueConstraint.CreateStatement();
Assert.AreEqual(output, "UNIQUE ON CONFLICT ROLLBACK");
}
}
}
16 changes: 16 additions & 0 deletions SQLite.CodeFirst/Attributes/OnConflictAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace SQLite.CodeFirst
{
/// <summary>
/// The action to resolve a UNIQUE constraint violation.
/// Is used together with the <see cref="UniqueAttribute"/>.
/// </summary>
public enum OnConflictAction
{
None,
Rollback,
Abort,
Fail,
Ignore,
Replace
}
}
18 changes: 18 additions & 0 deletions SQLite.CodeFirst/Attributes/UniqueAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace SQLite.CodeFirst
{
/// <summary>
/// The UNIQUE Constraint prevents two records from having identical values in a particular column.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public sealed class UniqueAttribute : Attribute
{
public UniqueAttribute(OnConflictAction onConflict = OnConflictAction.None)
{
OnConflict = onConflict;
}

public OnConflictAction OnConflict { get; set; }
}
}
5 changes: 5 additions & 0 deletions SQLite.CodeFirst/DbInitializers/SqliteInitializerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Data.Entity.ModelConfiguration.Conventions;
using SQLite.CodeFirst.Convention;
using System.IO;
using System.Linq;
using SQLite.CodeFirst.Utility;

namespace SQLite.CodeFirst
Expand Down Expand Up @@ -36,6 +37,10 @@ protected SqliteInitializerBase(DbModelBuilder modelBuilder)
// See https://github.com/msallin/SQLiteCodeFirst/issues/7 for details.
modelBuilder.Conventions.Remove<TimestampAttributeConvention>();

modelBuilder.Properties()
.Having(x => x.GetCustomAttributes(false).OfType<UniqueAttribute>().FirstOrDefault())
.Configure((config, attribute) => config.HasColumnAnnotation("IsUnique", attribute));

// By default there is a 'ForeignKeyIndexConvention' but it can be removed.
// And there is no "Contains" and no way to enumerate the ConventionsCollection.
// So a try/catch will do the job.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ private IEnumerable<ColumnStatement> CreateColumnStatements()
AddMaxLengthConstraintIfNecessary(property, columnStatement);
AdjustDatatypeForAutogenerationIfNecessary(property, columnStatement);
AddNullConstraintIfNecessary(property, columnStatement);
AddUniqueConstraintIfNecessary(property, columnStatement);

yield return columnStatement;
}
Expand Down Expand Up @@ -66,5 +67,19 @@ private static void AddNullConstraintIfNecessary(EdmProperty property, ColumnSta
columnStatement.ColumnConstraints.Add(new NotNullConstraint());
}
}

private static void AddUniqueConstraintIfNecessary(EdmProperty property, ColumnStatement columnStatement)
{
MetadataProperty item;
bool found = property.MetadataProperties.TryGetValue("http://schemas.microsoft.com/ado/2013/11/edm/customannotation:IsUnique", true, out item);
if (found)
{
var value = (UniqueAttribute)item.Value;
columnStatement.ColumnConstraints.Add(new UniqueConstraint
{
OnConflict = value.OnConflict
});
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Text;

namespace SQLite.CodeFirst.Statement.ColumnConstraint
{
internal class UniqueConstraint : IColumnConstraint
{
private const string Template = "UNIQUE {conflict-clause}";

public OnConflictAction OnConflict { get; set; }

public string CreateStatement()
{
var sb = new StringBuilder(Template);

sb.Replace("{conflict-clause}", OnConflict != OnConflictAction.None ? "ON CONFLICT " + OnConflict.ToString().ToUpperInvariant() : string.Empty);

return sb.ToString().Trim();
}
}
}
3 changes: 3 additions & 0 deletions SQLite.CodeFirst/SQLite.CodeFirst.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,13 @@
<Compile Include="..\Shared\AssemblySharedInfo.cs">
<Link>Properties\AssemblySharedInfo.cs</Link>
</Compile>
<Compile Include="Attributes\OnConflictAction.cs" />
<Compile Include="Attributes\UniqueAttribute.cs" />
<Compile Include="Entities\IHistory.cs" />
<Compile Include="Internal\Builder\NameCreators\IndexNameCreator.cs" />
<Compile Include="Internal\Builder\NameCreators\SpecialChars.cs" />
<Compile Include="IDatabaseCreator.cs" />
<Compile Include="Internal\Statement\ColumnConstraint\UniqueConstraint.cs" />
<Compile Include="Internal\Utility\HashCreator.cs" />
<Compile Include="Internal\Utility\HistoryEntityTypeValidator.cs" />
<Compile Include="ISqliteSqlGenerator.cs" />
Expand Down