I am trying to get all the ID's after adding a new rows in the DB.
I tried this but gives me an exception -> return 0 for Id
foreach (var s in ss)
{
Table t1 = new Table();
...
...
_entities.Table.Add(t1);
Ids.Add(ID); // <--- trying to get Ids here.
}
_entities.SaveChanges();
TIA
Generally, your entities will have an ID property, which is updated after you call SaveChanges(). So you could do this:
List<int> Ids = new List<int>();
foreach (var s in ss)
{
Table t1 = new Table();
...
_entities.Table.Add(t1);
_entities.SaveChanges();
Ids.Add(t1.ID);
}
Or this:
List<Table> insertedTables = new List<Table>();
foreach (var s in ss)
{
Table t1 = new Table();
...
_entities.Table.Add(t1);
insertedTables.Add(t1);
}
_entities.SaveChanges();
List<int> Ids = insertedTables.Select(t => t.ID).ToList();
Related
I am trying to save a large cvs file into the database. The file i am using is about 7000 rows and each row contains 14 columns. I have to generate and tag each column of every row with a topic id i pass in my api. After saving each item i then loop through the actual data and i use the generated id to save each data in another table. My problem is i have nested foreach loops and in the first loop i call db.saveChanges() after taking each column in every row so i can reference the generated id. but that is A LOT of saveChanges() calls that are made before processing the data.
For an example:
public static void Save(TopicRequest req){
using(var db = new DbContext()){
foreach(var row in req.items){
var obj = new Entity{
topicId = req.topicId,
year = req.year
};
db.Add(obj);
db.saveChanges();
foreach(var col in row){
var newData = new Entity{
TopicObjId = obj.id,
Value = col
}
db.TopicData.Add(newData);
}
db.saveChanges();
}
}
}
so for a 7000 row file with 14 columns that means that my first loop will make a call to save into the db 98,000 times. This is causing a timeout and the file saved. How can i probably handle such large amounts of data in this way.
I suggest to use AddRange to improve the performance.
Add vs AddRange
Here's an example:
public async Task Save(TopicRequest req)
{
using(var db = new DbContext())
{
var list1 = new List<Entity1>();
var list2 = new List<Entity2>();
foreach(var row in req.items)
{
var obj = new Entity1
{
topicId = req.topicId,
year = req.year
};
list1.Add(obj);
}
db.Topic.AddRange(list1);
await db.SaveChangesAsync();
// this may not be necessary
await db.Entry(list1).ReloadAsync():
foreach(var obj in list1)
{
var newData = new Entity2
{
TopicObjId = obj.topicId,
Value = obj.value
};
list2.Add(newData);
}
db.TopicData.AddRange(list2);
await db.SaveChangesAsync();
}
}
while filling a combobx, I need to convert a Linq-result to a viewmodel.
Actually, I query the records and then I fill a list of the viewmodel in a loop, but that seems to be a bit strange:
public static IEnumerable<ComboBoxActivities> GetActivitySelectList()
{
using(ApplicationDbContext db = new ApplicationDbContext())
{
var result = from activity in db.Activities
where activity.Available
select new
{
ActivityId = activity.Id,
ActivityName = activity.ActivityName,
Available = activity.Available
};
List<ComboBoxActivities> list = new List<ComboBoxActivities>();
foreach(var res in result)
{
ComboBoxActivities listItem = new ComboBoxActivities()
{
ActivityId= res.ActivityId,
ActivityName= res.ActivityName,
Available= res.Available
};
list.Add(listItem);
}
return list;
}
}
Is this really the right way?
I also tried:
var result = from activity in db.Activities
where activity.Available
select new ComboBoxActivities()
{
ActivityId = activity.Id,
ActivityName = activity.ActivityName,
Available = activity.Available
};
But then my razorview crashes with the message that direct binding to a quers (DbSet, DbQuery...) is not supported.
You can convert the IEnumerable<T> to a List<T> by using ToList()
public static List<ComboBoxActivities> GetActivitySelectList()
{
using(ApplicationDbContext db = new ApplicationDbContext())
{
var result = from activity in db.Activities
where activity.Available
select new ComboBoxActivities()
{
ActivityId = activity.Id,
ActivityName = activity.ActivityName,
Available = activity.Available
};
return result.ToList();
}
}
As for loading a ComboBox from a table query, ComboBox has a DataSource property which you can assign the List to.
I have two tables in an SQL database. They both have five fields: ID (PK), Number, InvoiceDate, InvoiceNumber, and InvoiceAmount. I am attempting to use Entity Framework to insert the InvoiceDate, InvoiceNumber, and InvoiceAmount where the field Number matches from one table to the other.
The context for table one is:
var tc = new TemporaryCsvUpload();
Table two:
var pt = new PermanentTestTable();
First, I inserted values into table 1 from a CSV, now I am trying to insert into table two where the Number field matches.
var entity = new CsvDbEntities1();
foreach (var item in model)
{
var tc = new TemporaryCsvUpload();
tc.Number = item.Number;
tc.CreditInvoiceAmount = item.CreditInvoiceAmount;
tc.CreditInvoiceDate = item.CreditInvoiceDate;
tc.CreditInvoiceNumber = item.CreditInvoiceNumber;
entity.TemporaryCsvUploads.Add(tc);
entity.SaveChanges();
}
I am new to EF and any help would be appreciated. Thanks!
Sorry if I dont completely understand but here it goes based of this code :
foreach (var item in model)
{
var tc = new TemporaryCsvUpload();
tc.Number = item.Number;
tc.CreditInvoiceAmount = item.CreditInvoiceAmount;
tc.CreditInvoiceDate = item.CreditInvoiceDate;
tc.CreditInvoiceNumber = item.CreditInvoiceNumber;
entity.TemporaryCsvUploads.Add(tc);
entity.SaveChanges();
}
After you have saved the first table now you query the second for the same record as :
var table2entity = entity.PermanentTestTable.Where(x => x.Number == tc.Number).Select(x => x).First();
This will query the second table and grab whatever entity is there with the same number
So your end code might look like :
var entity = new CsvDbEntities1();
foreach (var item in model)
{
var tc = new TemporaryCsvUpload();
tc.Number = item.Number;
tc.CreditInvoiceAmount = item.CreditInvoiceAmount;
tc.CreditInvoiceDate = item.CreditInvoiceDate;
tc.CreditInvoiceNumber = item.CreditInvoiceNumber;
entity.TemporaryCsvUploads.Add(tc);
entity.SaveChanges();
var table2entity = entity.PermanentTestTable.ToList();
table2entity = table2entity.Where(x => x.Number == tc.Number).Select(x => x).First();
table2entity.CreditInvoiceAmount = item.CreditInvoiceAmount;
//More values inserted here
entity.SaveChanges()
}
I ended up having to nest a foreach loop to iterate through every row with a Number field. I'm sure there is a better way to do this, but I am just happy it's working:
var entity = new CsvDbEntities1();
foreach (var item in model)
{
var tc = new TemporaryCsvUpload
{
PoNumber = item.Number,
CreditInvoiceAmount = item.CreditInvoiceAmount,
CreditInvoiceDate = item.CreditInvoiceDate,
CreditInvoiceNumber = item.CreditInvoiceNumber
};
entity.TemporaryCsvUploads.Add(tc);
var ptt = entity.PermanentTestTables.ToList().Where(x => x.Number == tc.Number);
foreach (var row in ptt)
{
row.CreditInvoiceDate = tc.CreditInvoiceDate;
row.CreditInvoiceNumber = tc.CreditInvoiceNumber;
row.CreditInvoiceAmount = tc.CreditInvoiceAmount;
}
entity.SaveChanges();
}
I am inserting objects at the same time using Entity framework like below.
context = new MyContext();
foreach (var x in lstX)
{
var abc = new abc{ name= x.abcName };
context.abcs.Add(abc);
var xyz = new xyz{ name = x.xyzName };
context.xyzs.Add(xyz);
}
context.SaveChanges();
Is it possible get the identity of all these inserted objects?
When you call SaveChanges, the Identity field is populated on the original entity. So to obtain this id, simply store a reference to the identity and access it after SaveChanges:
context = new MyContext();
List<abc> addedABCs = new List<abc>();
List<xyz> addedXYZs = new List<xyz>();
foreach (var x in lstX)
{
var abc = new abc{ name= x.abcName };
addedABCs.Add(abc);
context.abcs.Add(abc);
var xyz = new xyz{ name = x.xyzName };
addedXYZs.Add(xyz);
context.xyzs.Add(xyz);
}
context.SaveChanges();
foreach (var abc in addedABCs)
{
Console.WriteLine("Added item with ID {0}", abc.Id);
}
I have a many-to-many relationship as follows:
Table1
ID (int) | Name (string)
Table2
ID (int) | Data (string)
Table1_2
Table1ID (int) | Table2ID (int)
I would like to do the following in Entity Framework:
Given a List<Table1>, look to see if any records in Table1 that match; if so, reference them; if not, add them and reference them. For example, something like:
public void InsertOrReferenceExisting(string data, List<Table1> table1References)
{
var myEntities = new MyEntities();
var table1Entities = new EntityCollection<Table1>();
foreach(var row in table1References)
{
var existing = myEntities.Table1.Where(x => x.Name == row.Name);
if (existing.Count() > 0)
{
// reference existing row in Table1
}
else
{
// add new row to Table1
}
}
myEntities.Table2.AddObject(new Table2
{
Data = data,
Table1s = table1Entities
});
myEntities.SaveChanges(SaveOptions.AcceptAllChangesAfterSave);
}
Am I on the right track?
Give this a try:
public void InsertOrReferenceExisting(string data, List<Table1> table1References)
{
using (var myEntities = new MyEntities())
{
var tbl2 = myEntities.Table2.CreateObject();
tbl2.Data = data;
myEntities.Table2.AddObject(tbl2);
foreach (var row in table1References)
{
var tbl1 = myEntities.Table1.Where(x => x.Name == row.Name).FirstOrDefault();
if (tbl1 == null)
{
tbl1 = myEntities.Table1.CreateObject();
tbl1.Name = row.Name;
}
tbl2.Table1.Add(tbl1);
}
myEntities.SaveChanges();
}
}
Note that this solution doesn't allow for multiple records in Table1 that have the same value in the Name column. You should probably enforce that with a unique constraint on the database level.