5

モデルのコントローラーを追加すると、生成されるアクションは次のようになります。

public ActionResult Edit(int id = 0)
{
    Entity entity = db.Entities.Find(id);
    if (entity == null)
    {
        return HttpNotFound();
    }
    return View(entity);
}

私の場合、いくつかの方法でDB IDにマップできる文字列IDを取得し、正しいエンティティを取得するためのコードを数行生成します。エンティティを取得するためにIDを取得するすべてのアクションにそのコードをコピーして貼り付けると、非常にエレガントではないと感じます。

取得コードをコントローラーのプライベート関数に配置すると、重複するコードの量が減りますが、それでも次のことが残ります。

var entity = GetEntityById(id);
if (entity == null)
    return HttpNotFound();

属性でルックアップを実行し、エンティティをアクションに渡す方法はありますか?Pythonから来ているので、これはデコレータで簡単に実現できます。IOperationBehaviorまだ簡単ではないものを実装することで、WCFサービスに対して同様のことを行うことができました。IDでエンティティを取得することは頻繁に行う必要があることなので、コードをコピーして貼り付ける以外の方法があると思います。

理想的には、次のようになります。

[EntityLookup(id => db.Entities.Find(id))]
public ActionResult Edit(Entity entity)
{
    return View(entity);
}

ここEntityLookupで、は任意の関数マッピングstring idを取得し、取得したエンティティをパラメータとしてアクションをEntity返すか呼び出します。HttpNotFound

4

2 に答える 2

3

カスタムActionFilterを書くことができます:

public class EntityLookupAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // retrieve the id parameter from the RouteData
        var id = filterContext.HttpContext.Request.RequestContext.RouteData.Values["id"] as string;
        if (id == null)
        {
            // There was no id present in the request, no need to execute the action
            filterContext.Result = new HttpNotFoundResult();
        }

        // we've got an id, let's query the database:
        var entity = db.Entities.Find(id);
        if (entity == null)
        {
            // The entity with the specified id was not found in the database
            filterContext.Result = new HttpNotFoundResult();
        }

        // We found the entity => we could associate it to the action parameter

        // let's first get the name of the action parameter whose type matches
        // the entity type we've just found. There should be one and exactly
        // one action argument that matches this query, otherwise you have a 
        // problem with your action signature and we'd better fail quickly here
        string paramName = filterContext
            .ActionDescriptor
            .GetParameters()
            .Single(x => x.ParameterType == entity.GetType())
            .ParameterName;

        // and now let's set its value to the entity
        filterContext.ActionParameters[paramName] = entity;
    }
}

その後:

[EntityLookup]
public ActionResult Edit(Entity entity)
{
    // if we got that far the entity was found
    return View(entity);
}
于 2013-02-25T15:49:50.400 に答える
0

同様のコードを繰り返す場合は、拡張メソッドを使用できます。

public static class ControllerExtensions
{
    public static ActionResult StandardEdit<TEntity>(
        this Controller controller, 
        DbContext db, 
        long id)
        where TEntity : class
    {
        TEntity entity = db.Set<TEntity>().Find(id);
        if (entity == null)
        {
            return controller.HttpNotFound();
        }
        return controller.View(entity);
    }
}

public ActionResult Edit(long id = 0)
{
    return this.StandardEdit<Client>(db, id);
}

まったく同じコードを何度も繰り返している場合は、継承によって解決する必要があります。

から継承する共通のコントローラーを作成しますController

public class StandardController : Controller
{
    public ActionResult Edit<TEntity>(long id = 0)
        where TEntity : class
    {
        TEntity entity = db.Set<TEntity>().Find(id);
        if (entity == null)
        {
            return HttpNotFound();
        }
        return View(entity);
    }
}

モデルコントローラーを変更して、この新しいコントローラーから継承します。

public class ClientController : StandardController
{
    public ActionResult Edit(long id = 0)
    {
        return base.Edit<Client>(id);
    }
}
于 2013-02-25T15:58:47.047 に答える