これについてSOとGoogleの両方を検索しましたが、関連する/受け入れられる回答が見つかりませんでした。
背景:
* MVC 4.5 を使用
* EF5 の上で使用しているジェネリックがいくつかあり、ジェネリックRepo<T>
によってアクセスされますService<T>
* ドメイン モデルとビュー モデルがあり、Automapper を使用してそれらの間をマッピングしています。このマッピングはService
レイヤー
* その上に、可能Controllers
な限り一般的なものがあります。
それで、質問に。オプションのリストをユーザーに提示する必要があり、ユーザーが 1 つ以上を選択する必要があるシナリオがいくつかあります。オプションはユーザー固有であるため、私のドメインUser
にList<Location>
は、保存された場所である があり、追加/変更するときは、Item
、少なくとも 1 つを選択する必要がありますLocation
。
コントローラーを汎用的でスリムに保ちたいので、コントローラーでそれをフェッチする誘惑に抵抗していList<Location>
ますが、同時に、ItemView
モデルに 1 つと 1 つAvailableLocations
という2 つのプロパティを持ちたくありませんSelectedLocations
。このモデルが使用されているためです。追加/変更だけでなく、検索結果などにも使用できます。
オプション:
* を追加/変更するための別のモデルを導入する必要がありItem
ますItemInput
。
* カスタム マッピングを使用して Automapper を取得し、利用可能な場所のリストを取得する必要がありますか?
* これらの利用可能な場所をどのレイヤーで取得する必要がありますか?
これに対するきちんとした一般的なアプローチに関する人々の提案は何ですか?
どうもありがとう!
2 に答える
私はこのようなことをします:
public IEnumerable<Location> GetLocations() {
return db.GetAll();
}
次に、コントローラーの内部(MVCスキャフォールディングからこれに従いました):
ViewBag.Locations = new SelectList(service.GetLocations, "name", "id");
(または独自のチェックボックス リスト) を作成し、HTML/View ページにリスト コントロールを配置します。
これが最善の方法であると私が考える理由は、ロジックがすべてサービス内に存在するためです。DTO/データ モデルに配置すると、次の問題に直面する可能性があります。
場所を引き戻すために追加のロジックが必要な場合はどうなりますか? つまり、ロケーションのサブロケーションです。
新しい変更を反映するようにサービスを変更 (またはオーバーライド) すると、このロジックはサービスの内部に入ります。
public IEnumerable<Location> GetLocations(string parent) {
return db.GetAll().Where(loc => loc.parentname = parent);
}
ps私は一般的なサービスを使用したことがありません。私がサービスを持っている理由は、サービスが提供するデータアクセスの一部に、一般的なDALと一緒に座ることを意図していないロジックが含まれているためです。
インターフェイスまたは抽象サービスを作成して、サービス間の一般的な操作を少し楽にすることもできますが、具体的なものを定義すると、UserManagementSerive
ユーザー、場所、およびアイテムをそれぞれ持つオブジェクトを管理したいと言っていることになります。独自の特定の機能?
この問いに対する唯一の答えはないと思います。
シンプルだが一般的ではないアプローチをお勧めします。ViewModelsと呼ばれるもの、つまり特定のビューに関連するモデル クラスを記述します。次に、コントローラーから使用可能な場所を取得し、取得した場所を使用してコントローラーに ViewModel のインスタンスを設定します。
基本的に、次のようないくつかのサービスを公開します。
IEnumerable<Location> GetAvailableLocationsForUser(string userName);
IEnumerable<T>
ではなくを使用したことに注意してくださいIQueryable<T>
。実装が実際にデータベースを要求するため、そうするのがコントローラーの役割である場合、バグが発生しやすい (少なくとも IMO) ためです (の遅延実行を思い出してくださいIQueryable<T>
)。そして、マッピングされたモデルではなく、ドメイン インスタンス、つまりエンティティを返します。個人的には、サービス層のドメイン クラス以外は扱いません。エンティティではなく、たとえばエンティティの構成であるドメイン クラスが存在する可能性があります。これは、効率的なリクエストを作成し、コントローラーでの遅延読み込みと遅延実行の使用を回避するのに役立ちます。これは、コントローラーがエンティティだけでなく、オブジェクト グラフ全体を必要とする場合に役立ちます。
次に、Web アプリケーション アセンブリで、次のようにモデルとビューモデルを記述します。
public LocationModel
{
...
}
public CreateItemViewModel : ItemModel
{
public List<LocationModel> AssociatedLocations { get; set; }
public List<LocationModel> AvailableLocations { get; set; }
...
}
- 基本的にモデル(
ItemModel
とLocationModel
) があり、これらは Web アプリケーションに関連するオブジェクトです。これは、計算された読み取り専用プロパティやプロパティの属性 (DisplayAttribute
...など) など、これらのモデルに Web 関連の要素が含まれている可能性があることを意味します。これは一般化できるものではないと思うので、実際にはこれらのモデルを複数回記述します。たとえば、あるビューではナビゲーション プロパティの使用が必要であるが、別のビューでは必要がない場合などです。したがって、モデルを使用するビューに応じて、マッピング プロセスの深さが変わります。また、AutoMapper はまったく使用しません (手書きのマッパーのみ)。 - 単一のビューに関連するオブジェクトであるViewModel ( )もあります (たとえば、この例ではアイテムを作成できるビュー)。Model と ViewModel の違いは、ViewModel が 1 つのビューに関連付けられている (そして、このビューに従って名前が付けられている) ことです。一方、モデルは複数のビューに関連しています (その名前空間は、どのビューかを知るのに役立ちます。たとえば、ディレクトリ内のすべてのビューに関連するモデルの場合)。ViewModel は、ドメイン クラスに基づいてコントローラー (または別のマッパー) でゼロから構築されます。
CreateItemViewModel
xxx.Item.Models
xxx.Item
上記の例では、 と を返すドメイン クラスを構築できますが、サービスレイヤーが Web パーツを認識する必要があります (つまり、サービス インターフェイスとドメイン クラスは、特定のビューに必要なプロパティを認識します)。 )。これらのプロパティが実際にアプリケーションの単一のビューに関連しているかどうかはわかりませんが、そうでない場合は、返されるエンティティの構成としてドメイン クラスを構築することもできます。AssociatedLocations
AvailableLocations
AssociatedLocations
AvailableLocations
public ItemExtended : Item
{
public List<Location> AssociatedLocations { get; set; }
public List<Location> AvailableLocations { get; set; }
}
ItemExtended GetItemExtendedById(long idItem);