Kinimod
Kinimod

Reputation: 166

Asp.net MVC Razor: Passing Complex model data

I have two classes:

public class Sportevent
{
    public int ID { get; set; }
    public DateTime EventsStart { get; set; }
    public DateTime EventsEnd { get; set; }

    public virtual Address Address { get; set; }
}

public class Address
{
    public int ID { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string Address3 { get; set; }
    public int PostalCode { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
    public string Nation { get; set; }
}

So a Sportevent references an Address Entity. The view for creating a Sportevent contains also the forms for the address. The controller receives the infos, but what happens with the Address? How can I pass them or is it already contained

public ActionResult Create([Bind(Include = "EventsStart,EventsEnd, Address")] Sportevent sportevent){
...
}

I think the above syntax of the binding is incorrect, because Address is a complex datatype instead a primitve one, or not? So what's the best practice for passing such complex datamodels?

Upvotes: 0

Views: 313

Answers (2)

Georg Patscheider
Georg Patscheider

Reputation: 9463

The Bind attribute might be necessary as a security precaution if you are binding directly to the EF persistable classes.

To get rid of it, introduce ViewModels that only contain the fields that the user is allowed to change. An additional benefit is that you can put View-centric properties and methods in the ViewModel and they will not pollute your entity model (separation of concerns).

public class CreateSporteventViewModel
{
    // ID is not needed in create usecase because it will be assigned by EF
    public DateTime EventsStart { get; set; }
    public DateTime EventsEnd { get; set; }

    public CreateAddressViewModel Address { get; set; }
}

public class CreateAddressViewModel 
{
    // ID is not needed in create usecase because it will be assigned by EF

    // Example of View-centric attribute
    [Display(ResourceType = typeof(Resources), Name = "Street")]
    public string Address1 { get; set; }

    // ... other properties relevant for create view
}

In the View, render the <input> as mentioned by user7405157:

@model CreateSporteventViewModel
@Html.EditorFor(m => m.EventsStart)
@Html.EditorFor(m => m.Address.Address1)

In the controller, create the entity model and populate it. There are libraries to facilitate this mapping step, e.g. AutoMapper.

public ActionResult Create(CreateSporteventViewModel viewModel){
    var persistableEvent = new Sportevent {
        EventsStart = viewModel.EventsStart,
        // ...
    };

    var persistableAddress = new Address {
       Address1 = viewModel.Address.Address1,
       // ...
    };
    persistableEvent.Address = persistableAddress;

    dbContext.Sportevents.Add(persistableEvent);
    dbContext.SaveChanges();
}

Upvotes: 1

user7405157
user7405157

Reputation: 21

You don't need that Bind attribute at all.

Just in your view for inputs that should bind the data for Address in input's name attribute put Address.ID, Address.Address1, Address.PostalCode and so on. Default binding will do the work for you.

Upvotes: 2

Related Questions