5

컨트롤러에서 데이터베이스 개체를 다시 만드는 것이 가장 좋은 방법인지 생각해 보는 중 작업 중입니다.ASPNET MVC에서 모델 바인딩 데이터베이스 엔티티

ModelBinders를 사용하고 싶습니다. 따라서 식별자 매개 변수를 기반으로 데이터베이스에서 객체를 가져 오기 위해 코드를 반복하지 않고 매개 변수를 통해 객체에 액세스 할 수 있습니다. 그래서 ModelBinder가 데이터 액세스 레이어를 호출하여 원래의 객체를 얻거나 데이터베이스에 존재하지 않으면 새 객체를 생성 한 다음, 모든 속성을 데이터베이스 객체에 바인드하여 업데이트합니다. 그러나 나는 ModelBinders가 데이터베이스 쿼리 (첫 번째 코멘트는 article)를 만들어서는 안된다는 것을 읽었습니다.

ModelBinder가 데이터베이스 쿼리를 수행하지 않아야하므로 (DefaultModelBinder를 사용하는 경우) 다른 db 개체 인 속성을 가진 데이터베이스 개체는 어떻게됩니까? 이것들은 결코 할당되지 않을 것입니다.

사용자가 편집 한 객체를 저장하면 (보기에서 1 또는 2 개의 속성을 편집 할 수 있음) ModelBinded 객체에 데이터가 누락되어 그대로 저장하면 데이터베이스의 데이터가 유효하지 않은 값으로 덮어 쓰입니다 , 또는 NOT NULL 제약 조건이 실패합니다.

그렇다면 뷰에서 다시 게시 된 양식 데이터로 바인딩 된 데이터베이스에서 컨트롤러 작업의 개체를 가져 오는 가장 좋은 방법은 무엇입니까?

메신저는 NHibernate를 사용합니다.

+0

나는 또한 당신과 똑같은 상황 (에있어 NH를 사용함). 코드 복제를 피하기 위해 모델 바인더를 구현했습니다. 바인더에서 DB에 액세스하는 방법에 대한 결론은 무엇입니까? –

+0

결국 바인더에서 데이터베이스 액세스에 반대했습니다. 내보기 모델은 이제 내 도메인 모델과 구분됩니다. 도메인 모델에 직접 바인딩하는 데 문제가 있습니다 (nhibernate는 잘못된 데이터로 요청이 끝날 때 바인드 된 객체를 비 웁니다. 새 세션을 만들지 않고 이후에 객체를 다시 가져 오지 않으면 결국 요청 전체에서 유효하지 않은 바인드 된 객체). –

+0

알려 주셔서 감사합니다. –

답변

4

데이터베이스에서 모델 개체를 가져온 다음 개체에 UpdateModel (또는 TryUpdateModel)을 사용하여 양식 매개 변수에서 값을 업데이트하십시오.

public ActionResult Update(int id) 
{ 
    DataContext dc = new DataContext(); 
    MyModel model = dc.MyModels.Where(m => m.ID == id).SingleOrDefault(); 

    string[] whitelist = new string[] { "Name", "Property1", "Property2" }; 

    if (!TryUpdateModel(model, whitelist)) { 
     ... model error handling... 
     return View("Edit"); 
    } 

    ViewData.Model = model; 

    return View("Show"); 
} 
+1

내 모델에서 일부 값에 할당 된 속성이 FormCollection에 없으면 TryUpdateModel을 수행 할 때 속성을 포함/제외해도 null로 설정된다는 것을 발견했습니다. 그래서 기본적으로 TryUpdateModel은 데이터 손실을 일으키는 것이므로 좋지 않습니다. –

+0

지정한 경우 화이트리스트에있는 속성 만 대체해야합니다. 나는 일부 값을 다른 것들만 업데이트 할 수있는 일부 편집 뷰를 가지고 있기 때문에 이것이 작동한다는 것을 알고있다. 확인을 위해 http://www.codeplex.com/aspnet에서 실제 코드를 볼 수 있습니다. – tvanfosson

2

불행히도 모델 바인더의 구성을 제어 할 수 없으므로 저장소 구현을 삽입 할 수 없습니다. 당신이 기본 클래스를 사용할 수 있는지

public class ProductBinder : DefaultModelBinder 
{ 
    protected override object CreateModel(ControllerContext controllerContext, 
     ModelBindingContext bindingContext, Type modelType) 
    { 
     if(modelType != typeof(Product)) 
      return null; 

     var form = controllerContext.HttpContext.Request.Form; 
     int id = Int32.Parse(form["Id"]); 
     if(id == 0) 
      return base.CreateModel(controllerContext, bindingContext, modelType); 

     IProductRepository repository = ServiceLocator.Resolve<IProductRepository>(); 

     return repository.Fetch(id);          
    }  
} 

당신은 심지어 모든 법인이 작동하지 않을 수도 있습니다 :

당신 항목을 가져 저장소 &에 끌어 서비스 로케이터에 직접 밖으로 도달 할 수있다 또는 클래스의 ID를 제공하는 인터페이스.

ModelBinders.Binders.Add(typeof(Product), new ProductBinder()); 

을 그리고 당신은이 작업을 수행 할 수 있습니다 :

당신은 Global.asax에이를 설정해야합니다 당신은 실제로 데이터베이스에 접속하지 않아도

public ActionResult Save([Bind] Product product) 
{ 
    .... 

    _repository.Save(product); 
} 
+0

이것은 내가 원래하고 있었던 일입니다. 여기에서 그것을하는 것이 의미가 있습니다. 그러나 ModelBinder가 데이터베이스를 쿼리해서는 안되는 여러 위치를 읽으면 두 번 생각하게됩니다. –

+1

약간 냄새 나는데, 기분이 나아진다면 Castle 프로젝트의 [ARDataBind]가 정확히 이것을합니다. –

+1

데이터베이스를 때리는 것은 좋은 생각이 아닙니다. 바인더는 BEFORE ActionFilters를 실행하므로 바인더에서 데이터베이스에 액세스 할 때 염두에 두십시오. –

-1

. 개체의 ID를 설정하기 만하면 관계를 설정하는 데 충분하지만 계단식을 지켜보십시오. 값을 지우는 것처럼 관련 객체를 업데이트하지 않는지 확인하십시오.

+2

정말 위험한 조언입니다. 업데이트하기 전에 항상 선택해야합니다. 데이터베이스의 모든 레코드를 업데이트하지 않을 수도있는 영역이 많기 때문에 빈 값으로 덮어 쓰게됩니다. –

+0

내가 질문을 제대로 읽지 않았기 때문에 매우 사실, 어리석은 대답이었다! –

0

먼저 ModelBinders에서 데이터베이스에 액세스하지 않는 것이 좋습니다. 분리 모델의 관점에서 ModelBinders는 클라이언트 요청을 해석하는 책임 만 있어야하며 분명히 데이터베이스는 아닙니다.
당신은 u는 정말 그런 식으로 작업을 수행하려는 경우를 Global.asax에서 다음

, 그러나 자기 (DRY), 사용 저장소/서비스 를 반복합니다 해달라고합니다.CS 등록 MVC

ModelBinderProviders.BinderProviders.Add(new EntityModelBinderProvider 
{ 
    ConnectionString = "my connection string" 
)); 

Cunstruct에 사용자 정의 MyModelBinderProvider

public class EntityBinderProvider: IModelBinderProvider 
{ 
    public string ConnectionString { get; set; } 

    public IModelBinder GetBinder(Type modelType) 
    { 
     if (Is known entity) 
      return new EntityBinder(ConnectionString); 
     else 
      return null; 
    } 
} 

벤 Scheirman에서 자세한 지침에 따라 데이터베이스 설정을 포함하는 사용자 정의 ModelBinderProvider