먼저 EF 코드가있는 고유 키
내 프로젝트에 다음 모델이 있습니다.
public class Category
{
public Guid ID { get; set; }
[Required(ErrorMessage = "Title cannot be empty")]
public string Title { get; set; }
}
Title고유 키로 만들려고하는데 솔루션을 검색했지만 찾을 수 없었습니다. 방법을 제안 해 주시겠습니까?
불행히도 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; }
먼저 사용자 정의 속성 클래스를 만듭니다.
[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 + ")");
}
}
}
}
}
}
}
마지막으로 Global.asax.cs 내부 Application_Start에 Initializer를 추가하십시오.
System.Data.Entity.Database.SetInitializer<MyApp.Models.DomainModels.myEntities>(new MyApp.Models.DomainModels.myEntities.Initializer());
That's it. based on the vb code at https://stackoverflow.com/a/7426773
Here is the VB.Net version - note the implementation of generics that is a little different, at the class level.
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
I create this class (which ws enhanced from another Stackoverflow answer -Execute a large SQL script (with GO commands)), which allows me to drop in the SQL scripts into a directory, and have them all executed each time they are required (Seed, or Migration). I'm not going to leave this open after I deploy to production, but during development it makes it easy to apply scripts each time the DB is recreated.
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;
}
} }
Here is what the VS Solution looks like:

I found this solution which although not creating a unique-key in the SQL level, it uses DataAnnotations validation, check it out:
참고URL : https://stackoverflow.com/questions/5701608/unique-key-with-ef-code-first
'program story' 카테고리의 다른 글
| DropDownList 컨트롤에 RequiredFieldValidator를 추가하는 방법은 무엇입니까? (0) | 2020.11.27 |
|---|---|
| Android에서 SD 카드의 텍스트 파일을 어떻게 읽을 수 있습니까? (0) | 2020.11.27 |
| 폴링없이 파일 변경 감지 (0) | 2020.11.27 |
| Html.EnumDropdownListFor : 기본 텍스트 표시 (0) | 2020.11.26 |
| Android Studio에서 Gradle '오프라인 모드'를 비활성화하는 방법은 무엇입니까? (0) | 2020.11.26 |