Need help in updating records using LinQ.
I tried updating the record, but it does not display in the database.
The primary key is set in both db and LinQ dbml file.
Below are the codes:
RPHContrib _phContrib = new RPHContrib();
_phContrib.PHTableNo = phContrib.PHTableNo;
_phContrib.AmountFrom = phContrib.AmountFrom;
_phContrib.AmountTo = phContrib.AmountTo;
_phContrib.EmployeePH = phContrib.EmployeePH;
_phContrib.EmployerAmt = phContrib.EmployerAmt;
_phContrib.IsActive = phContrib.IsActive;
_phContrib.CreatedByNo = phContrib.CreatedByNo;
_phContrib.CreatedDate = phContrib.CreatedDate;
_phContrib.ModifiedByNo = SessionStateController.OnlineUserNo;
_phContrib.ModifiedDate = DateTime.Now;
LINQHelper.Instance.GenericDataContext<HRWizardDataContext>(GetDataContext(false));
LINQHelper.Instance.Update<RPHContrib>(_phContrib);
public bool Update<T>(T obj) where T : class, ICommon, new()
{
using (var db = GetDBDataContext())
{
db.Connection.Open();
DbTransaction trans = db.Connection.BeginTransaction();
db.Transaction = trans;
// Populate object log
obj.IModifiedDate = DateTime.Now;
try
{
Detach<T>(obj); // Detach LINQ entity from the original DataContext before attaching to the new one
db.GetTable<T>().Attach(obj, true);
db.SubmitChanges();
db.Transaction.Commit();
}
catch (Exception ex)
{
db.Transaction.Rollback();
// TODO: Put error logging code here
throw ex;
}
finally
{
if (db.Connection != null)
{
db.Connection.Close();
db.Connection.Dispose();
}
}
}
return true;
}
When you are adding a new recored use InsertOnSubmit(Entity), afterwhich any Auto Numbers (eg. primary) will be updated on your object automatically after you call SubmitChanges().
Use Attach(Entity) when you are updating an entity. Make changes to the entity after you have attached it. Making changes before you attach it to the Context will not trigger the Update SQL as the context will think there is nothing to update.
You need to do insertonsubmit(obj); before submitchanges();
Related
I am having difficulties UPDATING the databes via LINQ to SQL, inserting a new record works fine.
The code correctly inserts a new row and adds a primary key, the issue I am having is when I go to update (chnage a value that is already in the database) that same row the database is not updating, it is the else part of the code that does not work correctly. This is strange b/c the DB is properly connected and functioning through the fact that the DataContext inserts a new row with no issues. Checking the database confirms this.
This is the code,
using System;
using System.Collections.Generic;
using System.Linq;
using Cost = Invoices.Tenant_Cost_TBL;
namespace Invoices
{
class CollectionGridEvents
{
static string conn = Settings.Default.Invoice_DbConnectionString;
public static void CostDataGridCellEditing(DataGridRowEditEndingEventArgs e)
{
using (DatabaseDataContext DataContext = new DatabaseDataContext(conn))
{
var sDselectedRow = e.Row.Item as Cost;
if (sDselectedRow == null) return;
if (sDselectedRow.ID == 0)
{
sDselectedRow.ID = DateTime.UtcNow.Ticks;
DataContext.Tenant_Cost_TBLs.InsertOnSubmit(sDselectedRow);
}
else
{
// these two lines are just for debuging
long lineToUpdateID = 636154619329526649; // this is the line to be updated primary key
long id = sDselectedRow.ID; // this is to check the primary key on selected line is same
// these 3 lines are to ensure I am entering actual data into the DB
int? amount = sDselectedRow.Cost_Amount;
string name = sDselectedRow.Cost_Name;
int? quantity = sDselectedRow.Cost_Quantity;
sDselectedRow.Cost_Amount = amount;
sDselectedRow.Cost_Name = name;
sDselectedRow.Cost_Quantity = quantity;
}
try
{
DataContext.SubmitChanges();
}
catch (Exception ex)
{
Alert.Error("Did not save", "Error", ex);
}
}
}
}
}
And I am calling the method from this,
private void CostDataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
CollectionGridEvents.CostDataGridCellEditing(e);
}
The lineToUpdateID is copied dirrectly from the database and is just there to check against the currently selected rows primary key is the same, so I know I am trying to update the same row.
I have looked through as many of the same type of issues here on SO , such as this one Linq-to-Sql SubmitChanges not updating fields … why?. But still no closer to finding out what is going wrong.
Any ideas would be much appreciated.
EDIT: Cost is just short hand of this using Cost = Invoices.Tenant_Cost_TBL;
You cannot do that. You need to get the record out of the database and then update that record. Then save it back. Like this:
else
{
// first get it
var query =
from ord in DataContext.Tenant_Cost_TBLs
where ord.lineToUpdateID = 636154619329526649
select ord;
// then update it
// Most likely you will have one record here
foreach (Tenant_Cost_TBLs ord in query)
{
ord.Cost_Amount = sDselectedRow.Cost_Amount;
// ... and the rest
// Insert any additional changes to column values.
}
}
try
{
DataContext.SubmitChanges();
}
catch (Exception ex)
{
Alert.Error("Did not save", "Error", ex);
}
Here is an example you can follow.
Or you can use a direct query if you do not want to select first.
DataContext.ExecuteCommand("update Tenant_Cost_TBLs set Cost_Amount =0 where ...", null);
Your object (Cost) is not attached to DB context. You should attach it then save changes. Check solution here
When I update my member, I want to update his BankCheck too.
This is my database:
My bankCheck can be added, updated or deleted.
My member can be updated only (name, surname...)
I choose my member in my datagrid, and select Edit, my wpf app switch to an other page and display my member with Textbox etc.
I click on my button to add/edit/delete his bankCheck and I can edit the first bankCheck.
I delete the last bankCheck and I add an other (for example).
I press OK and I click on "Valid my Edit".
My program re-creates a new Member with his bankCheck and i made this:
private void EditMember(Member updatedMember)
{
try
{
using (var context = new KravMagaEntities())
{
context.Member.Attach(updatedMember);
context.Entry(updatedMember).State = EntityState.Modified;
context.SaveChanges();
}
ResetAllControls();
States.EnumToText(States.StatesEnum.UpdatingSuccess);
Application.Current.Dispatcher.Invoke(() =>
{
_managementService.IsVisibleAddTab(true);
_managementService.IsVisibleEditTab(false);
});
}
catch (Exception exception)
{
States.EnumToText(States.StatesEnum.Error, exception);
}
}
But I have this error:
A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.
I don't know how I can fix this error.
Thank you.
My code:
private void OnEditMemberBtnClicked(object sender, RoutedEventArgs e)
{
try
{
var isValidateCertificat = IsValidDate(BirthDateTxt);
var isValidateBirth = IsValidDate(CertificateDateTxt);
var isValidateAutorisation = IsValidDate(AutorizationDateTxt);
var isValidateReglement = IsValidDate(RuleDateTxt);
if (isValidateBirth && isValidateCertificat && isValidateAutorisation && isValidateReglement)
{
States.EnumToText(States.StatesEnum.Updating);
var typePaiement = BankCheckRadio.IsChecked.Value;
var typePaiementText = typePaiement ? "Chèque" : "Espèce";
var doctor = "";
var dateCertificate = "";
if (BankCheckRadio.IsChecked.Value)
{
doctor = DoctorTxt.Text;
dateCertificate = CertificateDateTxt.Text;
}
var editedMember = new Member
{
id_Member = _idForEdit,
name_Member = UppercaseChar(NameTxt.Text),
surname_Member = UppercaseChar(SurnameTxt.Text),
birthDate_Member = BirthDateTxt.Text,
autorizationDate_Member = AutorizationDateTxt.Text,
address_Member = UppercaseChar(AddressTxt.Text),
postalCode_Member = PostalCodeTxt.Text,
country_Member = UppercaseChar(CountryTxt.Text),
fixPhone_Member = FixPhoneTxt.Text,
mobilePhone_Member = MobilePhoneTxt.Text,
mail_Member = MailTxt.Text,
beginDate_Member = BeginDateCombo.Text,
ruleDate_Member = RuleDateTxt.Text,
subscription_Member = SubscriptionCombo.Text,
typePaiement_Member = typePaiement,
typePaiementText_Member = typePaiementText,
federationNumero_Member = FederationNumeroTxt.Text.ToUpper(),
level_Member = LevelCombo.Text,
certificate_Member = CertificateCheckbox.IsChecked.Value,
doctor_Member = UppercaseChar(doctor),
certificateDate_Member = dateCertificate,
problem_Member = UppercaseChar(ProblemTxt.Text, true),
emergencyName_Member = UppercaseChar(EmergencyNameTxt.Text),
emergencyPhone_Member = EmergencyPhoneTxt.Text,
BankCheck = _bankChecks
};
if (_bankChecks != null)
{
using (var context = new KravMagaEntities())
{
foreach (var bankCheck in _bankChecks)
{
bankCheck.idMember_BankCheck = editedMember.id_Member;
context.Entry(bankCheck).State = EntityState.Added;
}
context.SaveChanges();
}
}
new Task(() => EditMember(editedMember)).Start();
}
}
catch (Exception exception)
{
States.EnumToText(States.StatesEnum.Error, exception);
}
}
So as I see, you're updating only Member, not all the modified BankAccounts. You're updating navigation property of entities from both sides but calling SaveChanges() only on entity from one side. So your Member starts to refer another BankAccount while your BankAccounts still refer to the old Member. You need to mark all appropriate BankAccounts as modified along with your modified Member in the same place and then call SaveChanges() so everything will be saved (from comment).
To prevent adding a duplicate you can try to set the state of your entities to the State.Modified instead of State.Added.
The reason of that problem was that you were updating only entity from one side. If you have BankAccounts-Members relationship then in case you update the navtigation property for Member you should update a navigation property for BankAccount too and vice versa. If you just update some property (Member.Name or anything) you just set this Member's State to State.Modified without affecting any of other Member's, BankAccount's etc.
If the entity tracking is turned on for you then EF will automatically track entities that were modified and set appropriate states for them. But as I've seen from your issue, it's turned off for you so you have to manually set the state for each object you want to add/update/delete.
I am going to get mad. I have a so simple code but it doesn't work.
I have tested every thing and I can't understand the reason.
The code is like this:
FataDBEntities model = new FataDBEntities();
UserAccount nua = new UserAccount();
nua.username = username;
nua.pass = password;
nua.email = mailaddress;
nua.activated = false;
model.UserAccounts.Add(nua);
try
{
model.SaveChanges();
}
catch (Exception)
{
throw;
}
string activationCode;
try
{
activationCode = genActivationCodeAndMail(mailaddress, username);
}
catch (Exception)
{
throw;
}
ActivationCode ac = new ActivationCode();
ac.code = activationCode;
ac.expiration_date = DateTime.Now.AddDays(1);
nua = model.UserAccounts.Single(p => p.username == username);
ac.wichUser = nua.ID;
model.ActivationCodes.Add(ac);
try
{
model.SaveChanges();
}
catch (Exception)
{
throw;
}
and the model is like this :
The error is with second insertion ... the first one works fine.
Additional information: Unable to update the EntitySet 'ActivationCode' because it has a DefiningQuery and no element exists in the element to support the current operation.
Please help...
According to this SO article, this error can occur if the entity set is mapped from the database view, custom database query or if database table does not have primary key.
This has happened to me before, and I used that same article to fix the issue :)
I have a project that inserts personal information to a table and details into another table. But sometimes personal information cannot be recorded, however details are recorded. As below code part, firstly personal information are inserted, then details. But sometimes personal information doesn't get saved and userId returns 0, So details are saved. I don't know why it doesn't work. Any idea?
public int ConferenceIdyeGoreKisiBilgileriniKaydet(string orderId)
{
KisiselBilgilerBal kisiBilgileri = (KisiselBilgilerBal)Session["kisiselBilgilerSession"];
registrationCode = GenerateGeristrationCode();
string toplamMaliyet = Session["toplamOdeme"].ToString();
PersonalInformation.SavePersonalInformations(kisiBilgileri, registrationCode,conferenceName);
int userId = AuthorPaperDetaylari.AdVeSoyadaGoreIdGetir(kisiBilgileri.f_name, kisiBilgileri.l_name);
AuthorPaperDetaylari.SaveAuthorPaperDetails(authorPaperDetay, userId); // save details via userId.
return userId;
}
This method saves personal information.
public static void SavePersonalInformations(KisiselBilgilerBal kisiBilgileri,string registrationCode,string conferenceName)
{
try
{
string cs = ConfigurationManager.AppSettings["SiteSqlServer"];
DBDataContext db = new DBDataContext(cs);
DBpersonalInformation personalInfo = new DBpersonalInformation();
personalInfo.f_name = kisiBilgileri.f_name;
personalInfo.l_name = kisiBilgileri.l_name;
personalInfo.university_affiliation = kisiBilgileri.university_affiliation;
personalInfo.department_name = kisiBilgileri.department_name;
personalInfo.address1 = kisiBilgileri.address1;
personalInfo.address2 = kisiBilgileri.address2;
personalInfo.city = kisiBilgileri.city;
personalInfo.state = kisiBilgileri.state;
personalInfo.zipCode = kisiBilgileri.zipCode;
personalInfo.country = kisiBilgileri.country;
personalInfo.phone = kisiBilgileri.phone;
personalInfo.email = kisiBilgileri.email;
personalInfo.orderId = kisiBilgileri.orderId;
personalInfo.registrationCode = registrationCode;
personalInfo.date = DateTime.Now;
personalInfo.conferenceName = conferenceName;
db.DBpersonalInformations.InsertOnSubmit(personalInfo);
db.SubmitChanges();
}
catch (Exception)
{
}
}
This method saves details
public static void SaveAuthorPaperDetails(AuthorPaperDetailsBal authorPaperDetay, int userId)
{
try
{
string cs = ConfigurationManager.AppSettings["SiteSqlServer"];
DBWebDataContext db = new DBWebDataContext(cs);
DBAuthorPaperDetail authorPaperDetail = new DBAuthorPaperDetail();
authorPaperDetail.paper_title = authorPaperDetay.paperTitleDetails;
authorPaperDetail.conference_maker_id = authorPaperDetay.confMakerId;
authorPaperDetail.additional_paper_title = authorPaperDetay.additionalPprTtle;
authorPaperDetail.areYouMainAuthor = authorPaperDetay.mainAuthor;
authorPaperDetail.feeForFirstAuthorPaper = authorPaperDetay.registerFeeForFirstAuthor;
authorPaperDetail.feeForAdditionalPaper = authorPaperDetay.regFeeForAdditionalPape;
authorPaperDetail.feeForParticipCoAuthors = authorPaperDetay.regFeeForCoAuthors;
authorPaperDetail.userId = userId;
authorPaperDetail.firstCoAuthorName = authorPaperDetay.firstCoAuthor;
authorPaperDetail.secondCoAuthorName = authorPaperDetay.secondCoAutho;
authorPaperDetail.thirdCoAuthorName = authorPaperDetay.thirdCoAuthor;
authorPaperDetail.toplamOdeme = authorPaperDetay.toplamMaliyet;
db.DBAuthorPaperDetails.InsertOnSubmit(authorPaperDetail);
db.SubmitChanges();
}
catch (Exception)
{
}
}
I don't know why it doesnt work. Any idea?
...
catch (Exception)
{
}
Well, that explains pretty much everything... don't do this. Ever. The database layer is trying to tell you what the problem is, and you are sticking your fingers in your ears, hoping that'll make it go away. If I had to guess: maybe an occasional timeout due to being blocked by another SPID.
If you can't do anything useful or appropriate with an exception, just let it bubble to the caller. If it gets to the UI, tell the user about it (or just log the issue internally and tell the user "There was a problem").
Also, a LINQ-to-SQL data-context is IDisposable; you should have using statement around db.
In addition to Marc's answer... You are calling SubmitChanges twice. If you want atomic data storage, you should call it once. You can use relational properties to create an object graph, and submit the whole graph at once.
public void SaveParentAndChildren()
{
using (CustomDataContext myDC = new CustomDataContext())
{
Parent p = new Parent();
Child c = new Child();
p.Children.Add(c);
myDC.Parents.InsertOnSubmit(p); //whole graph is now tracked by this data context
myDC.SubmitChanges(); // whole graph is now saved to database
// or nothing saved if an exception occurred.
} //myDC.Dispose is called for you here whether exception occurred or not
}
(1) var list1 = web.GetList("/lists/list1");
(2) var item1 = list1.GetItemById(10001);
(3) ...
take breakpoint here, open item with ID = 10001 for edit, change 'Title' fields and save it. Then run code follow:
(4)item1[SPBuiltInFieldId.Title] = "some text";
(5)item1.Update();
row (5) throws save conflict exception.
How can to lock item for edit at line (3)? Or any other approach to avoid conflict?
You have to check the SPListItem manually
try
{
var item = list.GetItemById(3);
item["MyField"] = "FooBar";
item.Update();
}
catch(SPException conflictEx)
{
// handle conflict by re-evaluating SPListItem
var item = list.GetItemById(3);
// ..
}
I don't know any other mechanism atm.
// *create a new SPWeb object for each list modification otherwise
we'll get Save Conflict*
from the following URL
http://platinumdogs.me/2010/01/21/sharepoint-calling-splist-update-causes-save-conflict-spexception/
exceptions
using (var thisWeb = featSite.OpenWeb(featWeb.ID))
{
try
{
var listUpdate = false;
var theList = thisWeb.Lists[att.Value];
// change list configuration
// .....
// commit List modifications
if (listUpate)
theList.Update();
}
catch
{
// log the event and rethrow
throw;
}
}
}
}
Another approach is using Linq to SharePoint, Linq to SharePoint offers you a conflict resolution mechanism
SharePoint's LINQ provider is querying for concurrent changes when you try to save changes you've made using the SubmitChanges method.
When a conflict has been found, a ChangeConflictException will be thrown.
foreach(var notebook in spSite.Notebooks)
{
notebook.IsTopNotebook = true;
}
try
{
spSite.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch(ChangeConflictException ex)
{
foreach(ObjectChangeConflict occ in spSite.ChangeConflicts)
{
if (((Notebook)occ.Object).Memory > 16)
{
foreach (MemberChangeConflict field in occ.MemberConflicts)
{
if (field.Member.Name == "IsTopNotebook")
{
field.Resolve(RefreshMode.KeepCurrentValues);
}
else
{
field.Resolve(RefreshMode.OverwriteCurrentValues);
}
}
}
else
{
occ.Resolve(RefreshMode.KeepCurrentValues);
}
}
spSite.SubmitChanges();
}