Tracking which entity properties have changed The 2019 Stack Overflow Developer Survey Results Are InDealing with Entity Framework's lack of enum supportEntity Framework 6.0.2 - Performance of Auditable Change Tracking Part 2 of 2Model Design for MVC4 Applications using Entity Framework Code FirstInsert Model object effectively using entity framworkObject to object mapping verification - is this extension method useful?Indexed Properties in C#Tracking Entity Changes (not EF)Setting Entity Framework up for successWeb-app for tracking containersImmutable type updater using a special constructor
Spanish for "widget"
If a poisoned arrow's piercing damage is reduced to 0, do you still get poisoned?
Extreme, unacceptable situation and I can't attend work tomorrow morning
What is a mixture ratio of propellant?
How can I fix this gap between bookcases I made?
Does light intensity oscillate really fast since it is a wave?
Where to refill my bottle in India?
I looked up a future colleague on LinkedIn before I started a job. I told my colleague about it and he seemed surprised. Should I apologize?
Should I use my personal or workplace e-mail when registering to external websites for work purpose?
In microwave frequencies, do you use a circulator when you need a (near) perfect diode?
Why is my p-value correlated to difference between means in two sample tests?
Why could you hear an Amstrad CPC working?
Idiomatic way to prevent slicing?
Can distinct morphisms between curves induce the same morphism on singular cohomology?
How can I create a character who can assume the widest possible range of creature sizes?
What are the motivations for publishing new editions of an existing textbook, beyond new discoveries in a field?
How to manage monthly salary
What is the steepest angle that a canal can be traversable without locks?
What is the best strategy for white in this position?
Is "plugging out" electronic devices an American expression?
Why Did Howard Stark Use All The Vibranium They Had On A Prototype Shield?
Limit the amount of RAM Mathematica may access?
It's possible to achieve negative score?
How to answer pointed "are you quitting" questioning when I don't want them to suspect
Tracking which entity properties have changed
The 2019 Stack Overflow Developer Survey Results Are InDealing with Entity Framework's lack of enum supportEntity Framework 6.0.2 - Performance of Auditable Change Tracking Part 2 of 2Model Design for MVC4 Applications using Entity Framework Code FirstInsert Model object effectively using entity framworkObject to object mapping verification - is this extension method useful?Indexed Properties in C#Tracking Entity Changes (not EF)Setting Entity Framework up for successWeb-app for tracking containersImmutable type updater using a special constructor
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
$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.
c# .net
$endgroup$
add a comment |
$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.
c# .net
$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
add a comment |
$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.
c# .net
$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
c# .net
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
add a comment |
$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
add a comment |
1 Answer
1
active
oldest
votes
$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
New contributor
$endgroup$
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
$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
New contributor
$endgroup$
add a comment |
$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
New contributor
$endgroup$
add a comment |
$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
New contributor
$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
New contributor
New contributor
answered 9 mins ago
guaikeguaike
1111
1111
New contributor
New contributor
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
var $window = $(window),
onScroll = function(e)
var $elem = $('.new-login-left'),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $elem.offset().top,
elemBottom = elemTop + $elem.height();
if ((docViewTop elemBottom))
StackExchange.using('gps', function() StackExchange.gps.track('embedded_signup_form.view', location: 'question_page' ); );
$window.unbind('scroll', onScroll);
;
$window.on('scroll', onScroll);
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
$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