8

EFのSystem.Data.Entity.Migrations.Infrastructure.IMigrationMetadataインターフェイスのセマンティクスを調べようとしています。DB移行の管理と適用に使用されていることを知っています。しかし、私はそれについての詳細な情報を見つけることができません。具体的には、私が知りたいのは:

  1. Sourceプロパティはどのように使用されますか?ツールを使用して移行を生成すると、なぜ常にnullになるのですか?
  2. どのTargetプロパティが使用されますか?ツールがBase64のようなものを生成し、リソースに配置されていることがわかります。それは何ですか?なぜそれがそのような非友好的な形式で生成されるのですか?
  3. ツールを使用せずに手動で移行を開発することは可能ですか?どういうわけか生成されるべきそのTargetプロパティBase64のような値のためにそれは簡単ではないと思います。私は正しいですか?
  4. このインターフェースが実際に使用されるのはいつですか?現時点では、このインターフェイスを実装していない移行は、移行者が自動的に見つけることができないことがわかりました。私は正しいですか?それがインターフェースの唯一の目的ですか?
4

3 に答える 3

13

IMigrationMetadata インターフェイスには、私が知っている次の役割があります。

  1. ID プロパティを使用して移行を識別し、 などのコマンドで認識して含めることができるようにしますUpdate-Database
  2. Target プロパティを介して移行が適用された後のモデルのスナップショットをそのまま提供します。これは、新しい移行に含める必要がある変更を決定するために使用されます。

の実装では必要ないため、Source プロパティはツールによって実装されないことが多いと推測していますAdd-Migration。そのコードはおそらく、最新の既存の移行の最後にあったモデルと、コードから生成されたモデルを比較して、新しい移行に含める必要がある変更を判断するだけです。

Target プロパティは、GZipStream を使用して圧縮され、Convert.ToBase64String を使用してエンコードされたモデルを EDMX 形式で返します。これらの値をデコードおよびエンコードするために、次のコードを作成しました。移行を手動でコーディングする場合は、おそらくこれが役立つでしょう。

using System;
using System.IO;
using System.IO.Compression;
using System.Text;

namespace ConsoleApplication6
{
    class Program
    {
        static void Main()
        {
            var minimalModel = File.ReadAllText("Model1.edmx");

            var encodedMinimalModel = Encode(minimalModel);

            var decodedMinimalModel = Decode(encodedMinimalModel);
        }

        private static string Decode(string encodedText)
        {
            var compressedBytes = Convert.FromBase64String(encodedText);

            var decompressedBytes = Decompress(compressedBytes);

            return Encoding.UTF8.GetString(decompressedBytes);
        }

        private static string Encode(string plainText)
        {
            var bytes = Encoding.UTF8.GetBytes(plainText);

            var compressedBytes = Compress(bytes);

            return Convert.ToBase64String(compressedBytes);
        }

        public static byte[] Decompress(byte[] bytes)
        {
            using (var memorySteam = new MemoryStream(bytes))
            {
                using (var gzipStream = new GZipStream(memorySteam, CompressionMode.Decompress))
                {
                    return ToByteArray(gzipStream);
                }
            }
        }

        private static byte[] ToByteArray(Stream stream)
        {
            using (var resultMemoryStream = new MemoryStream())
            {
                stream.CopyTo(resultMemoryStream);

                return resultMemoryStream.ToArray();
            }
        }

        public static byte[] Compress(byte[] bytes)
        {
            using (var memoryStream = new MemoryStream())
            {
                using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress))
                {
                    gzipStream.Write(bytes,0, bytes.Length);
                }

                return memoryStream.ToArray();
            }
        }
    }
}

圧縮はおそらく、人間が読めない形式が選択された理由に関するクエリを説明します。このコンテンツは、移行ごとに (Target プロパティで) 少なくとも 1 回繰り返され、モデルのサイズによっては大きくなる可能性があります。圧縮によりスペースが節約されます。

その点については、私が見る限り、適用後にモデルの真の表現を返す必要があるのは、実際には最後の移行だけです。その移行のみがAdd-Migration、新しい移行に必要な変更を計算するために使用されます。非常に大きなモデルや非常に多数の移行を扱っている場合は、そのコンテンツを削除すると有利になる可能性があります。この投稿の残りの部分では、最新の移行以外のすべてで使用できる Target プロパティの最小値の導出について説明します。

Target プロパティは文字列オブジェクトを返す必要があります。ターゲットが null を返す場合、update-database が呼び出されると、System.Data.Entity.Migrations.DbMigrator.ApplyMigration の System.Convert.FromBase64String への呼び出しで ArgumentNullException がスローされます。

さらに、有効な XML ドキュメントである必要があります。Target から空の文字列を返すと、「ルート要素が見つかりません」というメッセージとともに XmlException が発生しました。

この時点から、上記のコードを使用して値をエンコードしました。

たとえば、モデルを徐々に構築することではあまりうまくいかなかった<root />ので、プロジェクトに新しい「ADO.Netエンティティデータモデル」を追加して生成した空のEDMXファイルから要素を破棄することに切り替えました。 「空のモデル」オプション。これが結果でした。

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="3.0" xmlns:edmx="http://schemas.microsoft.com/ado/2009/11/edmx">
  <edmx:Runtime>
    <edmx:StorageModels>
      <Schema xmlns="http://schemas.microsoft.com/ado/2009/11/edm/ssdl" Namespace="Model1.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2005">
      </Schema>
    </edmx:StorageModels>
  </edmx:Runtime>
</edmx:Edmx>

上記のコードを使用してこれをエンコードすると、これが結果でした。

H4sIAAAAAAAEAJVQy07DMBC8I/EP1t6xExASRA1VVTgWIYK4W/amtfCjeN2q/D12HsqJAxdLOzOe2Z3V+uIsO2MkE3wLNa+AoVdBG79v4ZT6mwdYP11frVC7S/OSH/Y5i++KOH/31BS2hUNKx0YIUgd0krgzKgYKfeIqOCF1ELdV9SjqWhQ5ZFfGRt/3k0/G4YDMWJdClHvcBY2WJiZz3WA+xv4vURBpC+xVOqSjVNjC4F3zkoTANtbIbNmh7YG9xXA2GmOefyih488ySd5926016NMi2ElveqT0Eb4wd5Lz7mHZVozrzoeJPy6biKWGCSh95+kXfT3Qv6UBAAA=

以前のバージョンにロールバックする必要がある場合に備えて、ソース管理で各移行の実際のターゲット値を保持するように注意してください。移行をデータベースに適用してから、Visual Studio を使用して EDMX ファイルを生成してみてください。もう 1 つの方法は、モデルを形成するクラスをロールバックしてから実行することAdd-Migrationです。新しく作成された移行からターゲット値を取得します。

于 2013-02-22T15:33:20.823 に答える
-2

codeplexのEF6リポジトリに移動すると、次のように表示されます。

public interface IMigrationMetadata
{
    /// <summary>
    ///     Gets the unique identifier for the migration.
    /// </summary>
    string Id { get; }

    /// <summary>
    ///     Gets the state of the model before this migration is run.
    /// </summary>
    string Source { get; }

    /// <summary>
    ///     Gets the state of the model after this migration is run.
    /// </summary>
    string Target { get; }
}

プロジェクトを取得し、参照をチェックして、このインターフェースがどのように使用されているかを確認できます。base64のものはあなたのモデルです。繰り返しますが、コードを使用すると、それがどのように行われるかを追跡できるはずです。

于 2012-12-06T00:15:17.037 に答える