2011-05-03 3 views
1

그래서 재미있는 문제가 발생했습니다. PowerPivot 쿼리에서 사용자 지정 WHERE 절을 지정해야합니다. 외부 조건에 따라 변경해야합니다. 파일을 편집하고 사본을 저장하고 싶습니다. 어떤 생각을 어떻게 할 것인가? 바이너리에서 PowerPivot 파일을 열었지만 암호화되어 나타납니다 ...PowerPivot 파일의 연결 데이터 변경

답변

0

해결 방법 Excel 통합 문서를 Zip으로 열 수 있습니다 (Package 클래스 사용).

쿼리를 수정하려는 경우 가능합니다. /xl/customData/item1.data의 파일은 쿼리를 처리하는 데 사용되는 PowerPivot 데이터베이스 (Vertipaq 모드로 실행되는 Analysis Services 데이터베이스)를 나타내는 백업 파일입니다. 파일을 Vertipaq 모드에서 실행중인 SSAS 인스턴스로 복원해야합니다. 완료되면 쿼리를 ALTER 스크립트로 스크립팅하십시오. 스크립트 (이 경우 @projectId를 실제 projectID로 바꾸기)를 수정 한 다음 데이터베이스에 대해 스크립트를 실행하십시오. 이 모든 작업이 완료되면 데이터베이스를 다시 가져 와서 Excel 통합 문서로 되돌립니다. 그것은 쿼리를 수정합니다.

연결 데이터는 /xl/connections.xml 파일에 저장됩니다. 열어서 수정하고 바꾸십시오. 모든 것을 다시 포장하십시오. 이제 통합 문서가 다시 생깁니다.

내가 작성한 코드는 다음과 같습니다. 필요에 따라 메소드를 호출해야합니다. 그래도 기본적인 아이디어가 있습니다.

const string DBName = "Testing"; 
    const string OriginalBackupPath = @"\\MyLocation\BKUP.abf"; 
    const string ModifiedBackupPath = @"\\MyLocation\BKUPAfter.abf"; 
    const string ServerPath = @"machineName\powerpivot"; 

    private static readonly Server srv = new Server(); 
    private static readonly Scripter scripter = new Scripter(); 
    private static Database db; 

    private static byte[] GetPackagePartContents(string packagePath, string partPath) 
    { 
     var pack = Package.Open(packagePath, FileMode.OpenOrCreate, FileAccess.ReadWrite); 
     var part = pack.GetPart(new Uri(partPath, UriKind.Relative)); 
     var stream = part.GetStream(); 
     var b = new byte[stream.Length]; 
     stream.Read(b, 0, b.Length); 
     stream.Flush(); 
     stream.Close(); 
     pack.Flush(); 
     pack.Close(); 
     return b; 
    } 

    private static void WritePackagePartContents(string packagePath, string partPath, byte[] contents) 
    { 
     var uri = new Uri(partPath, UriKind.Relative); 
     var pack = Package.Open(packagePath, FileMode.OpenOrCreate, FileAccess.ReadWrite); 
     var part = pack.GetPart(uri); 
     var type = part.ContentType; 
     pack.DeletePart(uri); 
     pack.CreatePart(uri, type); 
     part = pack.GetPart(uri); 
     var stream = part.GetStream(); 
     stream.Write(contents, 0, contents.Length); 
     stream.Flush(); 
     stream.Close(); 
     pack.Flush(); 
     pack.Close(); 
    } 

    private static void RestoreBackup(string server, string dbName, string backupPath) 
    { 
     srv.Connect(server); 
     if (srv.Databases.FindByName(dbName) != null) { srv.Databases.FindByName(dbName).Drop(); srv.Update(); } 
     srv.Restore(backupPath, dbName, true); 
     srv.Update(); 
     srv.Refresh(); 
    } 

    private static void WriteContentsToFile(byte[] contents, string filePath) 
    { 
     var fileStream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write); 
     fileStream.Write(contents, 0, contents.Length); 
     fileStream.Flush(); 
     fileStream.Close(); 
    } 

    private static byte[] ReadContentsFromFile(string filePath) 
    { 
     var fileStream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write); 
     var b = new byte[fileStream.Length]; 
     fileStream.Read(b, 0, b.Length); 
     fileStream.Flush(); 
     fileStream.Close(); 
     return b; 
    } 

    private static XDocument GetAlterScript(MajorObject obj) 
    { 
     var stream = new MemoryStream(); 
     var streamWriter = XmlWriter.Create(stream); 
     scripter.ScriptAlter(new[] { obj }, streamWriter, false); 
     streamWriter.Flush(); 
     streamWriter.Close(); 
     stream.Flush(); 
     stream.Position = 0; 
     var b = new byte[stream.Length]; 
     stream.Read(b, 0, b.Length); 
     var alterString = new string(Encoding.UTF8.GetString(b).ToCharArray().Where(w => w != 65279).ToArray()); 
     var alter = XDocument.Parse(alterString); 
     stream.Close(); 
     return alter; 
    } 

    private static void ExecuteScript(string script) 
    { 
     srv.Execute(script); 
     srv.Update(); 
     db.Process(); 
     db.Refresh(); 
    } 



    private static void ProcessPowerpointQueries(string bookUrl, string projectId) 
    { 
     byte[] b = GetPackagePartContents(bookUrl, "/xl/customData/item1.data"); 
     WriteContentsToFile(b, OriginalBackupPath); 
     RestoreBackup(ServerPath, DBName, OriginalBackupPath); 
     var db = srv.Databases.GetByName(DBName); 
     var databaseView = db.DataSourceViews.FindByName("Sandbox"); 
     var databaseViewAlter = GetAlterScript(databaseView); 
     var cube = db.Cubes.FindByName("Sandbox"); 
     var measureGroup = cube.MeasureGroups.FindByName("Query"); 
     var partition = measureGroup.Partitions.FindByName("Query"); 
     var partitionAlter = GetAlterScript(partition); 
     var regex = new Regex(@"\[email protected]=\w*[ ,]"); 
     var newDatabaseViewAlter = databaseViewAlter.ToString().Replace(regex.Match(databaseViewAlter.ToString()).Value.Trim(',',' '), @"@projectid=" + projectId); 
     ExecuteScript(newDatabaseViewAlter); 
     var newPartitionAlter = partitionAlter.ToString().Replace(regex.Match(partitionAlter.ToString()).Value.Trim(',', ' '), @"@projectid=" + projectId); 
     ExecuteScript(newPartitionAlter); 
     db.Backup(ModifiedBackupPath, true); 
     WritePackagePartContents(bookUrl, @"/xl/customData/item1.data", ReadContentsFromFile(ModifiedBackupPath)); 
     db.Drop(); 
     srv.Disconnect(); 
    } 

    private static void ProcessWorkbookLinks(string bookUrl, string newCoreUrl) 
    { 
     var connectionsFile = GetPackagePartContents(bookUrl, @"/xl/connections.xml"); 
     var connectionsXml = Encoding.UTF8.GetString(connectionsFile); 
     connectionsXml = connectionsXml.Replace(
      new Regex(@"Data Source=\S*;").Match(connectionsXml).Value.Trim(';'), @"Data Source=" + newCoreUrl); 
     WritePackagePartContents(bookUrl, @"/xl/connections.xml", connectionsXml.Replace(@"https://server/site/", newCoreUrl).ToCharArray().Select(Convert.ToByte).ToArray()); 
    } 
+0

CamronBlue, 해당 코드 세트를 제공해 주셔서 감사합니다. 지금 구현 중이 야. 이 기능이 Office 2010 용 PowerPivot과 함께 제공되지 않는다고 거의 믿을 수 없습니다. 특정 Excel 통합 문서에 대해이 코드를 실제로 어떻게 실행 했습니까? COM 개체 또는 다른 것으로 패키지 했습니까? 대신 VBA를 통해 위에서 수행 한 것과 동일한 작업을 수행 할 수 있습니까? 나는 다른 언어보다 VBA에 훨씬 더 익숙하다. 감사! –

+0

@Brad .NET 라이브러리에서 위 코드를 구현했습니다. COM으로 패키지하지 않았으므로 VBA를 사용할 수 있는지 확실하지 않습니다. COM 개체로 패키지화하고 VBA에서 호출 할 수 있는지 알아 보려면 몇 가지 조사를해야 할 수도 있습니다. – CamronBute

+0

발췌 해 주셔서 감사합니다. 나는 그것이 도움이 될 것이라고 확신한다. 'Server','Database','Scripter' 클래스는 어디에서 왔는지 말해 줄 수 있습니까? 그것은 공식 API/라이브러리의 일부입니까 아니면 프로그램을 작성 했습니까? 감사. –

1

기존 연결로 이동하여 업데이트 할 수 있습니다. 기존 연결에서 매개 변수를 변경하는 대신 동일한 데이터 원본 (SQL, SSRS 또는 다른 항목)을 다시 열면 PowerPivot에서 해당 연결을 개별 연결로 처리하므로 처리 속도가 느려집니다.