We all know we're not supposed to link our MVC2 models directly to entities in our Entity Framework. Doing so would let form hackers modify all sorts of data that you'd probably prefer to keep unmodified. Unfortunately, I haven't found good methods of copying model values to entities and vice-versa. I didn't feel like writing a million lines of code to copy each value explicitly, so I rolled a little tool that will convert a model to an entity and vice-versa using the power of reflection in C#.
Basically, you can create an entity via the Entity Framework (these are usually generated automatically by the Visual Studio IDE, though you can add functionality by writing partial classes) and a corresponding model via MVC2 and have complete control over which properties are able to be set on each form by specifying an array of property names. It's pretty simple, as you can see by the few number of lines I used to implement it.
It's simplicity is a warning, though, because this tool probably won't work in a variety of scenarios. For one, it will only copy the public
properties of your model/entity; fields are ignored. For two, only shallow copies will be made of any reference types that exist in your objects. For three, nullable entity values aren't handled very well, as I can't seem to get at the attributes which define nullable values in the Entity Framework via reflection.
Anyway, enjoy. The source is below, and a short example follows:
public class EntityModeler<T, t>
where T : EntityModel<t>
where t : System.Data.Objects.DataClasses.EntityObject
{
public static T ModelEntity(t entity)
{
var model = System.Activator.CreateInstance<T>();
model.UpdateModel(entity);
return model;
}
public static IEnumerable<T> ModelEntities(IEnumerable<t> entities)
{
var list = new List<T>();
foreach (var entity in entities)
list.Add(EntityModeler<T, t>.ModelEntity(entity));
return list;
}
}
public abstract class EntityModel<T>
where T : System.Data.Objects.DataClasses.EntityObject
{
public void UpdateModel(T entity)
{
var myProperties = this.GetType().GetProperties(
BindingFlags.Instance |
BindingFlags.Public
);
var entityType = entity.GetType();
foreach (var myProp in myProperties)
{
var entityProp = entityType.GetProperty(myProp.Name);
if (entityProp != null && entityProp.CanRead && myProp.CanWrite)
{
var val = entityProp.GetValue(entity, null);
if (val == null)
if (myProp.PropertyType != typeof(Nullable))
continue;
myProp.SetValue(this, entityProp.GetValue(entity, null), null);
}
}
}
public void UpdateEntity(ref T entity, params string[] includeProperties)
{
var propertyInfo = this.GetType().GetProperties(
BindingFlags.Instance |
BindingFlags.Public
);
var entityType = entity.GetType();
foreach (var myProp in propertyInfo)
{
if (includeProperties.Contains(myProp.Name))
{
var entityProp = entityType.GetProperty(myProp.Name);
if (entityProp != null && entityProp.CanWrite && myProp.CanRead)
{
var val = myProp.GetValue(this, null);
if (val == null)
if (entityProp.PropertyType != typeof(Nullable))
continue;
entityProp.SetValue(entity, val, null);
}
}
}
}
public T CreateEntity(params string[] includeProperties)
{
var entity = System.Activator.CreateInstance<T>();
this.UpdateEntity(ref entity, includeProperties);
return entity as T;
}
}
public class PersonModel : EntityModel<PersonEntity>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string SocialSecurity { get; set; }
}
public class PersonController : Controller
{
public ActionResult Index()
{
var models =
EntityModeler<PersonModel, PersonEntity>.ModelEntities(
YourEntities.PersonSet
);
return View("Index", models);
}
[HttpPost]
public ActionResult Edit(PersonModel model)
{
if (!ModelState.IsValid)
return View(model);
var entity = model.CreateEntity(
"FirstName",
"LastName",
"Address"
);
return RedirectToAction("Details", new { id = entity.Id });
}
}