I want so every added\changed record will have a time stamp of creation\change.
But - so it will be easy to embed and easy to manage - automatically.
Overwrite the 'DbContext' class or embed this in the '.tt' file (Codefirst \ DBFirst)
The code assume so you have the fields 'CreatedOn'\'ModifiedOn' inside the POCO.
If you don't have them, or you have only one - the code will work fine.
Be aware! If you use a extension (as this one) so allow you to do batch updates or changes from a stored procedure - this will not work
EDIT:
I found the source of my inspiration - thanks 'Nick' here
public override int SaveChanges()
{
var context = ((IObjectContextAdapter)this).ObjectContext;
var currentTime = DateTime.Now;
var objectStateEntries = from v in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)
where v.IsRelationship == false && v.Entity != null
select v;
foreach (var entry in objectStateEntries)
{
var createdOnProp = entry.Entity.GetType().GetProperty("CreatedOn");
if (createdOnProp != null)
{
if (entry.State == EntityState.Added)
{
if (createdOnProp != null)
{
createdOnProp.SetValue(entry.Entity, currentTime);
}
}
else
{
Entry(entry.Entity).Property("CreatedOn").IsModified = false;
}
}
var modifiedOnProp = entry.Entity.GetType().GetProperty("ModifiedOn");
if (modifiedOnProp != null)
{
modifiedOnProp.SetValue(entry.Entity, currentTime);
}
}
return base.SaveChanges();
}
Related
I'm using AngularJS ver. 1.2.15 on my project. And, I have a select element on one of my views as per below:
<select class="select-white form-control form-select" id="cat2_{{feed.id}}" ng-model="feed.operationstatusid" ng-change="updateCategoryAndStatus(feed, true)"></select>
And, I'm feeding this element like this:
function SetCategory2(cat1Id, feed) {
var feedId = feed.id;
var fromRuleOpStatusId = -1;
$('#cat2_' + feedId).find('option').remove();
if (cat1Id > -1) {
$('#cat2_' + feedId).append($('<option></option>').text(lang.SelectSubCategory).val(0));
$.each($scope.category2, function (index, cat2Item) {
$('#cat2_' + feedId).append($('<option></option>').text(cat2Item.statusdescription).val(cat2Item.id));
});
var isselected = false;
$.each($scope.category2, function (index, cat2Item) {
if (feed.operationstatusid == cat2Item.id) {
$('#cat2_' + feedId).val(cat2Item.id);
fromRuleOpStatusId = -1;
isselected = true;
}
else {
var feedStr = "";
if (feed.title != undefined && feed.title != null) {
feedStr = feed.title.toLowerCase();
}
if ($scope.catTitleRulesTwo) {
$.each($scope.catTitleRulesTwo, function (r_index, r_item) {
if (cat2Item.id == r_item.titleCode && !isselected) {
if (feedStr != undefined && feedStr != null && r_item != undefined && r_item != null) {
String.prototype.contains = function (str) { return this.toLowerCase().indexOf(str) !== -1; };
var text = feedStr;
if (eval(r_item.ruleexpression)) {
$('#cat2_' + feedId).val(cat2Item.id);
fromRuleOpStatusId = cat2Item.id;
isselected = true;
}
}
}
});
}
}
});
if (fromRuleOpStatusId != -1) {
feed.operationstatusid = fromRuleOpStatusId;
}
}
else {
$('#cat2_' + feedId).append($('<option></option>').text(lang.SelectSubCategory).val(0));
}
}
I am aware of the facts about eval function, but the project I'm working on is quite old, so does the code. Anyway, this is about business logic and quite irrelevant with the thing I'm going to ask (or so I was thinking).
As you can see I'm appending all the options before I set the value of the selectbox with using .val(...). I have also checked that values do match along with the data types. But, when I observe this function step by step, I saw that selected value does show up without flaw. After the code finish with my above mentioned function (SetCategory2), code goes through on of the function located on AngularJS file, named xhr.onreadystatechange. It's not a long function, so I'm sharing it also on below.
xhr.onreadystatechange = function() {
if (xhr && xhr.readyState == 4) {
var responseHeaders = null,
response = null;
if(status !== ABORTED) {
responseHeaders = xhr.getAllResponseHeaders();
response = ('response' in xhr) ? xhr.response : xhr.responseText;
}
completeRequest(callback,
status || xhr.status,
response,
responseHeaders);
}
};
After the code released from this function, respective selectbox's value is pointed at the empty option.
I have run into topics which talks about this behaviour might due to invalid option-value match, but as I described above, I append all my options before deciding the value. So, I can't figure out what I'm missing.
Thank you in advance.
I have twenty eight instances of a two-frame MovieClip (frame1 = off - frame 2 = on) to select PDFs to send. The following code works fine, but I am looking to tighten it up and make it less verbose and easier to read. I include only one reference to an instance for space and sanity sake.
function PDFClick(e:MouseEvent):void {
targetPDF = e.target.ID;
trace("targetPDF " +targetPDF);
if (targetPDF == "PDF1")
if (pdf.pcconnectionPDF1.currentFrame == 1)
{
pdf.pcconnectionPDF1.gotoAndPlay(2);
PDF1 = 1;
trace("PDF1 is "+PDF1);
}else{
pdf.pcconnectionPDF1.gotoAndPlay(1);
PDF1 = 0;
trace("PDF1 is "+PDF1);
}
Thanks! trying to learn
You'll want to generalize your calls to your ID, that way you don't need special code for each condition.
function PDFClick(e:MouseEvent):void {
var ID:String = e.target.ID;
var mc = pdf["pcconnection" + ID];
if (mc.currentframe == 1) {
mc.gotoAndPlay(2);
this[ID] = 1;
} else {
mc.gotoAndPlay(1);
this[ID] = 0;
}
}
How about this:
function PDFClick(e:MouseEvent):void {
targetPDF = e.target.ID;
trace("targetPDF " +targetPDF);
if (targetPDF == "PDF1") {
var frame:int = pdf.pconnectionPDF1.currentFrame;
pdf.pconnectionPDF1.gotoAndPlay( frame == 1 ? (PDF1 = 1)+1 : (PDF1 = 0)+1 );
}
}
I think that's about what you are looking for.
I wrote the following method that receives a list and updates the database based on certain criteria:
public void UpdateInventoryGoods(List<InventoryGoods> list, int id)
{
int index = 0;
var query = from inventoryGoods in context.InventoryGoods
where inventoryGoods.ParentId == id
select inventoryGoods;
List<InventoryGoods> goodsList = query.ToList();
using (var scope = new TransactionScope())
{
foreach (InventoryGoods i in list)
{
foreach (InventoryGoods e in goodsList)
{
if (index == 30)
{
index = 0;
context.SubmitChanges();
}
if (e.Gid == i.Gid && !getEventId(e.Id).HasValue && !e.ActionOn.HasValue)
{
e.Action = i.Action;
}
else if ((e.Gid == i.Gid && getEventId(e.Id).HasValue) && (e.Action != i.Action || i.ActionOn == DateTime.MinValue))
{
e.Action = i.Action;
e.ActionOn = null;
var allEvents = from invent in context.InventoryGoodsEvents
where invent.InventoryGood == e.Id
select invent;
List<InventoryGoodsEvents> inventoryGoodsEventsList = allEvents.ToList();
var events = from g in context.GoodsEvent
select g;
List<GoodsEvent> goodsEventList = events.ToList();
foreach (InventoryGoodsEvents goodsEvent in inventoryGoodsEventsList)
{
context.InventoryGoodsEvents.DeleteOnSubmit(goodsEvent);
foreach (GoodsEvent ge in goodsEventList)
{
if (ge.Id == goodsEvent.EventId)
{
ge.IsDeleted = true;
ge.DeletedOn = DateTime.Now;
ge.DeletedBy = System.Web.HttpContext.Current.User.Identity.Name;
}
}
}
}
++index;
}
}
context.SubmitChanges();
scope.Complete();
}
}
public int? getEventId(int InventoryGood)
{
var InventoryGoodsEvents = from i in context.InventoryGoodsEvents
where i.InventoryGood == InventoryGood
select i;
List<InventoryGoodsEvents> lst = InventoryGoodsEvents.ToList();
if (lst.Count() > 0)
{
return lst[0].EventId;
}
else
{
return null;
}
}
Though this method works well for about 500 or 1000 objects, it gets too slow or eventually times out when I feed it over 8000 objects or more.
So, where could I improve its performance a little?
Don't call the database in a loop.
Try moving the queries outside the loops like this:
public void UpdateInventoryGoods(List<InventoryGoods> list, int id)
{
int index = 0;
var query = from inventoryGoods in context.InventoryGoods
where inventoryGoods.ParentId == id
select inventoryGoods;
List<InventoryGoods> goodsList = query.ToList();
using (var scope = new TransactionScope())
{
var allEvents = from invent in context.InventoryGoodsEvents
where goodsList.Contains(invent.InventoryGood)
select invent;
List<InventoryGoodsEvents> inventoryGoodsEventsList = allEvents.ToList();
var events = from g in context.GoodsEvent
select g;
List<GoodsEvent> goodsEventList = events.ToList();
foreach (InventoryGoods i in list)
{
foreach (InventoryGoods e in goodsList)
{
if (index == 30)
{
index = 0;
context.SubmitChanges();
}
var eventId = getEventId(e.Id);
if (e.Gid == i.Gid && !eventId.HasValue && !e.ActionOn.HasValue)
{
e.Action = i.Action;
}
else if ((e.Gid == i.Gid && eventId.HasValue) && (e.Action != i.Action || i.ActionOn == DateTime.MinValue))
{
e.Action = i.Action;
e.ActionOn = null;
foreach (InventoryGoodsEvents goodsEvent in inventoryGoodsEventsList)
{
context.InventoryGoodsEvents.DeleteOnSubmit(goodsEvent);
foreach (GoodsEvent ge in goodsEventList)
{
if (ge.Id == goodsEvent.EventId)
{
ge.IsDeleted = true;
ge.DeletedOn = DateTime.Now;
ge.DeletedBy = System.Web.HttpContext.Current.User.Identity.Name;
}
}
}
}
++index;
}
}
context.SubmitChanges();
scope.Complete();
}
}
I'm no Linq expert, but I think you can probably improve getEventId (should be capital first letter btw) with something like
public int? GetEventId(int inventoryGood)
{
var firstInventoryGoodsEvent = context.InventoryGoodsEvents
.Where(i => i.InventoryGood == inventoryGood)
.FirstOrDefault();
// ...etc
}
The use of FirstOrDefault() means you don't process the whole list if you find a matching element.
There are probably other optimisations but it's quite difficult to follow what you're doing. As an example:
foreach (InventoryGoods i in list)
{
foreach (InventoryGoods e in goodsList)
{
}
}
i and e don't confer much meaning here. It might be obvious to you what they mean but they aren't very descriptive to someone who has never seen your code before. Similarly, list is not the best name for a List. List of what? Your variable name should describe it's purpose.
Edit:
I'm not sure about anything else. You seem to be using ToList() in a few places where as far as I can see it's not necessary. I don't know what effect that would have on performance, but someone cleverer than me could probably tell you.
You could also try hoisting a few of your values outside of loops, eg:
foreach (foo)
{
foreach (bar)
{
DeletedOn = DateTime.Now;
DeletedBy = System.Web.HttpContext.Current.User.Identity.Name;
}
}
can be re-written as
var deletedOn = DateTime.Now;
var deletedBy = System.Web.HttpContext.Current.User.Identity.Name;
foreach (foo)
{
foreach (bar)
{
DeletedOn = deletedOn;
DeletedBy = deletedBy;
}
}
Again, I'm not sure how much difference if any that would make, you'll need to test it and see.
It's not going in batches of 30, it's going in batches of 1.
There's a query with no criteria, so it loads the whole table. Is that your intention?
getEventId(e.Id) returns a consistent value. Don't call it twice (per loop).
how to compare two arraycollection
collectionArray1 = ({first: 'Dave', last: 'Matthews'},...........n values
collectionArray = ({first: 'Dave', last: 'Matthews'},...........n values
how to compare..if equal just alert nochange if not alert chaged
If you just want to know if they are different from each other, meaning by length, order or individual items, you can do the following, which first checks to see if the lengths are different, then checks to see if the individual elements are different. This isn't terribly reusable, it's left as an exercise for the reader to split this apart into cleaner chunks :)
public function foo(coll1:ArrayCollection, coll2:ArrayCollection):void {
if (coll1.length == coll2.length) {
for (var i:int = 0; i < coll1.length; i++) {
if (coll1[i].first != coll2[i].first || coll1[i].last != coll2[i].last) {
Alert.show("Different");
return;
}
}
}
Alert.show("Same");
}
/* elements need to implement valueOf
public function valueOf():Object{}
*/
public static function equalsByValueOf(
first:ArrayCollection,
seconde:ArrayCollection):Boolean{
if((first==null) != (seconde==null) ){
return false;
}else if(!first && !seconde){
return false;
}
if(first.length!=seconde.length){
return false;
}
var commonLength:int = first.length;
var dictionary:Dictionary = new Dictionary();
for(var i:int=0;i<commonLength;i++){
var item1:Object = first.getItemAt(i);
var item2:Object = seconde.getItemAt(i);
dictionary[item1.valueOf()]=i;
dictionary[item2.valueOf()]=i;
}
var count:int = 0;
for (var key:Object in dictionary)
{
count++;
}
return count==commonLength;
}
/* valueOf sample
* something like javaObject.hashCode()
* use non changing fields(recommended)
*/
public function valueOf():Object{
return "_"+nonChangeField1+"_"+nonChangeField2+"...";
}
I was going to say this.
if(collectionArray === collectionArray1)
But that wont work (not triple = signs). As === is used to see classes.
I would write a function called check if object exists in array.
Create an array to hold elements that are not found. eg notFound
in Collection1 go through all the element and see if they exist in Collection2, if an element does not exist, add it to the notFound array. Use the function your created in step1
Now check Collection2, if an element is not found add it to the notFound array.
There is no 5.
Dude, use the mx.utils.ObjectUtil... the creators of actionscript have already thought about this.
ObjectUtil.compare(collection1, collection2) == 0;
This is my grid of nodes:
I'm moving an object around on it using the A* pathfinding algorithm. It generally works OK, but it sometimes acts wrongly:
When moving from 3 to 1, it correctly goes via 2. When going from 1 to 3 however, it goes via 4.
When moving between 3 and 5, it goes via 4 in either direction instead of the shorter way via 6
What can be wrong? Here's my code (AS3):
public static function getPath(from:Point, to:Point, grid:NodeGrid):PointLine {
// get target node
var target:NodeGridNode = grid.getClosestNodeObj(to.x, to.y);
var backtrace:Map = new Map();
var openList:LinkedSet = new LinkedSet();
var closedList:LinkedSet = new LinkedSet();
// begin with first node
openList.add(grid.getClosestNodeObj(from.x, from.y));
// start A*
var curNode:NodeGridNode;
while (openList.size != 0) {
// pick a new current node
if (openList.size == 1) {
curNode = NodeGridNode(openList.first);
}
else {
// find cheapest node in open list
var minScore:Number = Number.MAX_VALUE;
var minNext:NodeGridNode;
openList.iterate(function(next:NodeGridNode, i:int):int {
var score:Number = curNode.distanceTo(next) + next.distanceTo(target);
if (score < minScore) {
minScore = score;
minNext = next;
return LinkedSet.BREAK;
}
return 0;
});
curNode = minNext;
}
// have not reached
if (curNode == target) break;
else {
// move to closed
openList.remove(curNode);
closedList.add(curNode);
// put connected nodes on open list
for each (var adjNode:NodeGridNode in curNode.connects) {
if (!openList.contains(adjNode) && !closedList.contains(adjNode)) {
openList.add(adjNode);
backtrace.put(adjNode, curNode);
}
}
}
}
// make path
var pathPoints:Vector.<Point> = new Vector.<Point>();
pathPoints.push(to);
while(curNode != null) {
pathPoints.unshift(curNode.location);
curNode = backtrace.read(curNode);
}
pathPoints.unshift(from);
return new PointLine(pathPoints);
}
NodeGridNode::distanceTo()
public function distanceTo(o:NodeGridNode):Number {
var dx:Number = location.x - o.location.x;
var dy:Number = location.y - o.location.y;
return Math.sqrt(dx*dx + dy*dy);
}
The problem I see here is the line
if (!openList.contains(adjNode) && !closedList.contains(adjNode))
It may be the case that an adjNode may be easier(shorter) to reach through the current node although it was reached from another node previously which means it is in the openList.
Found the bug:
openList.iterate(function(next:NodeGridNode, i:int):int {
var score:Number = curNode.distanceTo(next) + next.distanceTo(target);
if (score < minScore) {
minScore = score;
minNext = next;
return LinkedSet.BREAK;
}
return 0;
});
The return LinkedSet.BREAK (which acts like a break statement in a regular loop) should not be there. It causes the first node in the open list to be selected always, instead of the cheapest one.