Room Model
public class Room
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
Id is the primary key here
As in entity framework, all the room details are in the dbcontext
dbContext.Rooms
And there is a IList<Room> updateRoomswith list of updated name and address for few rooms.
How do I update dbContext.Rooms for the matching items in updateRooms using the primary key Id and save to DB using entity framework.
Note: I do understand that I can update each Room in dbContext.Rooms and save as below
foreach (var room in updateRooms)
{
dbContext.Rooms.Attach(room);
dbContext.Entry(room).State = EntityState.Modified;
dbContext.SaveChanges();
}
but is there a way attach all rooms and save at once
For another awswer
foreach (var room in updateRooms)
{
dbContext.Entry(room).State = EntityState.Modified;
}
dbContext.SaveChanges();
You also use this.
First You need to find all the entries with Id (Primary Key) and update the values. Then call SaveChanges() method.
foreach (var room in updateRooms)
{
var roomToUpdate = dbContext.Rooms.Find(room.Id);
roomToUpdate.Name = room.Name;
roomToUpdate.Address = room.Address;
}
dbContext.SaveChanges();
foreach(var item in updateRooms)
{
var oldModel= dbContext.Rooms.First(a => a.Id == item.Id);
if(oldModel !=null)
{
oldModel.Name = item.Name;
oldModel.Address = item.Address;
dbContext.SaveChanges();
}
}
Try This.
Related
I am trying to link Shipments to Road using a clean database, with fresh data unlinked, first time trying to relate these 2 entities.
public class Road
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public ShipmentMode ShipmentMode { get; set; }
public string RoadName { get; set; }
public virtual List<Shipment> Shipments { get; set; }
}
public void SaveToDatabase()
{
using (var db = new DbContext())
{
foreach (var road in this.Roads)
{
road.Shipments.ForEach(shipment => shipment = db.Shipments.FirstOrDefault(s => s.Id == shipment.Id));
var input = db.Roads.Add(road);
}
db.SaveChanges();
}
}
At the line var input = db.Roads.Add(road); it will throw the error Message "The instance of entity type 'Shipment' cannot be tracked because another instance with the key value '{Id: 46}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.'.
I had this error before, fixed it but I rearranged the code and now it's back to throwing this error. I am just trying to get Shipments to link to Road.
This code below has worked for me. If anyone has a better solution, please feel free to post.
public void SaveToDatabase()
{
using (var db = new DbContext())
{
foreach (var road in this.Roads)
{
var shipments = road.Shipments;
road.Shipments = null;
var input = db.Roads.Add(road);
db.SaveChanges();
var getRoad = db.Lanes.Include(p => p.Shipments).FirstOrDefault(t => t.Id == input.Entity.Id);
getRoad.Shipments.AddRange(shipments);
db.SaveChanges();
}
}
}
Alternative solution
public void SaveToDatabase()
{
using (var db = new DbContext())
{
foreach (var road in this.Roads)
{
db.UpdateRange(road.Shipments);
var input = db.Roads.Add(road);
db.SaveChanges();
}
}
}
So I'm passing in a list of objects (that are originally in the database already) to a function to update a property (SentDate) in the database, the structure is similar to
public class Product
{
[Key, Column("SKU", Order = 0)]
public string SKU { get; set; }
[Key, Column("Sequence", Order = 1)]
public int Sequence { get; set; }
public DateTime SentDate { get; set; }
}
And it is going into a function to update. Where I went wrong was I was attempting to do:
public static void UpdateSentDate(List<Product> records, DateTime CurrentDate)
{
DbContext db = new DbContext(); // there is a DbSet for Product in here
var toUpdate = db.Products.Where(c => records.Contains(c)).ToList();
foreach (var rec in toUpdate)
{
rec.SentDate = CurrentDate;
}
db.SaveChanges();
}
This bombs at the toUpdate creation due to the records.Contains(c) as it doesn't involve primitives. So I'm curious how to get the records where records's SKUs and Sequences match up with the database's that is better than my current stopgap:
List<Product> dbRecords = new List<Product>();
foreach (var record in records)
{
var item = db.Products.Where(c => c.SKU == record.SKU && c.Sequence == record.Sequence).Single();
dbRecords.Add(item);
}
you can make it work a little faster if you assign a new date in the same time
foreach (var record in records)
{
var item = db.Products.Where(c => c.SKU == record.SKU && c.Sequence == record.Sequence).Single();
if (item!=null)
{
item.SentDate = CurrentDate;
db.Entry(item).Property(i=>i.SentDate).IsModified = true; // maybe you can ommit this
}
}
db.SaveChanges();
I am trying to learn about Entity Framework 6, and I am running into an issue, that I have been able to reproduce in a test project:
A Movie has a Nameand a Revenue. A Revenue has a GrossIncome:
public class Movie
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public Revenue Revenue { get; set; }
}
public class Revenue
{
[Key]
public int Id { get; set; }
public double GrossIncome { get; set; }
}
I am trying to use EF6 code-first to persist some data about movies in the database:
public class MovieContext: DbContext
{
public MovieContext(): base("name=testDB") { }
public DbSet<Movie> Movies { get; set; }
public DbSet<Revenue> Revenues { get; set; }
}
I start by inserting a new movie, with its associated revenue in the DB:
using (var context = new MovieContext())
{
Revenue revenue = new Revenue()
{
GrossIncome = 10
};
Movie movie = new Movie()
{
Name = "foo",
Revenue = revenue
};
context.Movies.Add(movie);
context.SaveChanges();
}
I can see in SQL Server that the tables are created, and that a Movies.Revenue_Id column has been created, with a foreign key relationship to Revenue.Id.
If I try to query it using SQL, it works fine:
SELECT Movies.Name, Revenues.GrossIncome
FROM Movies
LEFT JOIN Revenues ON Movies.Revenue_Id = Revenues.Id
returns
Name GrossIncome
----------------------
foo 10
However, if I try to use Entity Framework to query the data:
using (var context = new MovieContext())
{
List<Movie> movieList = context.Movies.ToList();
Console.WriteLine("Movie Name: " + movieList[0].Name);
if (movieList[0].Revenue == null)
{
Console.WriteLine("Revenue is null!");
}
else
{
Console.WriteLine(movieList[0].Revenue.GrossIncome);
}
Console.ReadLine();
}
The console reads:
Movie Name: foo <- It shows that the query works, and that the data in the main table is fetched.
Revenue is null! <- Even though the data in the DB is correct, EF does not read the data from the foreign key.
My question is simple: what am I doing wrong? How are the foreign key values supposed to be read?
Just include the child entity you want to load:
using (var context = new MovieContext())
{
List<Movie> movieList = context.Movies
.Include(m => m.Revenue) // ADD THIS INCLUDE
.ToList();
Console.WriteLine("Movie Name: " + movieList[0].Name);
if (movieList[0].Revenue == null)
{
Console.WriteLine("Revenue is null!");
}
else
{
Console.WriteLine(movieList[0].Revenue.GrossIncome);
}
Console.ReadLine();
}
This will load the movies - and also make sure that all the references to their respective .Revenue references have been loaded, too.
How to update the many to many navigation property?
I want to update the entity I get an error
have the same primary key value
I know there is way to split the many-many relation to two many-to-one relations, but this is the case. Update many-many relation.
I do this way to add new a entity with navigation property without problem BUT for updating there is an error. I tried to remove db.Entry(item).State = ... in update, but the problem is still there.
public class TrendChart
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<ParameterMonitor> Monitors { get; set; }
}
public class ParameterMonitor
{
public int Id { get; set; }
public virtual List<TrendChart> Charts{ get; set; }
}
var db = new DataAccess.ApplicationDbContext();
var newTrendChart = db.TrendChart.Where(x => x.Id == trendChart.Id).FirstOrDefault();
if (newTrendChart != null)
{
if (newTrendChart.Monitors != null)
newTrendChart.Monitors.Clear();
newTrendChart.Name = trendChart.Name;
newTrendChart.Monitors = new List<ParameterMonitor>();
foreach (var item in trendChart.Monitors)
{
newTrendChart.Monitors.Add(new DataAccess.ParameterMonitor { MOParameterId = item.MoParameterId });
}
// prevent from adding new parameter
foreach (var item in newTrendChart.Monitors)
{
// here the ERROR happens
db.Entry(item).StateSystem.Data.Entity.EntityState.Unchanged;
}
db.SaveChanges();
}
I found the solution, the point is that whenever you try to add something in intermediate table the CLEAR() function does not remove the history of items in the behind scene which we do not see, consider there are two items in the intermediate table , 1,2 and 1,3 . if you want to update the table by just 1,2 , it means the clear function remove 1,2 and 1,3 and again add 1,2. but it does not work because there is already an item 1,2 in behind scene. we need to remove() 1,3 and don't care about 1,2. Is there any other Solution.
var tempMOList = new List<int>();
tempMOList = newTrendChart.Monitors.Select(x=> x.MOParameterId).ToList();
foreach (var id in tempMOList)
{
var temp = newTrendChart.Monitors.Where(x => x.MOParameterId == id).FirstOrDefault();
if (trendChart.Monitors.Any(x => x.MoParameterId == id) == false)
newTrendChart.Monitors.Remove(temp);
}
foreach (var item in trendChart.Monitors)
{
if (newTrendChart.Monitors.Any(x => x.MOParameterId == item.MoParameterId) == false)
newTrendChart.Monitors.Add(new DataAccess.ParameterMonitor { MOParameterId = item.MoParameterId });
}
//prevent from adding new parameter
foreach (var item in newTrendChart.Monitors)
{
db.Entry(item).State = System.Data.Entity.EntityState.Unchanged;
}
db.SaveChanges();
I have added a prop to my class and added a new DbSet but when saving, it does not store my child objects.
My house class:
[Table("Houses")]
public class House
{
[Key]
public int ID { get; set; }
public List<Price> Prices { get; set; } // <-- new prop
}
my dbcontext has a Prices prop now: public DbSet<Price> Prices { get; set; } and I enabled migrations, added the migration and updated the database. So the prices table is created.
When I update a House object, it does not insert anything in the Prices table.
var h = new House(); // with prices etc filled
if (db.Houses.Any(hc => hc.Code.Equals(h.Code, StringComparison.InvariantCultureIgnoreCase)))
{
var original = db.Houses.First(k => k.Code.Equals(h.Code, StringComparison.InvariantCultureIgnoreCase));
h.ID = original.ID; // workaround for The property 'ID' is part of the object's key information and cannot be modified.
h.CountryId = original.CountryId;
db.Entry(original).CurrentValues.SetValues(h);
db.SaveChanges(); // does update House fields, but no prices
} else { // add new
db.Houses.Add(h);
db.SaveChanges();
}
I did add public virtual House House { get; set; } to my Price class. But I do not fill it, because when populating the house object, I do not know the ID in the db yet. Maybe that is causing it? I have also read https://stackoverflow.com/a/26572122/169714 and added this to my Price class:
[ForeignKey("HouseId")]
public virtual House House { get; set; }
public int HouseId { get; set; }
but still no entries in the prices table. I am probably doing something wrong storing/updating the database.
edit current store method:
using (var db = new MyCommon.HouseContext())
{
var l = db.Countries.First(tmpC => tmpC.Code.Equals(h.Country.Code));
h.OperatorId = op.ID;
h.CountryId = l.ID;
h.Country = l;
var existingHouse = db.Houses.Where(p => p.Code.Equals(h.Code, StringComparison.InvariantCultureIgnoreCase)).SingleOrDefault();
if (existingHouse != null)
{
// update
h.ID = existingHouse.ID; // workaround for The property 'ID' is part of the object's key information and cannot be modified.
h.CountryId = existingHouse.CountryId;
h.OperatorId = existingHouse.OperatorId;
db.Entry(existingHouse).CurrentValues.SetValues(h);
db.Entry(existingHouse).State = System.Data.Entity.EntityState.Modified;
//db.SaveChanges(); // moved to bottom for perf.
}
else
{
existingHouse = h;
db.Houses.Add(h); // insert
}
foreach (var ft in existingHouse.Prices)
{
var existingFt = existingHouse.Prices.SingleOrDefault(f => f.ID == ft.ID);
if (existingFt != null)
{
db.Entry(existingFt).CurrentValues.SetValues(ft);
db.Entry(existingFt).State = System.Data.Entity.EntityState.Modified;
}
else
{
existingHouse.Prices.Add(ft);
}
}
db.SaveChanges();
}
Check the EntityState of your objects. Attach the object to your context, and iterate through these Prices to mark the EntityState.Modified. If the Price objects are new, you can use EntityState.Added. You can see here for an 'upsert' pattern example.