1

アプリケーションのDALにEF4.1を使用しており、POCPエンティティでDbContextテンプレートジェネレーターを使用しています。モデルはデータベースから作成されるため、すべてのフィールド/ PK /FK/リレーションはデータベースですでに定義されています。エンティティのテーブルのフィールドをコードで見つける必要があります。一部のテーブルには単一のフィールドPKがあり、他のテーブルには複合PKがある場合があります。必要なのは、エンティティのリストを返すメソッドを用意することです。すべてのフィールド名が主キーを構成します。DbContextからでも、エンティティからでも構いません。以下のように、テンプレートをカスタマイズしてPOCOエンティティでメソッドを生成することもできます。

public List<string> PrimaryKey()
    {
        List<string> pk = new List<string>();
        pk.AddRange(
            new string[] {"Field1", "Field2"});
        return pk;
    }

しかし、PKを構成するフィールド名を見つける方法がわかりません。
助言がありますか?

ありがとうございました

4

4 に答える 4

2

私はいくつかの調査を行い、これを返すプロパティを生成するようにテンプレートを変更しました。

まず、テンプレートをカスタマイズして、フィールド名に強い型の名前を生成しました(コードで文字列を使用すると、リファクタリング時に問題が発生する可能性があります)。次に、それを使用して、主キーフィールドをリストとして返すプロパティを生成します

テンプレートへの変更は次のとおりです(私はADO.NET DbContext Template Generatorを使用しましたが、他のテンプレートの場合は非常に似ているはずです)。

<#=Accessibility.ForType(entity)#>
<#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#> 
<#=code.StringBefore(" : ", code.Escape(entity.BaseType))#>
{   
<#
WriteStrongTypedPropertyNames(code, entity);    // <-- Insert this
WritePrimaryKeyProperty(code, entity);          // <-- and this

// .....

そして、テンプレートファイルの最後に以下を追加します。

<#+
void WriteStrongTypedPropertyNames(CodeGenerationTools code, EntityType entity)
{

#>  /// <summary>
    /// Strong typed property names
    /// </summary>
    public class PropertyNames
    {
<#+
    foreach (var property in entity.Properties)
    {
#>
        public const string <#=code.Escape(property)#> = "<#=property#>";
<#+
    }
#>
    }

<#+

}

void WritePrimaryKeyProperty(CodeGenerationTools code, EntityType entity)
{

#>    /// <summary>
    /// Returns primary key as List
    /// </summary>
    public List<string> PrimaryKey
    {
        get
        {
            List<string> pk = new List<string>();
            pk.AddRange(
                new string[] {                  
<#+
            foreach (var member in entity.KeyMembers)
            {
                string delim = "";
#>
                    <#=delim#> PropertyNames.<#=code.Escape(member.Name)#>
<#+
                delim=",";
            }
#>              });
            return pk;
        }
    }

<#+

}
#>

エンティティに次のようなコードを生成します。

    /// <summary>
    /// Strong typed property names
    /// </summary>
    public class PropertyNames
    {
        public const string AppID = "AppID";
        public const string AppName = "AppName";
        public const string AppCode = "AppCode";
    }

    /// <summary>
    /// Returns primary key as List
    /// </summary>
    public List<string> PrimaryKey
    {
        get
        {
            List<string> pk = new List<string>();
            pk.AddRange(
                new string[] {                  
                     PropertyNames.AppID
                });
            return pk;
        }
    } 

これが誰かに役立つことを願っています

于 2011-10-12T23:45:45.510 に答える
1

DbContextから、タイプが不明な場合に実行時に主キーの名前と値を取得して、ほぼ同じことを行うのに苦労しました。私は削除の監査スキームを実装しようとしていたところですが、私が見つけたすべてのソリューションには、私が本当に理解していない余分なコードが含まれています。EntityKeyはDbContextからは利用できません。これも、混乱を招き、煩わしいものです。最後の5行は、5時間と1年の禿げを節約する可能性があります。私はInsertに対してこれを試みていません。そのため、そうする場合は、それらの値が0またはnullである可能性があるため、これらの値を注意深く調べる必要があります。

foreach(var entry in ChangeTracker.Entries<IAuditable>()) { 
...  
case EntityState.Deleted:
...  
var oc = ((IObjectContextAdapter.this).ObjectContext; //.this is a DbContext EntityKey
ek = oc.ObjectStateManager.GetObjectStateEntry(entry.Entity).EntityKey;
var tablename= ek.EntitySetName; 
var primaryKeyField = ek.EntityKeyValues[0].Key;     //assumes only 1 primary key var
primaryKeyValue = ek.EntityKeyValues[0].Value;
于 2012-01-25T19:50:13.447 に答える
0

@bzamfirに似たようなことをした後、この投稿に出くわしました。@Billが私も経験したと言っている頭痛の種のいくつかを軽減することを期待して、私がしたことを投稿すると思いました!
DBContextを使用して、テンプレートも変更しました。
1)すでにファイルにあるインポートのリストに追加します。2) KeyAttributeImports System.ComponentModel.DataAnnotationsを主キープロパティに追加するコードを各ループの主キープロパティに追加します。次のようになります。

For Each edmProperty As EdmProperty In primitiveProperties
    If ef.IsKey(edmProperty) Then  
       #><#= code.StringBefore("<KeyAttribute()>",Environment.NewLine & CodeRegion.GetIndent(region.CurrentIndentLevel + 2))#><#
End If
    WriteProperty(code, edmProperty)
Next

この拡張メソッドをコードのどこかに追加して、KeyAttributeに基づいて主キーを見つけることができます。

<Extension()>
Public Function FindPrimaryKeyProperty(Of T As Class)(context As DbContext, TEntity As T) As PropertyInfo
    Return TEntity.GetType().GetProperties().Single(Function(p) p.GetCustomAttributes(GetType(KeyAttribute), True).Count > 0)
End Function

KeyAttributeでフラグが付けられたプロパティが複数ある場合、この関数が失敗するという点を認識していますが、私の状況ではそうではありませんでした。

于 2012-07-03T20:17:46.813 に答える
0

あるいは、うまく機能しているように見え、テンプレートの編集(+1)を必要としないこのソリューションに出くわしました。
http://blog.oneunicorn.com/2012/05/03/the-key-to-addorupdate/

public static IEnumerable<string> KeysFor(this DbContext context, Type entityType)
{
    Contract.Requires(context != null);
    Contract.Requires(entityType != null);

    entityType = ObjectContext.GetObjectType(entityType);

    var metadataWorkspace =
    ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;
    var objectItemCollection = 
    (ObjectItemCollection)metadataWorkspace.GetItemCollection(DataSpace.OSpace);

    var ospaceType = metadataWorkspace
        .GetItems<EntityType>(DataSpace.OSpace)
        .SingleOrDefault(t => objectItemCollection.GetClrType(t) == entityType);

    if (ospaceType == null)
    {
        throw new ArgumentException(
            string.Format(
                "The type '{0}' is not mapped as an entity type.",
                entityType.Name),
            "entityType");
    }

    return ospaceType.KeyMembers.Select(k => k.Name);
}
于 2012-07-05T13:51:43.690 に答える