1

What if I have an object with a 100 properties that changed?

This would be horrible to code and prone to missing some properties.

Is there a different way of updating a record than to do it manually?

ApplicationUser CurrentUser = db.Users.FirstOrDefault(x => x.Id == model.Id);

CurrentUser.FirstName = model.FirstName;
CurrentUser.LastName = model.LastName;
CurrentUser.IsRSM = model.IsRSM;
CurrentUser.PhoneNumber = model.PhoneNumber;
CurrentUser.Email = model.Email;
CurrentUser.UserName = model.Email;
CurrentUser.Region = model.Region;
CurrentUser.Active = model.Active;

db.Entry(CurrentUser).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
3
  • 2
    You could iterate over the properties using reflection, or use AutoMapper to do it for you. Commented Jul 13, 2017 at 10:49
  • Look into AutoMapper, probably the best thing for this. Commented Jul 13, 2017 at 10:51
  • What if I have an object with a 100 properties that changed? This would be horrible to code blame developers who created those properties in one class ;) Commented Jul 13, 2017 at 11:06

3 Answers 3

2

As per comment, here are two ways you can do this programatically:

Reflection

var CurrentUser = db.Users.FirstOrDefault(x => x.Id == model.Id);

PropertyInfo[] sourceProps = model.GetType()
    .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty);

PropertyInfo[] targetProps = CurrentUser.GetType()
    .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty);

foreach (var prop in sourceProps)
{
    var targetProp = targetProps.FirstOrDefault(x => x.Name == prop.Name);
    if (targetProp != null)
        targetProp.SetValue(CurrentUser, prop.GetValue(model));
}

db.Entry(CurrentUser).State = EntityState.Modified;
db.SaveChanges();

AutoMapper

First create map on application startup:

cfg.CreateMap<ApplicationUserViewModel, ApplicationUser>();

Then execute the map:

_mapper.Map<ApplicationUserViewModel, ApplicationUser>(model, CurrentUser)
Sign up to request clarification or add additional context in comments.

1 Comment

Note that either solution only significantly helps you if the property names are always the same (or at least a significant amount of them are the same). For each property mapping pair that has different names, you will still have to manually set up the mapping. (This is not a shortcoming of Chris' answer, but rather a logical consequence of not being able to automatically guess the target property name)
0

You could do this

ApplicationUser CurrentUser = db.Users.FirstOrDefault(x => x.Id == model.Id);
Context.Entry(CurrentUser).CurrentValues.SetValues(ObjectBeingPassed);

In your method you need to be expecting the record that has come up from your post which will contain every property (ObjectBeingPassed).

Comments

-1

There are third way to do it

  • Create a mapping method where you manually map properties. (No "expensive" reflection)
  • Create unit tests for that mapping method where you verify that all properties set correctly and not missed.

With tests you will be always sure that no properties missed or set to wrong values used for them.
With tests you can then refactor your method top use Reflection of Automapper and you will always have "check" that properties mapped correctly.

5 Comments

"Create a mapping method where you manually map properties" Your first step is exactly what OP is trying to avoid. Furthermore, since OP is worried about forgetting a property; what makes you think he would not be worried about forgetting a property in the unit test?
@Flater, when you want add or update(rename, change type etc) property you first will add it to the test. With failing test you will change your mapping method until test pass. Doing this way you don't forget any properties. Main OP's concerns is maintaining, when you mapping user input to entity - after some time you will end up with situation when you have model properties which shouldn't be mapped to the entity. Or they should be modified/normalized before mapping...
"With failing test you will change your mapping method until test pass." Writing a test that correctly fails inherently means that you must test for all properties to have been set correctly. As I mentioned, OP has posted this question specifically because he worries about forgetting to set all properties. You've merely shifted the problem from creating the original mapping to creating the unit test; but the problem remains unchanged and unsolved. Also, nowhere in the question (nor the comments) does OP mention that his main concern is about maintaining existing code.
You've merely shifted the problem from creating the original mapping to creating the unit test; but the problem remains unchanged and unsolved - OP's concerns about forgetting some properties during mapping. Unit tests will notice you if some property missing. Yes - only disadvantage is you need write "correct" unit test - but you do it only one time.
The problem is still that OP fears forgetting properties. Whether it's a.Field = b.Field; or it's Assert.AreEqual(a.Field, b.Field) does not matter. Either one is prone to the same developer error. I agree with your answer if OP is writing the same mapping (for the same classes) several times in the same code base (and therefore could mess up one of the many mappings). But that is not part of the question as it is currently phrased.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.