Copy table data from one object to another object AX 2012 - axapta

I'm trying to do a Job which used to Copy and insert Journal Names from one entity to another entity. Below code able to handle only fields only I hardcoded. But I'm trying to do a code which will be useful in future i.e if we add new custom field to the table. My code should able to copy data of that newly custom field added.
static void sa_CopyData(Args _args)
{
LedgerJournalName tblLedgerJournalNameSource, tblLedgerJournalNameDesination;
NumberSequenceTable tblNST, tblNSTCopy;
NumberSequenceScope tblNSS;
Counter countIN, countOUT;
DataAreaId sourceEntity, destinationEntity;
sourceEntity = 'CNUS';
destinationEntity = 'CNEN';
//Journal Names creation
changeCompany(sourceEntity)
{
tblLedgerJournalNameSource = null;
while select * from tblLedgerJournalNameSource
where tblLedgerJournalNameSource.dataAreaId == sourceEntity
{
++countIN;
tblNSTcopy = null; tblNST = null; tblNSS = null;
select * from tblNSTcopy
where tblNSTCopy.RecId == tblLedgerJournalNameSource.NumberSequenceTable;
changeCompany(destinationEntity)
{
tblNST = null; tblNSS = null; tblLedgerJournalNameDesination = null;
select * from tblNST
join tblNSS
where tblNST.NumberSequenceScope == tblNSS.RecId
&& tblNST.NumberSequence == tblNSTCopy.NumberSequence
&& tblNSS.DataArea == destinationEntity;
//Insert only if Journal name is not exists
if(!(LedgerJournalName::find(tblLedgerJournalNameSource.JournalName)))
{
ttsBegin;
tblLedgerJournalNameDesination.initValue();
tblLedgerJournalNameDesination.JournalName = tblLedgerJournalNameSource.JournalName;
tblLedgerJournalNameDesination.Name = tblLedgerJournalNameSource.Name;
tblLedgerJournalNameDesination.JournalType = tblLedgerJournalNameSource.JournalType;
tblLedgerJournalNameDesination.ApproveActive = tblLedgerJournalNameSource.ApproveActive;
tblLedgerJournalNameDesination.ApproveGroupId = tblLedgerJournalNameSource.ApproveGroupId;
tblLedgerJournalNameDesination.NoAutoPost = tblLedgerJournalNameSource.NoAutoPost;
tblLedgerJournalNameDesination.WorkflowApproval = tblLedgerJournalNameSource.WorkflowApproval;
tblLedgerJournalNameDesination.Configuration = tblLedgerJournalNameSource.Configuration;
if (!tblNST.RecId)
{
info(strFmt('Number Sequence is not updated for %1 > Entity %2', tblLedgerJournalNameDesination.JournalName, destinationEntity));
}
tblLedgerJournalNameDesination.NumberSequenceTable = tblNST.recid;
tblLedgerJournalNameDesination.NewVoucher = tblLedgerJournalNameSource.NewVoucher;
tblLedgerJournalNameDesination.BlockUserGroupId = tblLedgerJournalNameSource.BlockUserGroupId;
tblLedgerJournalNameDesination.FixedOffsetAccount = tblLedgerJournalNameSource.FixedOffsetAccount;
tblLedgerJournalNameDesination.OffsetAccountType = tblLedgerJournalNameSource.OffsetAccountType;
tblLedgerJournalNameDesination.OffsetLedgerDimension = tblLedgerJournalNameSource.OffsetLedgerDimension;
tblLedgerJournalNameDesination.LedgerJournalInclTax = tblLedgerJournalNameSource.LedgerJournalInclTax;
tblLedgerJournalNameDesination.insert();
ttsCommit;
++countOUT;
}
}
}
}
info(strFmt('Journal Names Creation > Read: %1, Inserted: %2', countIN, countOUT));
}
Please let me know if you have any suggestions.

Use buf2buf(from, to). https://msdn.microsoft.com/en-us/library/global.buf2buf.aspx
It does not perform an insert, so after you do buf2buf() you can modify any fields you want in the target before doing an insert.
You could do tblLedgerJournalNameDesination.data(tblLedgerJournalNameSource); but that also copies system fields, which you most likely do not want.
You can also look at the source code behind Global::buf2Buf(from, to) and modify that logic if you want.

Related

How to create multi items/records or save item/record array at one time in client script file

I want to create multiple records at the same time using client script. This is what I'm doing:
var ceateDatasource = app.datasources.Reservation.modes.create;
var newItem = ceateDatasource.item;
newItem.User = user; //'eric'
newItem.Description = description; //'000'
newItem.Location_Lab_fk = lab.value.Id; //'T'
newItem.Area_fk = area.value.Id; //'L'
newItem.Equipment_fk = equipment.value.Id; //'S'
for(var i = 0 ; i < 3; i ++) {
newItem.Start_Date = startDate;
newItem.Start_Hours = '03';
newItem.Start_Minutes = '00';
newItem.End_Date = startDate;
newItem.End_Hours = '23';
newItem.End_Minutes = '30';
// Create the new item
ceateDatasource.createItem();
}
But the result I'm getting is this one:
The three records are created but the only the first one has data. The other two records have empty values on their fields. How can I achieve this?
Thanks.
Update(2019-3-27):
I was able to make it work by putting everything inside the for loop block. However, I have another question.
Is there any method like the below sample code?
var recordData = [Data1, Data2, Data3]
var ceateDatasource;
var newItem = new Array(recordData.length) ;
for(var i = 0 ; i < recordData.length; i ++) {
ceateDatasource = app.datasources.Reservation.modes.create;
newItem[i] = ceateDatasource.item;
newItem[i].User = recordData[i].user;
newItem[i].Description = recordData[i].Description;
newItem[i].Location_Lab_fk = recordData[i].Location_Lab_fk;
newItem[i].Area_fk = recordData[i].Area_fk;
newItem[i].Equipment_fk = recordData[i].Equipment_fk;
newItem[i].Start_Date = recordData[i].Start_Date;
newItem[i].Start_Hours = recordData[i].Start_Hours;
newItem[i].Start_Minutes = recordData[i].Start_Minutes;
newItem[i].End_Date = recordData[i].End_Date;
newItem[i].End_Hours = recordData[i].End_Hours;
newItem[i].End_Minutes = recordData[i].End_Minutes;
}
// Create the new item
ceateDatasource.createItem();
First, it prepares an array 'newItem' and only calls 'ceateDatasource.createItem()' one time to save all new records(or items).
I try to use this method, but it only saves the last record 'newItem[3]'.
I need to write a callback function in 'ceateDatasource.createItem()' but Google App Maker always show a warning "Don't make functions within a loop". So, are there any methods to call 'createItem()' one time to save several records? Or are there some functions like 'array.push' which can be used?
Thanks.
As per AppMaker's official documentation:
A create datasource is a datasource used to create items in a particular data source. Its item property is always populated by a draft item which can be bound to or set programmatically.
What you are trying to do is create three items off the same draft item. That why you see the result you get. If you want to create multiple items, you need to create a draft item for each one, hence all you need to do is put all your code inside the for loop.
for(var i = 0 ; i < 3; i ++) {
var ceateDatasource = app.datasources.Reservation.modes.create;
var newItem = ceateDatasource.item;
newItem.User = user; //'eric'
newItem.Description = description; //'000'
newItem.Location_Lab_fk = lab.value.Id; //'T'
newItem.Area_fk = area.value.Id; //'L'
newItem.Equipment_fk = equipment.value.Id; //'S'
newItem.Start_Date = startDate;
newItem.Start_Hours = '03';
newItem.Start_Minutes = '00';
newItem.End_Date = startDate;
newItem.End_Hours = '23';
newItem.End_Minutes = '30';
// Create the new item
ceateDatasource.createItem();
}
If you want to save several records at the same time using client script, then what you are looking for is the Manual Save Mode. So all you have to do is go to your model's datasource and click on the checkbox "Manual Save Mode".
Then use the same code as above. The only difference is that in order to persist the changes to the server, you need to explicitly save changes. So all you have to do is add the following after the for loop block:
app.datasources.Reservation.saveChanges(function(){
//TODO: Callback handler
});

Initial sync and duplicate objects with same primary key inside Realm Mobile Platform

I'm trying to turn on realm sync on device which already contains some data, that already persists on server. When new user connects to realm, it should merge local realm data with synced realm data. But this code is launched before initial sync happens. Since there is no data from server is received yet, app creates some records in synchronized realm. When sync finishes I see same data twice. Records I've just created and data fetched from server. With same primary key.
See code below for an example:
RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
config.syncConfiguration = [[RLMSyncConfiguration alloc] initWithUser:user realmURL:self.realmURL];
NSError *error = nil;
RLMRealm *newRealm = [RLMRealm realmWithConfiguration:config error:&error];
if(newRealm != nil && error == nil)
{
[newRealm beginWriteTransaction];
for(ModelFolder *folder in [ModelFolder allObjectsInRealm:curRealm])
{
ModelFolder *newFolder = [ModelFolder objectInRealm:newRealm forPrimaryKey:folder.uuid];
if(newFolder == nil)
[ModelFolder createInRealm:newRealm withValue:folder];
}
[newRealm commitWriteTransaction];
}
Is there a way to detect, that realm is completed initial sync?
UPD: Few more details.
ModelFolder contains #property RLMArray<ModelBookmark *><ModelBookmark> *bookmarks; And when I create Folder, that equals some folder that will be fetched in a few seconds they merged correctly. But. Bookmarks inside Folder object is not deduplicated and we get something like this:
RLMResults <0x802082d0> (
[0] ModelFolder {
uuid = 2615AB34-1C08-4E7B-8D49-6E02EDBCDF89;
name = (null);
descr = (null);
shareURL = (null);
date = 1484566331137;
bookmarks = RLMArray <0x806c78d0> (
[0] ModelBookmark {
uuid = C752FCEB-65CB-47C8-8CF4-6CA44C119ECC;
name = (null);
descr = (null);
shareURL = (null);
date = 1484566331137;
folderUuid = 2615AB34-1C08-4E7B-8D49-6E02EDBCDF89;
longitude = 27.54834598813616;
latitude = 53.91333128839566;
mapZoom = 11.73785983313041;
category = 0;
visible = 1;
},
[1] ModelBookmark {
uuid = C752FCEB-65CB-47C8-8CF4-6CA44C119ECC;
name = (null);
descr = (null);
shareURL = (null);
date = 1484566331137;
folderUuid = 2615AB34-1C08-4E7B-8D49-6E02EDBCDF89;
longitude = 27.54834598813616;
latitude = 53.91333128839566;
mapZoom = 11.73785983313041;
category = 0;
visible = 1;
}
);
tracks = RLMArray <0x806fb120> (
);
opened = 1;
}
)
Unfortunately merging of the ordered lists is not supported currently (until https://github.com/realm/realm-core/issues/1206 is implemented). For now you have to manually deduplicate list items, you can use the same workaround we use in RealmTasks app, see https://github.com/realm/RealmTasks/pull/180 for implementation details.

Writing to General Journal, Financial Dimensions not working

I'm writing to the general journal in x++. I am able to post there currently but the dimensions on the line item are not showing up. The code runs just will have 701100- - - - - and the rest not populated on the line item. i'm not sure why... I've tried several different things... such as below.
ledgerDimensions = ["701100","701100", "MIDWHS", "ACCT", "000001", "AIR", "019-000100"];
journalTrans.parmLedgerDimension(AxdDimensionUtil::getLedgerAccountId(ledgerDimensions));
offsetDimensions = ["701100","701100", "MIDWHS", "ACCT", "000001", "AIR", "019-000100"];
journalTrans.parmOffsetLedgerDimension(AxdDimensionUtil::getLedgerAccountId(offsetDimensions));
journaltrans.save()
and also have tried
// dimensionAttribute = DimensionAttribute::findByName("Location");
// dimensionAttributeValue = //DimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute, "MINOT");
// dimStorage = DimensionAttributeValueSetStorage::find(0);
// dimStorage.addItem(dimensionAttributeValue);
// journalTrans.parmOffsetDefaultDimension(dimStorage.save());
//journalTrans.save()
both are just adding the account number and nothing else.. don't know why!
I used the service for our import interface for general journal.
Below my code, try it this way, it's easy to create the dimensions with this service.
I copied the code from our system and commented it, if you need any further explaination, ask me.
Declarations:
LedgerGeneralJournal ledgerGeneralJournal;
LedgerGeneralJournalService ledgerGeneralJournalService;
AfStronglyTypedDataContainerList journalHeaderCollection;
LedgerGeneralJournal_LedgerJournalTable journalHeader;
AfStronglyTypedDataContainerList journalLineCollection;
AifEntityKeyList journalHeaderCollectionKeyList;
int journalLineCounter; // to create more than one line
int entityKeyCount;
int journalHeaderCounter; // to create more than one journal header if needed
Add parm methods for your counter variables if needed:
public int parmJournalLineCounter(int _journalLineCounter = journalLineCounter)
{
journalLineCounter = _journalLineCounter;
return journalLineCounter;
}
public int parmJournalHeaderCounter(int _journalHeaderCounter = journalHeaderCounter)
{
journalHeaderCounter = _journalHeaderCounter;
return journalHeaderCounter;
}
initializations:
Header
ledgerGeneralJournalService = LedgerGeneralJournalService::construct();
ledgerGeneralJournal = new LedgerGeneralJournal();
journalHeaderCollection = ledgerGeneralJournal.createLedgerJournalTable();
this.parmJournalLineCounter(0); // note to add a parm method for your counter variables
this.parmJournalHeaderCounter(_newInstance ? 1 : this.parmJournalHeaderCounter() + 1); // i added a parameter if more headers are needed
journalHeader = journalHeaderCollection.insertNew(this.parmJournalHeaderCounter());
journalHeader.parmJournalName(contract.parmJournalNameId()); // init your own journal ID
Here my method to create the lines with dimensions.
Note that i only use CostCenter here, if you need more, add them as done with CostCenter (i commented the lines)
protected void writeLine(
str _oldCompany,
TransDate _transDate,
Voucher _voucher,
str _mainAccountNum,
AmountMST _amount,
LedgerJournalTransTxt _transTxt,
CurrencyCode _currencyCode,
str _offsetAccountNum,
str costCenter
)
{
LedgerGeneralJournal_LedgerJournalTrans journalLine;
AifMultiTypeAccount journalLineLedgerDimensionMain;
AifDimensionAttributeValue journalLineDim1Main;
AfStronglyTypedDataContainerList journalLineDimensionCollectionMain;
AifMultiTypeAccount journalLineLedgerDimensionOffset;
str lineMainAccount;
str lineFullAccount;
str lineMainDimensionName = 'CostCenter';
str lineMainDimensionValue;
str lineOffsetAccount;
str lineOffsetFullAccount;
this.parmJournalLineCounter(this.parmJournalLineCounter()+1);
journalLine = this.parmJournalLineCollection().insertNew(this.parmJournalLineCounter());
journalLine.parmLineNum(this.parmJournalLineCounter());
journalLine.parmCompany(CompanyInfo::findByPTROldCompany(_oldCompany).company());
journalLine.parmOffsetCompany(journalLine.parmCompany());
journalLine.parmTransDate(_transDate);
journalLine.parmVoucher(_voucher);
journalLine.parmAccountType(LedgerJournalACType::Ledger);
lineMainAccount = _mainAccountNum;
journalLine.parmAmountCurCredit(_amount > 0 ? 0 : _amount);
journalLine.parmAmountCurDebit(_amount > 0 ? _amount : 0);
journalLine.parmTxt(_transTxt);
journalLine.parmCurrencyCode(_currencyCode);
journalLine.parmOffsetAccountType(LedgerJournalACType::Ledger);
lineOffsetAccount = _offsetAccountNum;
// Create Main Account Dimensions
journalLineLedgerDimensionMain = journalLine.createLedgerDimension();
journalLineLedgerDimensionMain.parmAccount(lineMainAccount);
lineFullAccount = strFmt("%1-%2-", lineMainAccount, costCenter ? lineMainDimensionValue : ''); // if you need more dimensions, add them here first
journalLineLedgerDimensionMain.parmDisplayValue(lineFullAccount);
// and then add the values here like costcenter:
if (costCenter)
{
lineMainDimensionValue = costCenter;
journalLineDimensionCollectionMain = journalLineLedgerDimensionMain.createValues();
journalLineDim1Main = new AifDimensionAttributeValue();
journalLineDim1Main.parmName(lineMainDimensionName);
journalLineDim1Main.parmValue(lineMainDimensionValue);
journalLineDimensionCollectionMain.add(journalLineDim1Main);
journalLineLedgerDimensionMain.parmValues(journalLineDimensionCollectionMain);
}
journalLine.parmLedgerDimension(journalLineLedgerDimensionMain);
// Create Offset Account Dimensions
// same procedure with offset dimensions if needed
if (_offsetAccountNum)
{
journalLineLedgerDimensionOffset = journalLine.createOffsetLedgerDimension();
journalLineLedgerDimensionOffset.parmAccount(lineOffsetAccount);
lineOffsetFullAccount = strFmt("%1--", lineOffsetAccount);
journalLineLedgerDimensionOffset.parmDisplayValue(lineOffsetFullAccount);
journalLine.parmOffsetLedgerDimension(journalLineLedgerDimensionOffset);
}
}
// Create Lines
journalLineCollection = journalHeader.createLedgerJournalTrans();
Finally to write the journal:
public void finalizeLedgerJournal()
{
int keyCount;
List journalIdList;
journalHeader.parmLedgerJournalTrans(journalLineCollection);
ledgerGeneralJournal.parmLedgerJournalTable(journalHeaderCollection);
journalHeaderCollectionKeyList = LedgerGeneralJournalService.create(ledgerGeneralJournal);
// if you need the journalId for further processing:
this.parmEntityKeyCount(journalHeaderCollectionKeyList.getEntityKeyCount());
if (entityKeyCount > 0)
{
for (keyCount = 1;keyCount <= entityKeyCount;keyCount++)
{
if (!contract.parmJournalIdList())
{
contract.parmJournalIdList(new List(Types::String));
}
journalIdList = contract.parmJournalIdList();
journalIdList.addEnd(LedgerJournalTable::findByRecId(journalHeaderCollectionKeyList.getEntityKey(keyCount).parmRecId()).JournalNum);
contract.parmJournalId(LedgerJournalTable::findByRecId(journalHeaderCollectionKeyList.getEntityKey(keyCount).parmRecId()).JournalNum);
}
}
}

PHPexcel - getOldCalculatedValue and rangeToArray

Searched for quite a while now, but I'm stuck at the following problem.
I am using PHPexcel 1.8.0
The spreadsheet is read using the following code:
$rowData = $sheet->rangeToArray('A' . $row . ':' . $highestColumn . $row, NULL, TRUE, TRUE);
So far ok and it works well.
But some spreadsheets contain external referenced data.
And for that I want to use "getOldCalculatedValue".
How do I combine "getOldCalculatedValue" with "rangeToArray" ?
Or is "rangeToArray" inappropriate for this ?
Thanks for any help or hints !
Simple answer, you can't combine the two
rangeToArray() is a simple method for a simple purpose, it doesn't try to do anything clever, simply to return the data from the worksheet as efficiently and quickly as possible
getOldCalculatedValue() is used for a very specific circumstance, and isn't guaranteed to be correct even then, because it retrieves the last value calculated for the cell in MS EXcel itself, which ,ay not be correct if the external workbook wasn't available to MS Excel in that circumstance, or MS Excel formula evaluation was disable.
When calculating cells values from a formula, the PHPExcel calculation engine should use the getOldCalculatedValue() as a fallback if it finds an external reference, and rangeToArray() will try to use this method, but it isn't perfect, especially when that reference in nested deep inside other formulae referenced in other cells.
If you know that a formula in a cell contains an external reference, you should use getOldCalculatedValue() directly for that cell
I came up with the following solution.
Maybe not perfect, but it currently does the job. Thanks for any improvements!
With PHPExcel included and the excel file uploaded and ready, I continue with:
$sheet = $objPHPExcel->getSheet(0);
$highestRow = $sheet->getHighestRow();
Create a new array to store the cell values of a row
$arr_row = array();
Loop through the rows
for ($rownumber = 2; $rownumber <= $highestRow; $rownumber++){
$row = $sheet->getRowIterator($rownumber)->current();
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
Then loop through the cells of the current row
foreach ($cellIterator as $cell) {
Find cells with a formula
$cellcheck = substr($cell->getValue(),0,1);
if($cellcheck == '='){
$cell_content = $cell->getOldCalculatedValue();
}
else{
$cell_content = $cell->getValue();
}
Add the cell values to the array
array_push($arr_row,$cell_content);
Close cell loop
}
At this point I use the $arr_row to do further calculations and string formatting, before finally inserting it into a mysql table.
Close row loop
}
I made some changes in the function rangeToArray() inside Worksheet.php.
Worked fine!
public function rangeToArray($pRange = 'A1', $nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) {
// Returnvalue
$returnValue = array();
// Identify the range that we need to extract from the worksheet
list($rangeStart, $rangeEnd) = PHPExcel_Cell::rangeBoundaries($pRange);
$minCol = PHPExcel_Cell::stringFromColumnIndex($rangeStart[0] -1);
$minRow = $rangeStart[1];
$maxCol = PHPExcel_Cell::stringFromColumnIndex($rangeEnd[0] -1);
$maxRow = $rangeEnd[1];
$maxCol++;
// Loop through rows
$r = -1;
for ($row = $minRow; $row <= $maxRow; ++$row) {
$rRef = ($returnCellRef) ? $row : ++$r;
$c = -1;
// Loop through columns in the current row
for ($col = $minCol; $col != $maxCol; ++$col) {
$cRef = ($returnCellRef) ? $col : ++$c;
// Using getCell() will create a new cell if it doesn't already exist. We don't want that to happen
// so we test and retrieve directly against _cellCollection
if ($this->_cellCollection->isDataSet($col.$row)) {
// Cell exists
$cell = $this->_cellCollection->getCacheData($col.$row);
if ($cell->getValue() !== null) {
if ($cell->getValue() instanceof PHPExcel_RichText) {
$returnValue[$rRef][$cRef] = $cell->getValue()->getPlainText();
} else {
if ($calculateFormulas)
{ ##################################### CHANGED LINES
if(!preg_match('/^[=].*/', $cell->getValue()))
{
$returnValue[$rRef][$cRef] = $cell->getCalculatedValue(); # THE ORIGINAL CODE ONLY HAD THIS LINE
}
else
{
$returnValue[$rRef][$cRef] = $cell->getOldCalculatedValue();
}
} ##################################### CHANGED LINES
else
{
$returnValue[$rRef][$cRef] = $cell->getValue();
}
}
if ($formatData) {
$style = $this->_parent->getCellXfByIndex($cell->getXfIndex());
$returnValue[$rRef][$cRef] = PHPExcel_Style_NumberFormat::toFormattedString(
$returnValue[$rRef][$cRef],
($style && $style->getNumberFormat()) ?
$style->getNumberFormat()->getFormatCode() :
PHPExcel_Style_NumberFormat::FORMAT_GENERAL
);
}
} else {
// Cell holds a NULL
$returnValue[$rRef][$cRef] = $nullValue;
}
} else {
// Cell doesn't exist
$returnValue[$rRef][$cRef] = $nullValue;
}
}
}
// Return
return $returnValue;
}

. The An object with the same key already exists in the ObjectStateManagerObjectStateManager cannot track multiple objects with the same key

I am trying to simply update the entity object and I get this error.. All the googling on the error I did takes me to complex explanations... can anyone put it simply?
I am working of of this simple tutorial
http://aspalliance.com/1919_ASPNET_40_and_the_Entity_Framework_4__Part_2_Perform_CRUD_Operations_Using_the_Entity_Framework_4.5
else
{
//UPDATE
int iFid = Int32.Parse(fid.First().fid.ToString());
oFinancial.fid = iFid;
oFinancial.mainqtr = currentQuarter;
oFinancial.mainyear = currentYear;
oFinancial.qtr = Int32.Parse(currentQuarter);
oFinancial.year = Int32.Parse(currentYear);
oFinancial.updatedate = DateTime.Now;
// ObjectStateEntry ose = null;
// if (!dc.ObjectStateManager.TryGetObjectStateEntry(oFinancial.EntityKey, out ose))
// {
dc.financials.Attach(oFinancial);
// }
dc.ObjectStateManager.ChangeObjectState(oFinancial, System.Data.EntityState.Modified);
}
dc.SaveChanges();
here is what is higher up in the code that I use simple to get me the primary key value.. probably a better way but it works.
var fid = from x in dc.financials
where iPhaseID == x.phaseid &&
strTaskID == x.ftaskid &&
strFundType == x.fundtype &&
iCurrentQuarter == x.qtr &&
iCurrentYear == x.year
select x;
If the oFinancial object came from your dc and you never manually detached it, then there is no reason to call the Attach method or to mess with the ObjectStateManager. As long as the dc knows about the object (which it does unless you detach it), then the ObjectStateManager will keep track of any changes you make and update them accordingly when you call dc.SaveChanges().
EDIT: Here's a refactored version of what you posted, hope it helps:
else {
//UPDATE
// as long as oFinancial was never detatched after you retrieved
// it from the "dc", then you don't have to re-attach it. And
// you should never need to manipulate the primary key, unless it's
// not generated by the database, and you don't already have another
// object in the "dc" with the same primary key value.
int iFid = Int32.Parse(fid.First().fid.ToString());
oFinancial.fid = iFid;
oFinancial.mainqtr = currentQuarter;
oFinancial.mainyear = currentYear;
oFinancial.qtr = Int32.Parse(currentQuarter
oFinancial.year = Int32.Parse(currentYear);
oFinancial.updatedate = DateTime.Now;
}
dc.SaveChanges();
One other thing: if iFid is the primary key, then you shouldn't mess with it as long as this object came from the dc. I believe the problem is that you're resetting the primary key (iFid) to the same value of another object within the dc, and EF4 is barking because you can't have two rows with the same primary key value in a table.

Resources