简体   繁体   中英

Comparing two models in .NET

Lets imaging the we have model:

public class InheritModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string OtherData { get; set; }
}

We have a controller with View, that represents this model:

private InheritModel GetAll()
{
    return new InheritModel
    {
        Name = "name1",
        Description = "decs 1",
        OtherData = "other"
    };
}

public ActionResult Index()
{
    return View(GetAll());
}

Now we can edit this in View, change some data and post in back to server:

[HttpPost]
public ActionResult Index(InheritModel model)
{
    var merged = new MergeModel();
    return View(merged.Merge(model, GetAll()));
}

What i need to do:

  • In view we have a reproduction of model
  • User change something and post
  • Merge method need to compare field-by-field posted model and previous model
  • Merge method create a new InheritModel with data that was changed in posted model, all other data should be null

Can somebody help me to make this Merge method?

UPDATE(!)

It's not a trivial task. Approaching like:

public InheritModel Merge(InheritModel current, InheritModel orig)
{
    var result = new InheritModel();
    if (current.Id != orig.Id) 
    {
        result.Id = current.Id;
    }
}

Not applicable. It's should be Generic solution. We have more than 200 properties in the model. And the first model is built from severeal tables from DB.

public InheritModel Merge(InheritModel current, InheritModel orig)
{
    var result = new InheritModel();
    if (current.Id != orig.Id) 
    {
        result.Id = current.Id;
    }
    if (current.Name != orig.Name) 
    {
        result.Name = current.Name;
    }
    ... for the other properties

    return result;
}

Another possibility is to use reflection and loop through all properties and set their values:

public InheritModel Merge(InheritModel current, InheritModel orig)
{
    var result = new InheritModel();
    var properties = TypeDescriptor.GetProperties(typeof(InheritModel));
    foreach (PropertyDescriptor property in properties)
    {
        var currentValue = property.GetValue(current);
        if (currentValue != property.GetValue(orig))
        {
            property.SetValue(result, currentValue);
        }
    }
    return result;
}

Obviously this works only for 1 level nesting of properties.

Per topic, it seems that what you want is a sort of "change tracking" mechanism which is definitely not trivial or simple by any means. Probably, it makes sense to use any modern ORM solution to do that for you, does it?

Because otherwise you need to develop something that maintains the "context" (the 1st level object cache) like EF's ObjectContext or NH's Session that would be generic solution.

Also, there is no information on what happens at the lower level - how do you actualy save the data. Do you already have some mechanism that saves the object by traversing it's "non-null" properties?

I have a similar project experience, which made me thought a lot about the original design. Think the following question:

You have a view that representing a model, then users modified something of the model in the view, all the CHANGES are posted to server and the model is modified, and then it's saved to database probably. What's posted to the server on earth?

An instance of InheritModel ? No. You want the changes only. It's actually part of InheritModel , it's a InheritModel Updater , it's an instance of Updater<InheritModel> . And in your question you need to merge two models, because your Update method looks like:

public InheritModel Update(InheritedModel newModel)
{
    //assign the properties of the newModel to the old, and save it to db
    //return the latest version of the InheritedModel
}

Now ask yourself: why do I need a whole instance of InheritedModel when I just want to update one property only?

So my final solution is: posting the changes to the controller, the argument is something like a Updater<TModel> , not TModel itself. And the Updater<TModel> can be applied to a TModel , the properties metioned in the updater is assigned and saved. There shouldn't a MERGE operation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM