【Entity Framework】テーブルの主キーの値を渡して、レコードを取得する方法(ナビゲーションの値も含む)
以下のような実装で取得可能。
次の実装は呼び出し元
SampleTable というテーブルがあり、
主キーに相当するプロパティが SampleId になります。
SampleSubTable と SampleTable はナビゲーションプロパティが定義しています。
static void Main(string[] args) { SampleTable data = null; using (var context = new Sample01Entities()) { context.Configuration.ProxyCreationEnabled = false; data = GetSampleTableData(context, 2); } Console.WriteLine(data.SampleId); Console.WriteLine(data.SampleName); Console.WriteLine(data.SampleSubTable.Count); Console.ReadLine(); } private static SampleTable GetSampleTableData( DbContext context, int key1) { return DbContextUtility.GetData<SampleTable>( context, new SampleTable() { SampleId = key1 }); }
次の実装は呼び出し先
リファクタリングの余地はあるが、
実現したいことはできていると思います。
public static class DbContextUtility { #region EntityType private static Dictionary<Type, EntityType> entityTypes = new Dictionary<Type, EntityType>(); private static EntityType GetEntityType(DbContext context, Type type) { EntityType result; if (entityTypes.TryGetValue(type, out result)) return result; var objectContext = ((IObjectContextAdapter)context).ObjectContext; var metadata = objectContext.MetadataWorkspace; result = metadata.GetItem<EntityType>(type.FullName, DataSpace.OSpace); entityTypes.Add(type, result); return result; } #endregion public static T GetData<T>( DbContext context, T entity) where T : class { var type = typeof(T); var entityType = GetEntityType(context, type); var keyProperties = entityType.KeyMembers.Select(k => type.GetProperty(k.Name)); var values = keyProperties.Select(m => m.GetValue(entity)).ToArray(); var result = (T)context.Set<T>().Find(values); GetEntity(context, result, new HashSet<object>()); return (T)result; } private static void GetEntity( DbContext context, object entity, HashSet<object> values) { if (values.Contains(entity)) return; values.Add(entity); var type = entity.GetType(); var entityType = GetEntityType(context, type); var navproperties = entityType.NavigationProperties.Select( m => entity.GetType().GetProperty(m.Name)); foreach (var nav in navproperties) { if (nav.PropertyType.IsGenericType) { context.Entry(entity).Collection(nav.Name).Load(); var enumerable = (IEnumerable)nav.GetValue(entity); foreach(var e in enumerable) GetEntity(context, e, values); } else { context.Entry(entity).Reference(nav.Name).Load(); var value = nav.GetValue(entity); GetEntity(context, value, values); } } } }
【Entity Framework】Set やら Find やら使って、ナビゲーションプロパティも含めてDBから取得する方法
調べた結果、できそうな雰囲気。
眠いので今週中位に記事を書く予定。
EntityType から、いろいろな情報が取得できるので、
面白い事ができそうです。
DB(SQL Server や Oracle)に、
依存しない形で汎用的な部分を作りこめるのはうれしいですね。
【ASP.NET MVC】モデルのバインドに関して (2)
前回投稿した記事で、
モデルのバインドに関して調べました。
saboten-sakura.hatenablog.com
以下のように複数の Name が存在した場合。
@using (Html.BeginForm("Send", "Home", null, FormMethod.Post)) { <input type="text" name="a" /> <input type="checkbox" name="a" value="true" /> <input type="hidden" name="a" value="false" /> <input type="submit" value="送信" /> }
以下のような実装をする事でフォーム上の値が変数にバインドされます。
※引数の型が配列になっています。
public class HomeController : Controller { public ActionResult Send(bool[] a) { return this.Index(); } }
bool 型なので、 true or false のみですが、
string 型 や int 型などでもキャスト可能であれば利用可能です。
【ASP.NET MVC】モデルのバインドに関して
ポストする時に同じ name があった場合、
どのような挙動となるのか確認しました。
※自分自身のメモです。時間も遅いのでわかり辛かったらすみません。。。
次のような Controller と View があるとします。
public class HomeController : Controller { public ActionResult Index() { return View("Index"); } public ActionResult Send(bool a) { return this.Index(); } }
※ submit すると HomeController クラスの Send メソッドが呼ばれます。
@using (Html.BeginForm("Send", "Home", null, FormMethod.Post)) { <input type="checkbox" name="a" value="true" /> <input type="hidden" name="a" value="false" /> <input type="submit" value="送信" /> }
checkbox を チェック した状態で引数 a には true が設定されます。
また、
checkbox を チェック しない状態で引数 a には false が設定されます。
これは、name が複数同じ値が存在した場合、
先に読み込まれた値を元に解決しているようです。
その為、以下のような実装も可能となります。
@using (Html.BeginForm("Send", "Home", null, FormMethod.Post)) { <input type="text" name="a" /> <input type="checkbox" name="a" value="true" /> <input type="hidden" name="a" value="false" /> <input type="submit" value="送信" /> }
type が text の入力値が bool型へ変換できない場合は実行時例外が発生します。
文字列そてい、 "true" および "false" と入力した場合は、
入力した値が bool 型へ変換され引数 a に設定されます。
この事から、上から下へ順に解決されている事が確認できました。
ASP.NET MVC モデルバインド時に DataAnnotation を実行しない方法
タイトルの通り、モデルバインド時に、
DataAnnotation を実行しない方法です。
DataAnnotationsModelValidatorProvider を、
ModelValidatorProviders.Providers から取得し削除します。
using System.Linq; using System.Web.Mvc; public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { ModelValidatorProviders.Providers.Remove( ModelValidatorProviders.Providers.Single( p => p is DataAnnotationsModelValidatorProvider)); } }
たまに更新
公私共々、忙しく更新が疎かになっていました^^;
また、ボチボチと更新してゆきたいところです。
と、それとは別に、資格をとるべく勉強中。。。
C#ジャンプスタートのプログラミング