Ok This one is driving me nuts! What am i doing wrong here? The Insert operation works but the update does not... Thank you in advance!
if (mFromXml.Any()) {
using (DBDataContext DB = new DBDataContext()) {
foreach (object m_loopVariable in mFromXml) {
m = m_loopVariable;
XSLive mToDb = new XSLive();
mToDb.Id = m.Id;
mToDb.Location = m.Location;
XS.XSLive existingMInDb = (from c in DB.XSLive where c.Id == mToDb.Id).FirstOrDefault();
if (existingMInDb != null) {
existingMInDb = mToDb;
} else {
DB.XSLive.InsertOnSubmit(mToDb);
}
}
DB.SubmitChanges();
}
}
The problem is that you're replacing the existingMInDb object with a new object by reference. The result is that the entire existingMInDb variable now points to mToDb. The old existingMInDb object, which was tracked by Entity Framework, is gone.
You need to update the properties individually on the existingMInDb object. You need to change:
if (existingMInDb != null) {
existingMInDb = mToDb;
}
To:
if (existingMInDb != null) {
existingMInDbId.Id = mToDb.Id;
existingMInDbId.Location = mToDb.Location;
}
Related
I have to update one field in the row of the table after fetching two records from the same row. As an easiest practice I have fetched two records individually, created a new value and then updating that particular property through Entity framework. I think there is a better way to do the same thing with less code. If any body can suggest please.
if (objModel.amountpaid==0)
{
using (estatebranchEntities db=new estatebranchEntities())
{
int rentVar = Convert.ToInt32(db.PropertyDetails.Where(m => m.propertyid == objVM.propertyid).Select(m => m.rent).SingleOrDefault());
int balanceVar = Convert.ToInt32(db.PropertyDetails.Where(m => m.propertyid == objVM.propertyid).Select(m => m.balance).SingleOrDefault());
int balanceUpdateVar = (rentVar + balanceVar);
var propInfo = new PropertyDetail() { balance = balanceUpdateVar };
//var result = (from a in db.PropertyDetails
// where a.propertyid == objVM.propertyid
// select new PropertyDetail
// {
// rent = a.rent,
// balance = a.balance
// }).ToList();
db.PropertyDetails.Attach(propInfo);
db.Entry(propInfo).Property(z => z.balance).IsModified = true;
db.SaveChanges();
}
}
Here is what I think you can do.
Fetch the data once and update once.
using (estatebranchEntities db=new estatebranchEntities())
{
var propDetails = db.PropertyDetails.FirstOrDefault(m => m.propertyid == objVM.propertyid);
if (propDetails != null)
{
int rentVar = Convert.ToInt32(propDetails.rent);
int balanceVar = Convert.ToInt32(propDetails.balance);
int balanceUpdateVar = rentVar + balanceVar;
//now do the update
propDetails.balance = balanceUpdateVar;
db.Entry(proDetails).State = EntityState.Modified;
db.SaveChanges();
}
}
if you need to use the rentVar,balanceVar or the balanceUpdateVar, outside of the using statement then declare them outside it.
E.g. I have such code
using (AccountingEntities ent = new AccountingEntities())
{
//just to read record
var recs = ent.Payments.Where(pp => pp.PaymentId == 123);
foreach (p in recs)
{
if (p.Status == 1)
{
using (var dbContextTransaction = ent.Database.BeginTransaction())
{
var someotherrecs = ent.SomeTable.Where(s => s.PaymentId == 456);
foreach (var rec in someotherrecs)
{
rec.Status = 2;
}
ent.SaveChanges();
dbContextTransaction.Commit();
}
}
}
}
If i don't have to change records I will avoid starting transaction,may be in 90% of all cases.Is it OK to do such things (starting and finishing multiple transactions within single context) ?
As #Ivan Stoev mentioned in a comment you don't need a transaction here at all.
Read documentation https://learn.microsoft.com/ru-ru/dotnet/api/system.data.objects.objectcontext.savechanges?view=netframework-4.8
and find there:
SaveChanges operates within a transaction.
So, EF has a changetracker wich tracks any changes to entities. When you perform SaveChanges then in a single transaction all changes will be commited or rolled back in case of exception.
So your code may looks like:
using (AccountingEntities ent = new AccountingEntities())
{
//just to read record
var recs = ent.Payments.Where(pp => pp.PaymentId == 123);
foreach (p in recs)
{
if (p.Status == 1)
{
var someotherrecs = ent.SomeTable.Where(s => s.PaymentId == 456);
foreach (var rec in someotherrecs)
{
rec.Status = 2;
}
ent.SaveChanges();
}
}
}
I've got this query where I'm trying to check if there is an item in the table TruckItems that matches the string value in the variable tareTotal.
public QuoteResult GetTruckInformation(QuoteData data)
{
QuoteResult qr = null;
using (TruckDb db = new TruckDb())
{
var tareTotal = db.ChassisModel.Where(x => x.Id == data.ChassisId).FirstOrDefault();
var items = (from x in db.TruckItems where x.Model == tareTotal.Name select x); //Issue lies here
if (items.Any()) //Error here
{
var truckTareTotal = db.TruckItems.Where(x => x.Model == tareTotal.Name).FirstOrDefault().TareTotal;
var truckGVM = db.TruckItems.Where(x => x.Model == tareTotal.Name).FirstOrDefault().GVM;
var list = new QuoteResult
{
TareTotal = Convert.ToDouble(truckTareTotal),
GVM = Convert.ToDouble(truckGVM)
};
qr = list;
}
}
return qr;
}
I'm getting the error at if (items.Any()):
Non-static method requires a target.
I do not fully understand my problem and I can't find anything that might help me with my problem. Can someone please give me some pointers as to what I'm doing wrong with my variable items? Thank you!
EDIT:
Thanks to everyone for helping me! All of your coding works perfectly fine. I've found my issue and for some reason it has something to do with threading...
In my client side application I used the GetTruckInformation method in a combobox selection changed event and for some reason when it runs through that event, my server side application changes threads between all my statements, thus resulting in all of my data being null.
Here is my WPF/client side method just for show:
private async void cmbChassisModel_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
using (TruckServiceClient service = new TruckServiceClient())
{
QuoteData data = new QuoteData();
data.ChassisId = cmbChassisModel.GetDisplayItemId();
var items = await service.GetTruckInformationAsync(data);
if (items != null)
{
lblTareTotalAmount.Content = items.TareTotal;
lblGVMAmount.Content = items.GVM;
}
}
}
No one has to answer to this issue, I just wanted to let everyone know. :) I will try and figure out why this would happen. :)
Use a .ToList() on the items. Like this:
var items= db.TruckItems.Where(w=>w.Model == tareTotal.Name).ToList();
Otherwise you might run into troubles when executing .Any()
Edit:
Just for the sake of the expirment. Do this:
if(tareTotal==null)
throw new Exception("The tare total is null");
var items= db.TruckItems.Where(w=>w.Model == tareTotal.Name).ToList();
If no items match the db.ChassisModel.Where(x => x.Id == data.ChassisId) then tareTotal will be null.
Anyway, if you only want to check if db.TruckItems contains tareTotal.Name or not, use this. This also improve performance:
Change:
var items = (from x in db.TruckItems where x.Model == tareTotal.Name select x);
if (items.Any())
to:
if(db.TruckItems.Any(x => x.Model == tareTotal.Name))
Check this optimized method:
public QuoteResult GetTruckInformation(QuoteData data)
{
QuoteResult qr = null;
using (TruckDb db = new TruckDb())
{
var tareTotal = db.ChassisModel.Where(x => x.Id == data.ChassisId).FirstOrDefault();
if (tareTotal != null)
{
var item = db.TruckItems.Where(x => x.Model == tareTotal.Name).FirstOrDefault();
if (item != null)
{
var list = new QuoteResult
{
TareTotal = Convert.ToDouble(item.TareTotal),
GVM = Convert.ToDouble(item.GVM)
};
qr = list;
}
}
}
return qr;
}
Simple :
var hasItems = (from x in db.TruckItems where x.Model == tareTotal.Name select x).Any();
Will be tru if you have at least one item matching your condition.
What I'm trying to do is edit the matching row and change a value for a column but it keeps returning null. I believe this is because of the way that I save the query to an object because if I access the query directly then it keeps processing the query everytime. What is the best way to handle this?
using (SymbolsTableAdapter symbolAdapter = new SymbolsTableAdapter())
using (Dataset.SymbolsDataTable symbolTable = new Dataset.SymbolsDataTable())
{
symbolAdapter.Fill(symbolTable);
foreach (var error in errors)
{
var query = from c in symbolTable
where c.Symbol == error.Key && c.Market == error.Value
select c;
Dataset.SymbolsRow row = query.AsParallel().FirstOrDefault();
if (row != null)
{
row.isUnderReview = true;
}
}
// now save
if (symbolTable.GetChanges() != null)
{
symbolTable.AcceptChanges();
}
}
Ok I'm not sure why AcceptChanges wasn't actually doing anything but I changed my code a bit to the below and it works just fine for anyone's future reference
Dataset.SymbolsDataTable tempSymbolsTable = new Dataset.SymbolsDataTable();
tempSymbolsTable = (Dataset.SymbolsDataTable)symbolTable.GetChanges();
if (tempSymbolsTable != null)
{
symbolAdapter.Update(tempSymbolsTable);
tempSymbolsTable.Dispose();
}
Something along the lines of this.
private void SearchResult(string nameOfBean)
{
foreach (Record VARIABLE in mbeanDataGrid.Records)
{
if (VARIABLE.ToString().Contains(nameOfBean))
{
((VARIABLE as DataRecord).DataItem as Record).IsSelected = true;
}
}
}
However i know this syntax is wrong and im looking some advice! Pretty much to select the item (As if you had clicked on it) via code. According to its name.
you can select records with the following code (if you want select more than one record)
private void ShowSearchResult(string searchStr)
{
var recordsToSelect = new List<Record>();
foreach (Record rec in xamGrid.Records) {
var yourData = rec is DataRecord ? ((DataRecord)rec).DataItem as YourDataClass : null;
if (yourData != null && yourData.MatchWithSearchStr(searchStr)) {
recordsToSelect.Add(rec);
}
}
xamGrid.SelectedItems.Records.Clear();
// you need linq -> .ToArray()
xamGrid.SelectedItems.Records.AddRange(recordsToSelect.ToArray(), false, true);
}
or if you only want to activate and select a record then do this one
private void ShowSearchResult(string searchStr)
{
foreach (Record rec in xamGrid.Records) {
var yourData = rec is DataRecord ? ((DataRecord)rec).DataItem as YourDataClass : null;
if (yourData != null && yourData.MatchWithSearchStr(searchStr)) {
xamGrid.ActiveRecord = rec;
// don't know if you really need this
xamGrid.ActiveRecord.IsSelected = true;
break;
}
}
}
hope this helps