唯一键我已经在我的项目与EF代码第一
public class Category
{
public Guid ID { get; set; }
[Required(ErrorMessage = "Title cannot be empty")]
public string Title { get; set; }
}
,我试图让Title
作为唯一键下面的模型,我用Google搜索解决方案,但找不到任何。 有什么建议我该怎么做?
唯一键我已经在我的项目与EF代码第一
public class Category
{
public Guid ID { get; set; }
[Required(ErrorMessage = "Title cannot be empty")]
public string Title { get; set; }
}
,我试图让Title
作为唯一键下面的模型,我用Google搜索解决方案,但找不到任何。 有什么建议我该怎么做?
不幸的是,你不能首先在代码中将它定义为唯一键,因为EF根本不支持唯一键(它有望为下一个主要版本计划)。你可以做的是通过调用SQL命令手动创建自定义数据库初始化程序,并添加唯一索引:
public class MyInitializer : CreateDatabaseIfNotExists<MyContext>
{
protected override void Seed(MyContext context)
{
context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX IX_Category_Title ON Categories (Title)");
}
}
而且你必须在应用程序的引导设置这个初始化。
Database.SetInitializer<MyContext>(new MyInitializer());
编辑
现在(EF 6.1起),您可以轻松拥有独特的约束,
[Index("TitleIndex", IsUnique = true)]
public string Title { get; set; }
这里是VB.Net版本 - 请注意泛型的实现,是一个在课堂上一点也不一样。
Public Class MyInitializer(Of T As DbContext)
Inherits CreateDatabaseIfNotExists(Of T)
Protected Overrides Sub Seed(context As T)
context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX IX_Category_Title ON Categories (Title)")
End Sub
End Class
哦来吧 - 添加一个简洁的VB版本有什么问题,对于vb用户有完全相同的问题?这不是这个问题 - 不仅为原始海报提供资源?另外,如上所述,实施有所不同。 – GilShalit 2014-06-23 04:44:53
首先创建自定义属性类:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class UniqueAttribute : ValidationAttribute
{
public override Boolean IsValid(Object value)
{
// constraint implemented on database
return true;
}
}
然后添加到您的类:
public class Email
{
[Key]
public int EmailID { get; set; }
public int PersonId { get; set; }
[Unique]
[Required]
[MaxLength(100)]
public string EmailAddress { get; set; }
public virtual bool IsDefault { get; set; }
public virtual Boolean IsApprovedForLogin { get; set; }
public virtual String ConfirmationToken { get; set; }
[ForeignKey("PersonId")]
public virtual Person Person { get; set; }
}
然后在你的DbContext添加一个初始值设定:
public class Initializer : IDatabaseInitializer<myEntities>
{
public void InitializeDatabase(myEntities context)
{
if (System.Diagnostics.Debugger.IsAttached && context.Database.Exists() && !context.Database.CompatibleWithModel(false))
{
context.Database.Delete();
}
if (!context.Database.Exists())
{
context.Database.Create();
var contextObject = context as System.Object;
var contextType = contextObject.GetType();
var properties = contextType.GetProperties();
System.Type t = null;
string tableName = null;
string fieldName = null;
foreach (var pi in properties)
{
if (pi.PropertyType.IsGenericType && pi.PropertyType.Name.Contains("DbSet"))
{
t = pi.PropertyType.GetGenericArguments()[0];
var mytableName = t.GetCustomAttributes(typeof(TableAttribute), true);
if (mytableName.Length > 0)
{
TableAttribute mytable = mytableName[0] as TableAttribute;
tableName = mytable.Name;
}
else
{
tableName = pi.Name;
}
foreach (var piEntity in t.GetProperties())
{
if (piEntity.GetCustomAttributes(typeof(UniqueAttribute), true).Length > 0)
{
fieldName = piEntity.Name;
context.Database.ExecuteSqlCommand("ALTER TABLE " + tableName + " ADD CONSTRAINT con_Unique_" + tableName + "_" + fieldName + " UNIQUE (" + fieldName + ")");
}
}
}
}
}
}
}
而且为最后添加Initializ呃在Application.Start里面Global.asax.cs
System.Data.Entity.Database.SetInitializer<MyApp.Models.DomainModels.myEntities>(new MyApp.Models.DomainModels.myEntities.Initializer());
就是这样。基于在vb代码https://stackoverflow.com/a/7426773
几个更正。 1.在ExecuteSqlCommand期间,tableName应该被括起来。2.如果你使用的是非复数名称,使用else {tableName = t.Name} – James 2012-10-25 21:29:12
我创建这个类(这是从另一个Stackoverflow答案 - Execute a large SQL script (with GO commands)增强),它允许我将SQL脚本放入一个目录,并让他们都执行每次需要(种子或迁移)。在部署到生产环境后,我不打算将其打开,但在开发期间,每次重新创建数据库时都可以轻松应用脚本。
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//dll Microsoft.SqlServer.Smo
//dll Microsoft.SqlServer.Management.Sdk.Sfc
//dll Microsoft.SqlServer.ConnectionInfo
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Monitor.Common;
namespace MonitorDB.DataLayer.Migrations
{
public class ExecuteSQLScripts :Monitor.Common.ExceptionHandling
{
public ExecuteSQLScripts()
{
}
public bool ExecuteScriptsInDirectory(DBContext.SolArcMsgMonitorContext context, string scriptDirectory)
{
bool Result = false;
try
{
SqlConnection connection = new SqlConnection(context.Database.Connection.ConnectionString);
Server server = new Server(new ServerConnection(connection));
DirectoryInfo di = new DirectoryInfo(scriptDirectory);
FileInfo[] rgFiles = di.GetFiles("*.sql");
foreach (FileInfo fi in rgFiles)
{
FileInfo fileInfo = new FileInfo(fi.FullName);
string script = fileInfo.OpenText().ReadToEnd();
server.ConnectionContext.ExecuteNonQuery(script);
}
Result = true;
}
catch (Exception ex)
{
CatchException("ExecuteScriptsInDirectory", ex);
}
return Result;
}
} }
这里是VS的解决方案是什么样子:
我发现这个解决方案,它虽然没有创造在SQL级别的唯一密钥,它使用DataAnnotations验证,检查出来:
我使用MVC 3和EF 4,代码无法识别context.Database.ExecuteSqlCommand中的ExecuteSqlCommand(“CREATE UNIQUE INDEX IX_Category_Title ON Categories(Title)”);这是关于版本还是其他? – Saeid 2011-11-16 10:48:31
@Saeid:这是用于DbContext API(EFv4.1)的。 EFv4中没有数据库初始值设定项。 ObjectContext API提供了自己的方法来直接执行SQL - “ExecuteStoreCommand”。 – 2011-11-16 11:01:38
也是一个很好的方法来添加默认约束(例如,GETDATE()等) – 2012-09-28 13:49:09