Tracking which entity properties have changed





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







2












$begingroup$


There are a number of topics pertaining to entity change tracking. All the ones I've seen involve either 1) notifying when a property has changed or 2) merely determining whether or not an entity is dirty.



My goal is quite different. I wrote a mini-repository framework that generates SQL for inserts, selects, updates, and deletes. Updates are particularly tricky because the framework needs to support partial updates. To do this, you have to know which properties have changed and only generate the update SQL for those specific fields. Otherwise, you run the risk of overwriting existing data with nulls or default values unless you load the original entity from the database prior to the update.



Take this person class as an example:



public class Person
{
public string FirstName { get; set; }

public string LastName { get; set; }

public DateTime DateOfBirth { get; set; }
}


Quite a bit of boilerplate code would be required to allow it to track its own property changes. Here's an example (leaving LastName and DateOfBirth alone for brevity):



public class Person
{
HashSet<string> ChangedProperties =
new HashSet<string>(StringComparer.OrdinalIgnoreCase);

string _FirstName = null;
public string FirstName
{
get { return _FirstName; }
set
{
ChangedProperties.Add(nameof(FirstName));
_FirstName = value;
}
}

public string LastName { get; set; }

public DateTime DateOfBirth { get; set; }

public string GetChangedProperties()
{
return ChangedProperties.ToArray();
}
}


Imagine having to do this for 50 properties or more (some of the classes I work with have 90+ properties).



So I came up with a special tracking class that uses generics and expressions to encapsulate all of that boilerplate property code. Having actually begun to use it in my application, I've developed a bit of a love/hate relationship with it.



Here's the watered-down version of the class:



public class PropertyChangeTracker<TEntity> where TEntity : class
{
TEntity Entity = null;
HashSet<PropertyInfo> ChangedProperties = new HashSet<PropertyInfo>();

public PropertyChangeTracker(TEntity Entity)
{
this.Entity = Entity;
}

public void Set<TValue>(Expression<Func<TEntity, TValue>> Expression, TValue Value)
{
var Member = (Expression.Body as MemberExpression).Member as PropertyInfo;

ChangedProperties.Add(Member);

Member.SetValue(Entity, Value);
}

public PropertyInfo GetChangedProperties()
{
return ChangedProperties.ToArray();
}
}


It uses reflection to set the property which is, by many engineer standards, a serious no-no that will result in a Christmas stocking full of coal. My production version of the above code actually uses dynamically-generated delegates using expression trees to set entity properties (I may post that code for review at another time), but this should get you started. So long as you're not using reflection haphazardly within thousands of iterations, it isn't really that bad, especially these days with faster hardware and the accumulation of all the .NET framework optimizations that have taken place since .NET's early days.



So here's how you use the class:



var BobJones = PersonRepo.GetPersonById(100);
var Tracker = new EntityChangeTracker<Person>(BobJones);

Tracker.Set(e => e.LastName, "Jones");
Tracker.Set(e => e.DateOfBirth, new DateTime(1970, 2, 15));


In that example, you load Bob from the database and make a correction to his last name and DOB. The tracking class will track that only those properties have changed. When you go to generate your update, you just do this:



    var Properties = Tracker.GetChangedProperties();

string Sql = $@"
update persontable
set {string.Join(", ", Properties.Select(pi => $"{pi.Name} = :{pi.Name}").ToArray())}
where id = 100";


My framework knows how to get the entity table name and primary key for the where clause, but this shows how the update fields are generated:



update persontable 
set LastName = :LastName, DateOfBirth = :DateOfBirth
where id = 100


You can then parameterize it like this:



    var Parameters = Properties.Select(p => new YourDbParameter(p.Name, p.GetValue(BobJones)));


So about that love/hate relationship I mentioned earlier. Here are the pros/cons to this:



Pros




  • The automation/encapsulation aspect prevents the need to write massive amounts of boilerplate code within your class, especially when you're dealing with a large number of properties. Going from auto-properties to properties with concrete setters and getters that contain tracking logic can increase your class code by as much as 11 lines of code per property.

  • The extraction of the property name from an expression eliminates magic strings, though .NET 4.6.1 now offers the nameof keyword which can mitigate this as shown in my first example.

  • This solution can be retrofitted for use with any existing class without having to convert every auto-property to complex properties with tracking logic.


Cons:




  • In an effort to eliminate boilerplate code within your class, you end up writing a bit more code anyway in the form of a lambda expressions every time you want to track changes to your class, but this is typically only noticeable with VB.NET and its verbose lambda syntax. If you just bite down and write all the tracking code within your class, you can, as Ron Popeil would say, set it and forget it and only have to update the code whenever you need to add a new property.


Overall, I really think the pros outweigh the cons, but want to see if anyone else can find a better way to achieve what I've done here or extol the virtues of another implementation.










share|improve this question











$endgroup$












  • $begingroup$
    Did you consider t4 for auto-generating boilerplate code? You can also either wrap entities in a generated wrapper that tracks changes to the properties or simply store a copy of the originally retrieved entity inside your Tracker. But maybe my real question is why you spend time writing your own ORM these days instead of focusing on your business logic.
    $endgroup$
    – Mattias Åslund
    May 11 '16 at 17:45










  • $begingroup$
    @MattiasÅslund Haven't heard of T4, but will look into it. I also don't want to store a copy of the original entity because that means I have to make a database call to get it and I am a minimalist when it comes to accessing resources. I am not really sure I understand the last question.
    $endgroup$
    – oscilatingcretin
    May 11 '16 at 17:52


















2












$begingroup$


There are a number of topics pertaining to entity change tracking. All the ones I've seen involve either 1) notifying when a property has changed or 2) merely determining whether or not an entity is dirty.



My goal is quite different. I wrote a mini-repository framework that generates SQL for inserts, selects, updates, and deletes. Updates are particularly tricky because the framework needs to support partial updates. To do this, you have to know which properties have changed and only generate the update SQL for those specific fields. Otherwise, you run the risk of overwriting existing data with nulls or default values unless you load the original entity from the database prior to the update.



Take this person class as an example:



public class Person
{
public string FirstName { get; set; }

public string LastName { get; set; }

public DateTime DateOfBirth { get; set; }
}


Quite a bit of boilerplate code would be required to allow it to track its own property changes. Here's an example (leaving LastName and DateOfBirth alone for brevity):



public class Person
{
HashSet<string> ChangedProperties =
new HashSet<string>(StringComparer.OrdinalIgnoreCase);

string _FirstName = null;
public string FirstName
{
get { return _FirstName; }
set
{
ChangedProperties.Add(nameof(FirstName));
_FirstName = value;
}
}

public string LastName { get; set; }

public DateTime DateOfBirth { get; set; }

public string GetChangedProperties()
{
return ChangedProperties.ToArray();
}
}


Imagine having to do this for 50 properties or more (some of the classes I work with have 90+ properties).



So I came up with a special tracking class that uses generics and expressions to encapsulate all of that boilerplate property code. Having actually begun to use it in my application, I've developed a bit of a love/hate relationship with it.



Here's the watered-down version of the class:



public class PropertyChangeTracker<TEntity> where TEntity : class
{
TEntity Entity = null;
HashSet<PropertyInfo> ChangedProperties = new HashSet<PropertyInfo>();

public PropertyChangeTracker(TEntity Entity)
{
this.Entity = Entity;
}

public void Set<TValue>(Expression<Func<TEntity, TValue>> Expression, TValue Value)
{
var Member = (Expression.Body as MemberExpression).Member as PropertyInfo;

ChangedProperties.Add(Member);

Member.SetValue(Entity, Value);
}

public PropertyInfo GetChangedProperties()
{
return ChangedProperties.ToArray();
}
}


It uses reflection to set the property which is, by many engineer standards, a serious no-no that will result in a Christmas stocking full of coal. My production version of the above code actually uses dynamically-generated delegates using expression trees to set entity properties (I may post that code for review at another time), but this should get you started. So long as you're not using reflection haphazardly within thousands of iterations, it isn't really that bad, especially these days with faster hardware and the accumulation of all the .NET framework optimizations that have taken place since .NET's early days.



So here's how you use the class:



var BobJones = PersonRepo.GetPersonById(100);
var Tracker = new EntityChangeTracker<Person>(BobJones);

Tracker.Set(e => e.LastName, "Jones");
Tracker.Set(e => e.DateOfBirth, new DateTime(1970, 2, 15));


In that example, you load Bob from the database and make a correction to his last name and DOB. The tracking class will track that only those properties have changed. When you go to generate your update, you just do this:



    var Properties = Tracker.GetChangedProperties();

string Sql = $@"
update persontable
set {string.Join(", ", Properties.Select(pi => $"{pi.Name} = :{pi.Name}").ToArray())}
where id = 100";


My framework knows how to get the entity table name and primary key for the where clause, but this shows how the update fields are generated:



update persontable 
set LastName = :LastName, DateOfBirth = :DateOfBirth
where id = 100


You can then parameterize it like this:



    var Parameters = Properties.Select(p => new YourDbParameter(p.Name, p.GetValue(BobJones)));


So about that love/hate relationship I mentioned earlier. Here are the pros/cons to this:



Pros




  • The automation/encapsulation aspect prevents the need to write massive amounts of boilerplate code within your class, especially when you're dealing with a large number of properties. Going from auto-properties to properties with concrete setters and getters that contain tracking logic can increase your class code by as much as 11 lines of code per property.

  • The extraction of the property name from an expression eliminates magic strings, though .NET 4.6.1 now offers the nameof keyword which can mitigate this as shown in my first example.

  • This solution can be retrofitted for use with any existing class without having to convert every auto-property to complex properties with tracking logic.


Cons:




  • In an effort to eliminate boilerplate code within your class, you end up writing a bit more code anyway in the form of a lambda expressions every time you want to track changes to your class, but this is typically only noticeable with VB.NET and its verbose lambda syntax. If you just bite down and write all the tracking code within your class, you can, as Ron Popeil would say, set it and forget it and only have to update the code whenever you need to add a new property.


Overall, I really think the pros outweigh the cons, but want to see if anyone else can find a better way to achieve what I've done here or extol the virtues of another implementation.










share|improve this question











$endgroup$












  • $begingroup$
    Did you consider t4 for auto-generating boilerplate code? You can also either wrap entities in a generated wrapper that tracks changes to the properties or simply store a copy of the originally retrieved entity inside your Tracker. But maybe my real question is why you spend time writing your own ORM these days instead of focusing on your business logic.
    $endgroup$
    – Mattias Åslund
    May 11 '16 at 17:45










  • $begingroup$
    @MattiasÅslund Haven't heard of T4, but will look into it. I also don't want to store a copy of the original entity because that means I have to make a database call to get it and I am a minimalist when it comes to accessing resources. I am not really sure I understand the last question.
    $endgroup$
    – oscilatingcretin
    May 11 '16 at 17:52














2












2








2





$begingroup$


There are a number of topics pertaining to entity change tracking. All the ones I've seen involve either 1) notifying when a property has changed or 2) merely determining whether or not an entity is dirty.



My goal is quite different. I wrote a mini-repository framework that generates SQL for inserts, selects, updates, and deletes. Updates are particularly tricky because the framework needs to support partial updates. To do this, you have to know which properties have changed and only generate the update SQL for those specific fields. Otherwise, you run the risk of overwriting existing data with nulls or default values unless you load the original entity from the database prior to the update.



Take this person class as an example:



public class Person
{
public string FirstName { get; set; }

public string LastName { get; set; }

public DateTime DateOfBirth { get; set; }
}


Quite a bit of boilerplate code would be required to allow it to track its own property changes. Here's an example (leaving LastName and DateOfBirth alone for brevity):



public class Person
{
HashSet<string> ChangedProperties =
new HashSet<string>(StringComparer.OrdinalIgnoreCase);

string _FirstName = null;
public string FirstName
{
get { return _FirstName; }
set
{
ChangedProperties.Add(nameof(FirstName));
_FirstName = value;
}
}

public string LastName { get; set; }

public DateTime DateOfBirth { get; set; }

public string GetChangedProperties()
{
return ChangedProperties.ToArray();
}
}


Imagine having to do this for 50 properties or more (some of the classes I work with have 90+ properties).



So I came up with a special tracking class that uses generics and expressions to encapsulate all of that boilerplate property code. Having actually begun to use it in my application, I've developed a bit of a love/hate relationship with it.



Here's the watered-down version of the class:



public class PropertyChangeTracker<TEntity> where TEntity : class
{
TEntity Entity = null;
HashSet<PropertyInfo> ChangedProperties = new HashSet<PropertyInfo>();

public PropertyChangeTracker(TEntity Entity)
{
this.Entity = Entity;
}

public void Set<TValue>(Expression<Func<TEntity, TValue>> Expression, TValue Value)
{
var Member = (Expression.Body as MemberExpression).Member as PropertyInfo;

ChangedProperties.Add(Member);

Member.SetValue(Entity, Value);
}

public PropertyInfo GetChangedProperties()
{
return ChangedProperties.ToArray();
}
}


It uses reflection to set the property which is, by many engineer standards, a serious no-no that will result in a Christmas stocking full of coal. My production version of the above code actually uses dynamically-generated delegates using expression trees to set entity properties (I may post that code for review at another time), but this should get you started. So long as you're not using reflection haphazardly within thousands of iterations, it isn't really that bad, especially these days with faster hardware and the accumulation of all the .NET framework optimizations that have taken place since .NET's early days.



So here's how you use the class:



var BobJones = PersonRepo.GetPersonById(100);
var Tracker = new EntityChangeTracker<Person>(BobJones);

Tracker.Set(e => e.LastName, "Jones");
Tracker.Set(e => e.DateOfBirth, new DateTime(1970, 2, 15));


In that example, you load Bob from the database and make a correction to his last name and DOB. The tracking class will track that only those properties have changed. When you go to generate your update, you just do this:



    var Properties = Tracker.GetChangedProperties();

string Sql = $@"
update persontable
set {string.Join(", ", Properties.Select(pi => $"{pi.Name} = :{pi.Name}").ToArray())}
where id = 100";


My framework knows how to get the entity table name and primary key for the where clause, but this shows how the update fields are generated:



update persontable 
set LastName = :LastName, DateOfBirth = :DateOfBirth
where id = 100


You can then parameterize it like this:



    var Parameters = Properties.Select(p => new YourDbParameter(p.Name, p.GetValue(BobJones)));


So about that love/hate relationship I mentioned earlier. Here are the pros/cons to this:



Pros




  • The automation/encapsulation aspect prevents the need to write massive amounts of boilerplate code within your class, especially when you're dealing with a large number of properties. Going from auto-properties to properties with concrete setters and getters that contain tracking logic can increase your class code by as much as 11 lines of code per property.

  • The extraction of the property name from an expression eliminates magic strings, though .NET 4.6.1 now offers the nameof keyword which can mitigate this as shown in my first example.

  • This solution can be retrofitted for use with any existing class without having to convert every auto-property to complex properties with tracking logic.


Cons:




  • In an effort to eliminate boilerplate code within your class, you end up writing a bit more code anyway in the form of a lambda expressions every time you want to track changes to your class, but this is typically only noticeable with VB.NET and its verbose lambda syntax. If you just bite down and write all the tracking code within your class, you can, as Ron Popeil would say, set it and forget it and only have to update the code whenever you need to add a new property.


Overall, I really think the pros outweigh the cons, but want to see if anyone else can find a better way to achieve what I've done here or extol the virtues of another implementation.










share|improve this question











$endgroup$




There are a number of topics pertaining to entity change tracking. All the ones I've seen involve either 1) notifying when a property has changed or 2) merely determining whether or not an entity is dirty.



My goal is quite different. I wrote a mini-repository framework that generates SQL for inserts, selects, updates, and deletes. Updates are particularly tricky because the framework needs to support partial updates. To do this, you have to know which properties have changed and only generate the update SQL for those specific fields. Otherwise, you run the risk of overwriting existing data with nulls or default values unless you load the original entity from the database prior to the update.



Take this person class as an example:



public class Person
{
public string FirstName { get; set; }

public string LastName { get; set; }

public DateTime DateOfBirth { get; set; }
}


Quite a bit of boilerplate code would be required to allow it to track its own property changes. Here's an example (leaving LastName and DateOfBirth alone for brevity):



public class Person
{
HashSet<string> ChangedProperties =
new HashSet<string>(StringComparer.OrdinalIgnoreCase);

string _FirstName = null;
public string FirstName
{
get { return _FirstName; }
set
{
ChangedProperties.Add(nameof(FirstName));
_FirstName = value;
}
}

public string LastName { get; set; }

public DateTime DateOfBirth { get; set; }

public string GetChangedProperties()
{
return ChangedProperties.ToArray();
}
}


Imagine having to do this for 50 properties or more (some of the classes I work with have 90+ properties).



So I came up with a special tracking class that uses generics and expressions to encapsulate all of that boilerplate property code. Having actually begun to use it in my application, I've developed a bit of a love/hate relationship with it.



Here's the watered-down version of the class:



public class PropertyChangeTracker<TEntity> where TEntity : class
{
TEntity Entity = null;
HashSet<PropertyInfo> ChangedProperties = new HashSet<PropertyInfo>();

public PropertyChangeTracker(TEntity Entity)
{
this.Entity = Entity;
}

public void Set<TValue>(Expression<Func<TEntity, TValue>> Expression, TValue Value)
{
var Member = (Expression.Body as MemberExpression).Member as PropertyInfo;

ChangedProperties.Add(Member);

Member.SetValue(Entity, Value);
}

public PropertyInfo GetChangedProperties()
{
return ChangedProperties.ToArray();
}
}


It uses reflection to set the property which is, by many engineer standards, a serious no-no that will result in a Christmas stocking full of coal. My production version of the above code actually uses dynamically-generated delegates using expression trees to set entity properties (I may post that code for review at another time), but this should get you started. So long as you're not using reflection haphazardly within thousands of iterations, it isn't really that bad, especially these days with faster hardware and the accumulation of all the .NET framework optimizations that have taken place since .NET's early days.



So here's how you use the class:



var BobJones = PersonRepo.GetPersonById(100);
var Tracker = new EntityChangeTracker<Person>(BobJones);

Tracker.Set(e => e.LastName, "Jones");
Tracker.Set(e => e.DateOfBirth, new DateTime(1970, 2, 15));


In that example, you load Bob from the database and make a correction to his last name and DOB. The tracking class will track that only those properties have changed. When you go to generate your update, you just do this:



    var Properties = Tracker.GetChangedProperties();

string Sql = $@"
update persontable
set {string.Join(", ", Properties.Select(pi => $"{pi.Name} = :{pi.Name}").ToArray())}
where id = 100";


My framework knows how to get the entity table name and primary key for the where clause, but this shows how the update fields are generated:



update persontable 
set LastName = :LastName, DateOfBirth = :DateOfBirth
where id = 100


You can then parameterize it like this:



    var Parameters = Properties.Select(p => new YourDbParameter(p.Name, p.GetValue(BobJones)));


So about that love/hate relationship I mentioned earlier. Here are the pros/cons to this:



Pros




  • The automation/encapsulation aspect prevents the need to write massive amounts of boilerplate code within your class, especially when you're dealing with a large number of properties. Going from auto-properties to properties with concrete setters and getters that contain tracking logic can increase your class code by as much as 11 lines of code per property.

  • The extraction of the property name from an expression eliminates magic strings, though .NET 4.6.1 now offers the nameof keyword which can mitigate this as shown in my first example.

  • This solution can be retrofitted for use with any existing class without having to convert every auto-property to complex properties with tracking logic.


Cons:




  • In an effort to eliminate boilerplate code within your class, you end up writing a bit more code anyway in the form of a lambda expressions every time you want to track changes to your class, but this is typically only noticeable with VB.NET and its verbose lambda syntax. If you just bite down and write all the tracking code within your class, you can, as Ron Popeil would say, set it and forget it and only have to update the code whenever you need to add a new property.


Overall, I really think the pros outweigh the cons, but want to see if anyone else can find a better way to achieve what I've done here or extol the virtues of another implementation.







c# .net






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 11 '16 at 19:26







oscilatingcretin

















asked May 11 '16 at 17:08









oscilatingcretinoscilatingcretin

13116




13116












  • $begingroup$
    Did you consider t4 for auto-generating boilerplate code? You can also either wrap entities in a generated wrapper that tracks changes to the properties or simply store a copy of the originally retrieved entity inside your Tracker. But maybe my real question is why you spend time writing your own ORM these days instead of focusing on your business logic.
    $endgroup$
    – Mattias Åslund
    May 11 '16 at 17:45










  • $begingroup$
    @MattiasÅslund Haven't heard of T4, but will look into it. I also don't want to store a copy of the original entity because that means I have to make a database call to get it and I am a minimalist when it comes to accessing resources. I am not really sure I understand the last question.
    $endgroup$
    – oscilatingcretin
    May 11 '16 at 17:52


















  • $begingroup$
    Did you consider t4 for auto-generating boilerplate code? You can also either wrap entities in a generated wrapper that tracks changes to the properties or simply store a copy of the originally retrieved entity inside your Tracker. But maybe my real question is why you spend time writing your own ORM these days instead of focusing on your business logic.
    $endgroup$
    – Mattias Åslund
    May 11 '16 at 17:45










  • $begingroup$
    @MattiasÅslund Haven't heard of T4, but will look into it. I also don't want to store a copy of the original entity because that means I have to make a database call to get it and I am a minimalist when it comes to accessing resources. I am not really sure I understand the last question.
    $endgroup$
    – oscilatingcretin
    May 11 '16 at 17:52
















$begingroup$
Did you consider t4 for auto-generating boilerplate code? You can also either wrap entities in a generated wrapper that tracks changes to the properties or simply store a copy of the originally retrieved entity inside your Tracker. But maybe my real question is why you spend time writing your own ORM these days instead of focusing on your business logic.
$endgroup$
– Mattias Åslund
May 11 '16 at 17:45




$begingroup$
Did you consider t4 for auto-generating boilerplate code? You can also either wrap entities in a generated wrapper that tracks changes to the properties or simply store a copy of the originally retrieved entity inside your Tracker. But maybe my real question is why you spend time writing your own ORM these days instead of focusing on your business logic.
$endgroup$
– Mattias Åslund
May 11 '16 at 17:45












$begingroup$
@MattiasÅslund Haven't heard of T4, but will look into it. I also don't want to store a copy of the original entity because that means I have to make a database call to get it and I am a minimalist when it comes to accessing resources. I am not really sure I understand the last question.
$endgroup$
– oscilatingcretin
May 11 '16 at 17:52




$begingroup$
@MattiasÅslund Haven't heard of T4, but will look into it. I also don't want to store a copy of the original entity because that means I have to make a database call to get it and I am a minimalist when it comes to accessing resources. I am not really sure I understand the last question.
$endgroup$
– oscilatingcretin
May 11 '16 at 17:52










1 Answer
1






active

oldest

votes


















1












$begingroup$

I suggest you using static AOP something like Fody or Postsharp , you do not need change you entity , just add a Attribute to class, TrackChange.Fody can perfect to solve your problem, https://github.com/jrt324/TrackChange






share|improve this answer








New contributor




guaike is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$














    Your Answer





    StackExchange.ifUsing("editor", function () {
    return StackExchange.using("mathjaxEditing", function () {
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    });
    });
    }, "mathjax-editing");

    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "196"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f128113%2ftracking-which-entity-properties-have-changed%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1












    $begingroup$

    I suggest you using static AOP something like Fody or Postsharp , you do not need change you entity , just add a Attribute to class, TrackChange.Fody can perfect to solve your problem, https://github.com/jrt324/TrackChange






    share|improve this answer








    New contributor




    guaike is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.






    $endgroup$


















      1












      $begingroup$

      I suggest you using static AOP something like Fody or Postsharp , you do not need change you entity , just add a Attribute to class, TrackChange.Fody can perfect to solve your problem, https://github.com/jrt324/TrackChange






      share|improve this answer








      New contributor




      guaike is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      $endgroup$
















        1












        1








        1





        $begingroup$

        I suggest you using static AOP something like Fody or Postsharp , you do not need change you entity , just add a Attribute to class, TrackChange.Fody can perfect to solve your problem, https://github.com/jrt324/TrackChange






        share|improve this answer








        New contributor




        guaike is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.






        $endgroup$



        I suggest you using static AOP something like Fody or Postsharp , you do not need change you entity , just add a Attribute to class, TrackChange.Fody can perfect to solve your problem, https://github.com/jrt324/TrackChange







        share|improve this answer








        New contributor




        guaike is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.









        share|improve this answer



        share|improve this answer






        New contributor




        guaike is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.









        answered 1 hour ago









        guaikeguaike

        1111




        1111




        New contributor




        guaike is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.





        New contributor





        guaike is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.






        guaike is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Code Review Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f128113%2ftracking-which-entity-properties-have-changed%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Сан-Квентин

            8-я гвардейская общевойсковая армия

            Алькесар