12

エンティティフレームワーク5(コードファーストアプローチ)を使用して、従来のストアドプロシージャのクラスをパラメータで設定しています。詳細は次のとおりです。 私の問題は、列の名前を異なる名前のプロパティにマップしたいということです(私はErpからの名前が気に入らない)。 私は別の名前を持つプロパティの列名を指定するには、(私はビューまたはテーブルにマップするとき、私は何をすべきかのような)Configurationクラスを使用することを試みたが、ここに私の結果は以下のとおりです。エンティティフレームワークコードファースト - SqlQueryのマッピングの設定

  • 私がいない場合(私はDbContextのOnModelCreatingメソッドでそれを追加しません)EFは動作しますが、カラムの名前と正確に一致するプロパティだけをロードします(これは私がこの場合に期待したものです)。他のプロパティはnullです。
  • 構成クラスを使用して(DbContextのOnModelCreatingメソッドのmodelBuilderに追加すると)、EFによって「データリーダーが指定された '... Item」と互換性がないという例外が発生します。 "Description 'は、同じ名前のデータリーダーに対応する列を持っていません"と、これは私にとっては非常に奇妙に聞こえます。なぜなら、プロパティDescriptionが列ItemDescriptionにマップされるからです。

設定が結果に影響するが、その仕様が列のマッピングに使用されないのはなぜですか? SqlQueryを使用してこのマッピングを指定する別の方法はありますか?ここで

詳細は以下のとおりです。

マイPOCOクラス:

public class Item 
    { 
     public String Id { get; set; } 
     public String Description { get; set; } 
    } 

設定クラス:

public class ItemConfiguration : EntityTypeConfiguration<Item> 
    { 
     public ItemConfiguration() 
     { 
      HasKey(x => new { x.Id }); 
      Property(x => x.Id).HasColumnName("Code"); 
      Property(x => x.Description).HasColumnName("ItemDescription"); 
     } 
    } 

ストアドプロシージャは、列 "コード" と「ItemDescriptionでデータを返します";私はこの方法でそれを呼び出す:

var par = new SqlParameter(); 
par.ParameterName = "@my_par"; 
par.Direction = ParameterDirection.Input; 
par.SqlDbType = SqlDbType.VarChar; 
par.Size = 20; 
par.Value = ...; 

var data = _context.Database.SqlQuery<Item>("exec spItem @my_par", par); 

、これで私は、コンテキストに設定を追加します。

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
     modelBuilder.Configurations.Add(new ItemConfiguration()); 
} 

ありがとうございました!

+0

この投稿はとてもうれしいです。私は私と苦労していました。私が必要としていたのは「エグゼクティブ」の部分でした。私はたくさんの例を見つけましたが、誰も「エグゼクティブ」を持っていませんでした。 –

答えて

11

私がここで見つける:

http://entityframework.codeplex.com/workitem/233?PendingVoteId=233

を "sqlqueryの方法を口座に任意のマッピングを取らないように設計されています..." ということ。

また、「この問題を解決し、今後の検討のためにバックログに入れるために、SqlQueryにColumn属性を付与するオプションを持たせることは有益であることに同意します。私の同じ問題、投票してください:-)

+2

さて、2013年ですが、まだ動作していないようです。 –

+1

2014 ... –

+1

2014年10月、それでも何もしません。 CodePlexで議決された問題。 –

3

一方、この方法を使用することができます。 (クラスにはうまくいきましたが)必要に応じて修正するのは難しくありません... マップされたカスタムタイプを取得するためにはコンテキストが必要ですし、同時にデータレアを実行するには別の接続が必要です。

使用法:
List students = Mapper.Map(context、(New SchoolContext())。データベース。接続、 "選択*学生から");

public static class Mapper 
{ 
    /// <summary> 
    /// Maps the result of a query into entities. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="context">The context.</param> 
    /// <param name="queryConnection">The connection to run the query. Must be different from the one on the context.</param> 
    /// <param name="sqlQuery">The SQL query.</param> 
    /// <returns>An entity list</returns> 
    /// <exception cref="System.ArgumentNullException"> 
    /// context 
    /// or 
    /// queryConnection 
    /// or 
    /// sqlQuery 
    /// </exception> 
    public static List<T> Map<T>(DbContext context, DbConnection queryConnection, string sqlQuery) where T:new() 
    { 
     if (context == null) 
      throw new ArgumentNullException("context"); 
     if (queryConnection == null) 
      throw new ArgumentNullException("queryConnection"); 
     if (sqlQuery == null) 
      throw new ArgumentNullException("sqlQuery"); 

     var connectionState = queryConnection.State; 

     if (connectionState != ConnectionState.Open) 
      queryConnection.Open(); 

     DbCommand command = queryConnection.CreateCommand(); 
     command.CommandText = sqlQuery; 
     DbDataReader reader = command.ExecuteReader(); 

     List<T> entities = new List<T>(); 

     while (reader.Read()) 
     { 
      entities.Add(InternalMap<T>(context, reader)); 
     } 

     if (connectionState != ConnectionState.Open) 
      queryConnection.Close(); 

     return entities; 

    } 

    private static T InternalMap<T>(DbContext context, DbDataReader reader) where T: new() 
    { 

     T entityObject = new T(); 

     InternalMapEntity(context, reader, entityObject); 

     return entityObject; 
    } 

    private static void InternalMapEntity(DbContext context, DbDataReader reader, object entityObject) 
    { 

     ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext; 
     var metadataWorkspace = ((EntityConnection)objectContext.Connection).GetMetadataWorkspace(); 

     IEnumerable<EntitySetMapping> entitySetMappingCollection = metadataWorkspace.GetItems<EntityContainerMapping>(DataSpace.CSSpace).Single().EntitySetMappings; 
     IEnumerable<AssociationSetMapping> associationSetMappingCollection = metadataWorkspace.GetItems<EntityContainerMapping>(DataSpace.CSSpace).Single().AssociationSetMappings; 

     var entitySetMappings = entitySetMappingCollection.First(o => o.EntityTypeMappings.Select(e => e.EntityType.Name).Contains(entityObject.GetType().Name)); 

     var entityTypeMapping = entitySetMappings.EntityTypeMappings[0]; 
     string tableName = entityTypeMapping.EntitySetMapping.EntitySet.Name; 
     Console.WriteLine(tableName); 

     MappingFragment mappingFragment = entityTypeMapping.Fragments[0]; 

     foreach (PropertyMapping propertyMapping in mappingFragment.PropertyMappings) 
     { 
      object value = Convert.ChangeType(reader[((ScalarPropertyMapping) propertyMapping).Column.Name], propertyMapping.Property.PrimitiveType.ClrEquivalentType); 
      entityObject.GetType().GetProperty(propertyMapping.Property.Name).SetValue(entityObject, value, null); 
      Console.WriteLine("{0} {1} {2}", propertyMapping.Property.Name, ((ScalarPropertyMapping)propertyMapping).Column, value); 
     } 

     foreach (var navigationProperty in entityTypeMapping.EntityType.NavigationProperties) 
     { 
      PropertyInfo propertyInfo = entityObject.GetType().GetProperty(navigationProperty.Name); 

      AssociationSetMapping associationSetMapping = associationSetMappingCollection.First(a => a.AssociationSet.ElementType.FullName == navigationProperty.RelationshipType.FullName); 

      // associationSetMapping.AssociationTypeMapping.MappingFragment.PropertyMappings contains two elements one for direct and one for inverse relationship 
      EndPropertyMapping propertyMappings = associationSetMapping.AssociationTypeMapping.MappingFragment.PropertyMappings.Cast<EndPropertyMapping>().First(p => p.AssociationEnd.Name.EndsWith("_Target")); 

      object[] key = propertyMappings.PropertyMappings.Select(c => reader[c.Column.Name]).ToArray(); 
      object value = context.Set(propertyInfo.PropertyType).Find(key); 
      propertyInfo.SetValue(entityObject, value, null); 
     } 

    } 
} 
関連する問題