I use Entity Framework and stored procedures.
modelBuilder.Entity<MyModel>().MapToStoredProcedures();
I used Insert update and delete without any problem.but for some purpose I want to use AutoDetectChangesEnabled = false;
After that entity doesn't work anymore and nothing changes in the database after SaveChanges. But when I comment AutoDetectChangesEnabled or set it to true, it works fine.
This is my code: I read from Excel and import into database:
dt = exc.ReadExcel(address, ".xlsx");
using (var db = new Context())
{
db.Configuration.AutoDetectChangesEnabled = false;
for (int i = 1; i < dt.Rows.Count; i++)
{
int id = int.Parse(dt.Rows[i][0].ToString());
var thisChah = db.MyModel.Find(id);
if (thisChah == null)
{
continue;
}
thisChah.f1 = dt.Rows[i][1].ToString();
thisChah.f2 = dt.Rows[i][2].ToString();
thisChah.f3 = dt.Rows[i][3].ToString();
thisChah.f4 = dt.Rows[i][4].ToString();
thisChah.f5 = dt.Rows[i][5].ToString();
thisChah.f6 = dt.Rows[i][6].ToString();
thisChah.f7 = dt.Rows[i][7].ToString();
LogsAnyThing("row " + i + "- OK ");
if(i % 50 == 0)
{
int result = db.SaveChanges();
if (result > 0)
{
LogsAnyThing("row " + i + "- Added ");
}
}
}
db.SaveChanges();
}
Since you have turned off AutoDetectChanges , you need to explicitly tell context to look for any changes before attempting to call SaveChanges(). You can do this by adding this statement - db.ChangeTracker.DetectChange() before call to db.SaveChanges(). Without this context is not aware that any changes has been done to the model.
You can read more #https://learn.microsoft.com/en-us/ef/ef6/saving/change-tracking/auto-detect-changes
Related
This code saves my data to the database. The app records the time spent on each day of the month.
They write to the database in SQL Server, using EF. The problem is just that I would like them to overwrite instead of writing more
Controller:
List<Karta_Model> objNextKartaModel = new List<Karta_Model>();
for (int i = 0; i < liczbaDni; i++)
{
var modelNext = new Karta_Model()
{
Login = userName,
Rok = numerRoku,
Miesiac = numerMiesiaca,
DzMiesiaca = modelKarta.Model1[i].DzMiesiaca.Value,
DzTygodnia = modelKarta.Model1[i].DzTygodnia,
Rozpoczecie = modelKarta.Model1[i].Rozpoczecie
....
};
objNextKartaModel.Add(modelNext);
await _ecpContext.Karta.AddRangeAsync(objNextKartaModel);
await _ecpContext.SaveChangesAsync();
}
Id in SQL Server is defined as:
[Id] [int] IDENTITY(1,1)
I came up with the idea to extract the first row ID from the previously saved database
var nrIdBase = _ecpContext.Karta
.FirstOrDefault(f => f.DzMiesiaca == 1 &&
f.Miesiac == numerMiesiaca &&
f.Rok == numerRoku &&
f.Login == userName).Id;
but I don't know how to use it.
I tried something like this:
for (int i = 0; i < liczbaDni; i++)
{
var modelNext = new Karta_Model()
{
Id = nrIdBase +i,
Login = userName,
Rok = numerRoku,
Miesiac = numerMiesiaca,
DzMiesiaca = modelKarta.Model1[i].DzMiesiaca.Value,
DzTygodnia = modelKarta.Model1[i].DzTygodnia,
Rozpoczecie = modelKarta.Model1[i].Rozpoczecie
....
};
}
but I get an error:
InvalidOperationException: The instance of entity type 'Karta_Model' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
Does anyone have an idea how to do this?
How to overwrite saved data once?
In order to update an existing recording in a database, you need to have it's ID before the update operation.
Then you can do this:
var existingRecord = _ecpContext.Karta.FirstOrDefault(x => x.Id == theExistingId);
if (existingRecord != null) {
existingRecord.Login = "CHANGED";
await _ecpContext.SaveChangesAsync()
}
This call that you are using:
await _ecpContext.Karta.AddRangeAsync(objNextKartaModel);
Is only for adding new items to the database.
Following the idea in my comment above, one thing you can do is to delete the existing data in the table before adding the new ones.
List<Karta_Model> objNextKartaModel = new List<Karta_Model>();
for (int i = 0; i < liczbaDni; i++)
{
var modelNext = new Karta_Model()
{
Login = userName,
Rok = numerRoku,
Miesiac = numerMiesiaca,
DzMiesiaca = modelKarta.Model1[i].DzMiesiaca.Value,
DzTygodnia = modelKarta.Model1[i].DzTygodnia,
Rozpoczecie = modelKarta.Model1[i].Rozpoczecie
....
};
objNextKartaModel.Add(modelNext);
//Add logic to delete the existing data
foreach(var model in _ecpContext.Karta)
{
_ecpContext.Karta.Remove(model);
}
await _ecpContext.Karta.AddRangeAsync(objNextKartaModel);
await _ecpContext.SaveChangesAsync();//One SaveChanges call is enough to update the database
}
I have the problem that I have a MariaDB database with HeidiSQL. There are four tables and im using Linq to insert new data. One of the tables isn´t always necessary. So i marked the column with the foreign key in one of the a other tables for can be NULL. The problem is that when i create the new objects to insert into database it creates the new data in the database but the foreign key in the other table keeps emtpy.
When i undo the Null option in the column and want to insert a standardvalue instead, it throws an UpdateEntityException.
What i should mention is, that i cerated the database first in HeidiSQL and created then the code in Visual Studio with EntityFramework 5.0.
Or might the mistake caused by building and adding the database object in an if-clause?
There are some code examples of my code, i hope it will help.
DateTime aktuellesDatum = DateTime.Now;
int proId = getProjectIdByProjectnumber(zeichnungen[0].Projektnummer);
int tagId = getTagIdByTag(zeichnungen[0].Tag, zeichnungen[0].Projektnummer);
string hauptzeichnung = "";
int gruppeId = -1;
//Noch kein Projekt vorhanden
if(proId == -1)
{
using (DMSContext db = new DMSContext())
{
foreach (ZeichnungInDB zeichnungInDB in zeichnungen)
{
zeichnungInDB.Volante_Index = getVolCountByDrawingNumber(zeichnungInDB.Zeichnungsnummer) + 1;
var zeichnung = new zeichnung()
{
Zeichnung_ID = zeichnungInDB.Dateiname + "_" + zeichnungInDB.Index + "_VOL_" + zeichnungInDB.Volante_Index + "_" + aktuellesDatum.ToShortDateString(),
Zeichnungsnummer = zeichnungInDB.Zeichnungsnummer,
Index = zeichnungInDB.Index,
Zeitstempel = aktuellesDatum,
Dateiname_Org = zeichnungInDB.Dateiname,
Aenderung_Ext = zeichnungInDB.Aenderung_Ext,
Aenderung_Int = "AE_" + zeichnungInDB.Projektnummer + "_" + aktuellesDatum.Year + "-" + aktuellesDatum.Month + "-" + aktuellesDatum.Day + " " + aktuellesDatum.Hour + ":" + aktuellesDatum.Minute,
Dokumententyp = zeichnungInDB.DokumentenTyp,
Dateiendung = zeichnungInDB.Extension,
Volante_Index = zeichnungInDB.Volante_Index,
MMS_Sachmerkmal = zeichnungInDB.Mms_Sachmerkmal,
Status = zeichnungInDB.Status,
Aenderung_Bemerkung_Txt = zeichnungInDB.Aenderung_Bemerkung_Text,
Einzel_Bemerkung_Txt = zeichnungInDB.Einzel_Bemerkung,
Ahang_Link = zeichnungInDB.Anhang_Link,
Einzel_Link = zeichnungInDB.Einzel_Link,
};
db.zeichnungs.Add(zeichnung);
if(zeichnungInDB.Baugruppe_Hauptzeichnung == true)
{
hauptzeichnung = zeichnungInDB.Zeichnungsnummer;
}
}
var projekt = new projekt()
{
Projektnummer = zeichnungen[0].Projektnummer,
};
var tag = new tag()
{
Tag1 = zeichnungen[0].Tag,
};
if (!hauptzeichnung.Equals(""))
{
var baugruppe = new baugruppe
{
Hauptzeichnung = hauptzeichnung,
};
db.baugruppes.Add(baugruppe);
}
db.projekts.Add(projekt);
db.tags.Add(tag);
try
{
db.SaveChanges();
}
catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
{
Exception raise = dbEx;
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
string message = string.Format("{0}:{1}",
validationErrors.Entry.Entity.ToString(),
validationError.ErrorMessage);
// raise a new exception nesting
// the current instance as InnerException
raise = new InvalidOperationException(message, raise);
}
}
throw raise;
}
}
This is only a short e.g. from my code because the whole cs would be to long and nobody would spend the time on so much code.
One other thing i would like to ask is. If the following code works correct for update a string in a field?
private static void updateHauptzeichnung(int baugruppeId, string zeichnungsnummer)
{
using (var context = new DMSContext())
{
var query = context.baugruppes
.Where(b => b.Baugruppe_ID == baugruppeId)
.Select(g => new { g.Hauptzeichnung })
.SingleOrDefault();
if (query != null)
{
query.Hauptzeichnung.Replace(query.Hauptzeichnung, zeichnungsnummer);
}
context.SaveChanges();
}
}
I solved my problem. I changed the foreignkey field from can be NULL to is necessary, added in the foreign table a costum dataset with ID is 0 and I give new data this ID as its foreign ID when they have no offical link to the foreign table. It might not be the best solution, but it fixed my problem.
I am trying to insert a text file formatted in C Sharp to a Microsoft SQL server. I have 2 tables Transaction and TMatch in which I want to populate the data. 4 attributes each. I have created 2 classes for each. I am aware of how to input data manually into the database through the .Add() and .SaveChanges().
Here is what I have so far:
//Database insertions
TTransaction txn = new TTransaction();
**txn.Amount = 56; //I want a variable used below (AMOUNT) to go into amount.
txn.TRN = "sdfgsdfg";** //(TxnNo) to go into TRN
ScotiaNYAEntities context = new ScotiaNYAEntities();
context.TTransactions.Add(txn);
context.SaveChanges();
Traversing the text file using a while loop.
{
if (line.Contains("AMOUNT:")) //Look where to end for Transaction Text
{
// For Amount
IsAmount=true;
if(IsAmount)
{
Amount = line.Replace("AMOUNT:", String.Empty).Trim();
Console.WriteLine("AMOUNT: ********");
Console.WriteLine(Amount);
}
}..............................................
I am not sure how to reference a variable instead of just values.
Thank you.
leap of faith but you could have something like this
using (ScotiaNYAEntities context = new ScotiaNYAEntities())
{
foreach (string line in File.ReadLines(pathToFile))
{
if (line.Contains("AMOUNT:"))
{
if (IsAmount)
{
string amount = line.Replace("AMOUNT:", string.Empty).Trim();
TTransaction txn = new TTransaction();
txn.Amount = amount;
txn.TRN = "sdfgsdfg";
context.TTransactions.Add(txn);
}
}
}
context.SaveChanges();
}
This is what I did:
In the for loop for reading the file line by line
String TxnLOC = null;
IsTransactionLocation= false;
if (line.Contains("TRANSACTION LOC:"))
{
IsTransactionLocation = true;
if (IsTransactionLocation)
{
TxnLOC = line.Replace("TRANSACTION LOC:", String.Empty).Trim();
Console.WriteLine("The Transaction Location: ********");
Console.WriteLine(TxnLOC);
//Database insertion fot TTransaction Table
TTransaction txn = new TTransaction();
txn.TRN = txnNo;
txn.Amount = Convert.ToDecimal(Amount);
txn.TransactionLocation = TxnLOC;
context.TTransaction.Add(txn); //Adding to the database
context.SaveChanges();
IsTxnSection = false;//For 1 to many relationship
}
}
First off let me say that I have done research on this issue and I know how it happens but I don't know what to change in my code to prevent this error. I'm using a parallel foreach loop to quickly go through items and update them in the database. My code is below and I'm using a strongly typed dataset via sql.
Parallel.For(0, activeSymbolsCount, j =>
{
symbol = symbolTable.AsParallel().ElementAtOrDefault(j).Symbol;
SymbolInfo symbolClass = new SymbolInfo(symbol, market);
StockRating rating = performCalculations(symbolClass);
saveToTable(rating);
});
public static void saveToTable(StockRating rating)
{
if (rating != null)
{
string symbol = rating.symbol;
string market = rating.market;
using (StockRatingsTableAdapter ratingsAdapter = new StockRatingsTableAdapter())
using (StockRatingsDataTable ratingsTable = new StockRatingsDataTable())
{
ratingsAdapter.ClearBeforeFill = true;
ratingsAdapter.Adapter.UpdateBatchSize = 1000;
ratingsAdapter.Fill(ratingsTable);
var query = from c in ratingsTable
where c.Symbol == symbol && c.Market == market
select c;
StockRatingsRow row = query.AsParallel().FirstOrDefault();
if (row != null)
{
// update the info with the new calculated info
row.EstimatedReturn = rating.estimatedReturn;
row.LongRating = rating.longRating;
row.MediumRating = rating.mediumRating;
row.ShortRating = rating.shortRating;
row.Risk = rating.risk;
row.MarginEnabled = rating.isMarginEnabled;
}
StockRatingsDataTable tempRatingsTable = new StockRatingsDataTable();
tempRatingsTable = (StockRatingsDataTable)ratingsTable.GetChanges();
if (tempRatingsTable != null)
{
ratingsAdapter.Adapter.UpdateCommand.UpdatedRowSource = System.Data.UpdateRowSource.None;
ratingsAdapter.Update(tempRatingsTable);
tempRatingsTable.Dispose();
Console.WriteLine("Stock rating updated for " + rating.symbol + " in the " + rating.market + " market!");
}
}
}
}
I'm getting the exception when performing an update on this table and the method above is the only time I access any information from this table so that is why I didn't show my other code.
I have a ProductLevel table in an SQL database. It contains the products for a store. I want to copy these records into a ProductLevelDaily table at the time the user logs onto the hand held device in the morning.
As they scan items the bool goes from false to true so at anytime they can see what items are left to scan/check.
From the mobile device I pass the siteID and date to the server:
int userID = int.Parse(oWebRequest.requestData[5]); and a few other things
IEnumerable<dProductLevelDaily> plditems
= DSOLDAL.CheckProductDailyLevelbySiteCount(siteID, currentDate);
This checks if there are any records already moved into this table for this store. Being the first time this table should be empty or contain no records for this store on this date.
if (plditems.Count() == 0) // is 0
{
IEnumerable<dProductLevel> ppitems = DSOLDAL.GetProductsbySite(siteID);
// this gets the products for this store
if (ppitems.Count() > 0)
{
dProduct pi = new dProduct();
foreach (dProductLevel pl in ppitems)
{
// get the product
pi = DSOLDAL.getProductByID(pl.productID, companyID);
dProductLevelDaily pld = new dProductLevelDaily();
pld.guid = Guid.NewGuid();
pld.siteID = siteID;
pld.statusID = 1;
pld.companyID = companyID;
pld.counted = false;
pld.createDate = DateTime.Now;
pld.createUser = userID;
pld.productID = pl.productID;
pld.name = "1000"; // pi.name;
pld.description = "desc"; // pi.description;
DSOLDAL.insertProductLevelDailyBySite(pld);
}
}
}
On the PDA the weberequest response returns NULL
I can't see what the problem is and why it wont work.
The insert is in DSOLDAL:
public static void insertProductLevelDailyBySite(dProductLevelDaily pld)
{
dSOLDataContext dc = new dSOLDataContext();
try
{
dc.dProductLevelDailies.InsertOnSubmit(pld);
// dProductLevelDailies.Attach(pld, true);
dc.SubmitChanges();
}
catch (Exception exc)
{
throw new Exception(getExceptionMessage(exc.Message));
}
finally
{
dc = null;
}
}
This code works until I put the foreach loop inside with the insert
IEnumerable<dProductLevelDaily> plditems
= DSOLDAL.CheckProductDailyLevelbySiteCount(siteID, s);
if (plditems.Count() == 0) // plditems.Count() < 0)
{
IEnumerable<dProductLevel> ppitems = DSOLDAL.GetProductsbySite(siteID);
if (ppitems.Count() > 0)
{
oWebResponse.count = ppitems.Count().ToString();
oWebResponse.status = "OK";
}
else
{
oWebResponse.count = ppitems.Count().ToString();
oWebResponse.status = "OK";
}
}
else
{
oWebResponse.count = "2"; // plditems.Count().ToString();
oWebResponse.status = "OK";
}
These kind of bulk operations aren't very well matched to what Linq-to-SQL does.
In my opinion, I'd do this using a stored procedure, which you could include in your Linq-to-SQL DataContext and call from there.
That would also leave the data on the server and just copy it from one table to the other, instead of pulling down all data to your client and re-uploading it to the server.
Linq-to-SQL is a great tool - for manipulating single objects or small sets. It's less well suited for bulk operations.