2

簡単な質問の長い説明を前もってお詫びしますが、私がやろうとしていることを人々が正しく理解できるようにしたい.

バックグラウンド

SqlMetal によって生成されたファイルを読み取り、単純な挿入、更新、削除、選択のメソッドを含むクラスを作成して、Web サービスに公開できるツールを作成しています。ここでの主な利点は、テーブルが変更された場合、ツールを再実行するだけでデータベース関連のコードが自動的に更新され、それを使用するすべての場所でコンパイル エラーが生成されるため、手動で変更する必要がある場所を簡単に追跡できることです。作られる。たとえば、次のフィールドを持つ Customer テーブルがあるとします。

  • CustomerId (PK、ID)
  • ファーストネーム
  • 苗字

次のように、Insert メソッドと Delete メソッドを生成できるようにしたいと考えています。

// I only want non-database-generated fields to be parameters here.
public static Customer InsertCustomer(String firstName, String lastName)
{
...
}

// I only want the primary key fields to be parameters here.
public static int DeleteCustomer(int customerId)
{
...
}

SqlMetal を使用して Customer クラスを生成しています。次に、上記の方法で別のクラスを作成するために、その .cs ファイルを新しいツールに読み込みます。次に、この新しいクラスを Web サービスに公開して、基礎となるデータベースを公開することなく、この機能へのアクセスを許可できます。NRefactory を使用して SqlMetal で生成されたファイルを読み込んでいますが、これまでのところうまくいっていますが、Customer クラスのプロパティ属性を読み込もうとして問題が発生しました。

SqlMetal は、ColumnAttribute を使用してそのクラスを生成し、データベース列から派生した各プロパティを識別します。ColumnAttribute には、データベース列のプロパティを記述するためのいくつかの引数があります。上記の例では、次のようなものが生成されます。

...
[Column(Name="customerId", Storage="_CustomerId, DbType="INT NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
public int CustomerId
{
...
}


[Column(Name="firstName", Storage="_FirstName", DbType="NVarChar(100) NOT NULL", CanBeNull=false)]
public String FirstName
{
...
}


[Column(Name="lastName", Storage="_LastName", DbType="NVarChar(100) NOT NULL", CanBeNull=false)]
public String LastName
{
...
}
...

問題

ご覧のとおり、SqlMetal は、どの列がデータベースで生成され、どの列が主キーの一部であるかを識別するために必要な属性を提供します。したがって、このファイルを NRefactory に読み込んで型を解決すると、この情報をすべて取得できると期待できます。ただし、ColumnAttribute に到達することはできますが、そのすべての引数が解決されていないため、NamedArguments または PositionalArguments プロパティを介してアクセスできないことがわかりました。

これが私のコードです:

SyntaxTree syntaxTree = ...;
foreach(AstNode tableNode in syntaxTree.Children)
{
    ResolveResult result = resolver.Resolve(tableNode);
    var properties = result.Type.GetProperties();
    foreach (IProperty p in properties)
    {
        var attributes = p.Attributes;
        bool isPrimaryKeyField = false;
        bool isDbGenerated = false;
        bool isColumn = false;
        foreach (IAttribute attr in attributes)
        {
            if (attr.AttributeType.Name == "Column")
            {
                isColumn = true;
                foreach (var arg in attr.NamedArguments) // NamedArguments contains no items.
                {
                    if (arg.Key.Name == "IsPrimaryKey")
                    {
                        isPrimaryKeyField = (bool)arg.Value.ConstantValue == true;
                    }

                    if (arg.Key.Name == "IsDbGenerated")
                    {
                        isDbGenerated = (bool)arg.Value.ConstantValue == true;
                    }
                }
            }
        }

        if (isColumn)
        {
            ... // Create a parameter as appropriate.
        }
    }
}

コレクションには要素が含まれていないため、IAttribute.NamedArguments をループしようとするまで、これはすべて機能します。ただし、デバッガーを使用して「attr」の値を調べると、「unresolved」というプライベート変数があり、必要なすべての引数のリストが含まれていることがわかりますが、これにアクセスする方法が見つかりません。コードを通して。

この「未解決」変数の内容を取得するにはどうすればよいですか? リゾルバーでさらに何かをする必要がありますか? NRefactory を使用するのはこれが初めてなので、まだすべてのニュアンスに精通しているわけではありません。Google でこのレベルの深さの例を見つけるのに苦労しており、私が見た NRefactory のドキュメントはそれをカバーしていないようです。どんな助けでも大歓迎です。

4

1 に答える 1

2

私はそれを考え出した。SyntaxTree を解決する前に、System.Data.Linq のアセンブリを IProjectContent に読み込む必要がありました。

...
CecilLoader loader = new CecilLoader();
Assembly[] assembliesToLoad = {
    ...
    typeof(System.Data.Linq.Mapping.ColumnAttribute).Assembly
    ...};

IUnresolvedAssembly[] projectAssemblies = new IUnresolvedAssembly[assembliesToLoad.Length];
for(int i = 0; i < assembliesToLoad.Length; i++)
{
    projectAssemblies[i] = loader.LoadAssemblyFile(assembliesToLoad[i].Location);
}

IProjectContent project = new CSharpProjectContent();
project = project.AddAssemblyReferences(projectAssemblies);
...
于 2013-07-25T15:50:22.570 に答える