12

TFS 릴리스 관리를 사용하여 지속적인 통합 및 배포를 수행하고 있습니다.이전 버전을 배포하기위한 EF 코드 우선 마이그레이션

전 배포 중에 데이터베이스 마이그레이션을 수행하기 위해 migrate.exe를 사용하고 있습니다. 이전 버전에서 최신 버전으로 전환 할 때 유용합니다. 그러나 이전 버전의 응용 프로그램을 배포하려는 경우 더 진부 해집니다.

기본적으로 컨텍스트에 대한 마이그레이션을 보유하고있는 어셈블리는 버전 3에서 버전 2로 이동하는 방법을 알아야합니다. 일반적으로 배포 할 어셈블리를 마이그레이션 원본으로 사용하지만이 이미 배포 된 어셈블리는 v3에서 v2로 전환하는 방법을 알고있는 유일한 멤버이므로 사용해야합니다. (버전 2에서는 v3도 존재하지 않는다는 것을 알 수 있습니다.)

현재의 계획은 배포 중에 어떻게 든 두 어셈블리를 비교하는 것입니다. 설치 디렉토리에있는 어셈블리가 배포 이사의보다 "새로운"마이그레이션을 포함하는 경우, 내가 먼저 배포 디렉토리에있는 어셈블리의 "최신"가능한 마이그레이션을 얻을 필요가 다음 실행합니다 :

migrate.exe AssemblyInInstallationDir /targetMigration NewestFromAssemblyInDeploymentDir 

어디 새 버전으로 업그레이드하는 "정상적인"배포 시나리오에서, 당신은 다만 할 수 있습니다

migrate.exe AssemblyInDeploymentDir 

이 합법적 인 방법인가? 아직 각 EF 라이브러리를 사용하여 각 어셈블리에서 사용할 수있는 마이그레이션을 평가할 필요가 없습니다. 이 어셈블리들 각각은 "같은"다른 버전이라는 사실에 대한 도전도 있습니다. 별도의 앱 도메인에로드 한 다음 교차 앱 도메인 통신을 사용하여 필요한 정보를 가져와야 할 것입니다.

편집

나는 나 같은 어셈블리의 두 가지 버전으로 사용할 수있는 마이그레이션을 나열 할 수 있습니다 개념 응용 프로그램의 증거를 만들었습니다. 이것은이 전체 과정에서 매우 중요했기 때문에 문서화 할 가치가 있다고 생각했습니다.

응용 프로그램은 리플렉션을 사용하여 각 어셈블리를로드 한 다음 System.Data.Entity.Migrations의 DbMigrator 클래스를 사용하여 마이그레이션 메타 데이터를 열거합니다. 마이그레이션 이름에는 타임 스탬프 정보가 접두어로 붙어있어서이를 주문하고 어떤 어셈블리에 "더 새로운"마이그레이션 세트가 포함되어 있는지 확인할 수 있습니다.

Curent Version: Test.Data, Version=1.3.0.0, Culture=neutral, PublicKeyToken=null 
Target Version: Test.Data, Version=1.2.0.0, Culture=neutral, PublicKeyToken=null 

Current Context Migrations: 
    201403171700348_InitalCreate 
    201403171701519_AddedAddresInfoToCustomer 
    201403171718277_RemovedStateEntity 
    201403171754275_MoveAddressInformationIntoContactInfo 
    201403181559219_NotSureWhatIChanged 
    201403181731525_AddedRowVersionToDomainObjectBase 
Target Context Migrations: 
    201403171700348_InitalCreate 
    201403171701519_AddedAddresInfoToCustomer 
    201403171718277_RemovedStateEntity 
+1

나는이이 작업을 수행 할 수있는 승인 된 방법이지만, 문서화하고 당신의 접근 방식을 공유하기위한 칭찬 여부에 대한 답을 모르는 예를 들면 다음과 같습니다. –

답변

2

우리는 실제로이 문제를 해결했으며 1 년 넘게 툴링을 사용하여 완전히 지속적인 데이터베이스 배포를 생산에 적용했습니다. 인간이 관여하지 않았습니다. :)

우리는 GitHub의에이 공용의 일부를했습니다 : 변경을 "파괴"https://github.com/GalenHealthcare/Galen.Ef.Deployer

당신은 할 수 있지만, 일반적으로, 우리는 그뿐만 아니라 피 -하지만 대부분 우리의 응용 프로그램을 업그레이드하는 동안 라이브 남아 있기 때문에. 우리는 데이터 계층을 독립적으로 배포 할 수있는 구성 요소로 취급하므로 결과적으로 호환성을 유지해야하는 "인터페이스"가 있습니다.

역방향/포워드 호환 가능한 중간 버전을 배포하고 다양한 응용 프로그램 서비스를 업그레이드 한 다음 마지막으로 데이터베이스 계층을 업그레이드하여 기존 호환성을 제거하는 경우 다단계 업그레이드 방식을 사용합니다.

해당 시나리오에서도 Google 스키마와 데이터의 버전을 자동으로/(으)로 이동할 수 있습니다. 실제로 우리는 모든 단일 데이터베이스 버전을 위해 빌드 할 때마다이를 확인하는 단위 테스트를 추가했습니다. 기본적으로 스키마 반복 체인을 위/아래로 이동하고 상향식 및 하향식 마이그레이션이 항상 작동하며 데이터 일관성 및 호환성을 유지하는지 확인합니다. GitHub 프로젝트에서 이러한 테스트를 볼 수 있습니다.

https://github.com/GalenHealthcare/Galen.Ef.Deployer/blob/master/Galen.Ci.EntityFramework.Deployer/Galen.Ci.EntityFramework.Testing/MigrationTestRunner.cs

0

방법 나는 일반적으로이 파괴 내 데이터베이스 스키마에을 변경하지 않습니다 결코 (거의)이다 접근 :

static void Main(string[] args) 
{ 
    const string dllName = "Test.Data.dll"; 
    var assemblyCurrent = Assembly.LoadFile(Path.Combine(System.Environment.CurrentDirectory, string.Format("Current\\{0}", dllName))); 
    var assemblyTarget = Assembly.LoadFile(Path.Combine(System.Environment.CurrentDirectory, string.Format("Target\\{0}", dllName))); 

    Console.WriteLine("Curent Version: " + assemblyCurrent.FullName); 
    Console.WriteLine("Target Version: " + assemblyTarget.FullName); 

    const string contextName = "Test.Data.TestContext"; 
    const string migrationsNamespace = "Test.Data.Migrations"; 
    var currentContext = assemblyCurrent.CreateInstance(contextName); 
    var targetContext = assemblyTarget.CreateInstance(contextName); 

    var currentContextConfig = new DbMigrationsConfiguration 
    { 
     MigrationsAssembly = assemblyCurrent, 
     ContextType = currentContext.GetType(), 
     MigrationsNamespace = migrationsNamespace 
    }; 

    var targetContextConfig = new DbMigrationsConfiguration 
    { 
     MigrationsAssembly = assemblyTarget, 
     ContextType = targetContext.GetType(), 
     MigrationsNamespace = migrationsNamespace 
    }; 

    var migrator = new DbMigrator(currentContextConfig); 
    var localMigrations = migrator.GetLocalMigrations(); //all migrations 

    Console.WriteLine("Current Context Migrations:"); 
    foreach (var m in localMigrations) 
    { 
     Console.WriteLine("\t{0}", m); 
    } 

    migrator = new DbMigrator(targetContextConfig); 
    localMigrations = migrator.GetLocalMigrations(); //all migrations 

    Console.WriteLine("Target Context Migrations:"); 
    foreach (var m in localMigrations) 
    { 
     Console.WriteLine("\t{0}", m); 
    } 

    Console.ReadKey(); 
} 

}

응용 프로그램의 출력은 같다. 그것은 기본적으로 기술적 부채의 통제 된 형태입니다.

예를 들어, 내가 ColumnX를 ColumnY로 바꾸고 있다고 가정 해 봅시다. 일반적인 접근 방식은 "모든 데이터를 ColumnX에서 ColumnY로 복사하고 ColumnX는 스키마에서 제거"입니다. ColumnX가 없어 졌으므로 이전 버전으로 롤백 할 수 없게됩니다.

롤백하기 쉬운 방법은 ColumnY를 추가하고 데이터를 복사 한 다음 트리거를 추가하여 두 열을 서로 동기화되도록 유지하는 것입니다. 이것은 영구적 인 국가로 의도 된 것이 아닙니다!"ColumnX 및 관련 트리거 제거"에 대한 사용자 스토리는 즉시 백 로그에서 처리되므로 향후 반복을 위해 ColumnX에 종속 된 버전으로 롤백되지 않을 것입니다.

롤백에는 스키마에없는 데이터베이스에있는 항목을 삭제하지 않도록주의하면서 DACPAC의 이전 버전을 게시해야합니다. 이렇게하면 ColumnY에서 가져 오도록 여러 저장 프로 시저를 업데이트 한 경우 ColumnX에서 가져온 이전 버전을 게시 할 수 있으며 이전 버전에서는 스키마가 변경되었음을 기쁜 마음으로 알 수 있습니다.

관련 문제