How to update record using Entity Framework 6?
我正在尝试使用EF6更新记录。首先查找记录,如果存在,则更新它。这是我的密码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var book = new Model.Book { BookNumber = _book.BookNumber, BookName = _book.BookName, BookTitle = _book.BookTitle, }; using (var db = new MyContextDB()) { var result = db.Books.SingleOrDefault(b => b.BookNumber == bookNumber); if (result != null) { try { db.Books.Attach(book); db.Entry(book).State = EntityState.Modified; db.SaveChanges(); } catch (Exception ex) { throw; } } } |
每次我尝试使用上述代码更新记录时,都会收到以下错误:
{System.Data.Entity.Infrastructure.DbUpdateConcurrencyException: Store
update, insert, or delete statement affected an unexpected number of
rows (0). Entities may have been modified or deleted since entities
were loaded. Refresh ObjectStateManager entrie
您试图更新记录(对我来说,这意味着"更改现有记录的值并将其保存")。因此,您需要检索对象,进行更改并保存它。
1 2 3 4 5 6 7 8 9 | using (var db = new MyContextDB()) { var result = db.Books.SingleOrDefault(b => b.BookNumber == bookNumber); if (result != null) { result.SomeValue ="Some new value"; db.SaveChanges(); } } |
我一直在审查实体框架的源代码,并找到了一种方法来实际更新实体,如果您知道密钥属性,那么在其他情况下,您需要检查addorupdate实现:
1 2 3 4 5 6 7 8 9 10 11 | public void Update<T>(T item) where T: Entity { // assume Entity base class have an Id property for all items var entity = _collection.Find(item.Id); if (entity == null) { return; } _context.Entry(entity).CurrentValues.SetValues(item); } |
希望这有帮助!
您可以使用
1 2 | db.Books.AddOrUpdate(book); //requires using System.Data.Entity.Migrations; db.SaveChanges(); |
所以你有一个被更新的实体,你想用最少的代码在数据库中更新它…
并发性总是很棘手的,但我假设您只是希望您的更新能够获胜。下面是我如何处理同一个案例并修改名称以模仿您的类。换言之,把
1 2 3 4 5 6 7 8 9 | public static void SaveBook(Model.Book myBook) { using (var ctx = new BookDBContext()) { ctx.Books.Add(myBook); ctx.Entry(myBook).State = System.Data.Entity.EntityState.Modified; ctx.SaveChanges(); } } |
此代码是测试的结果,只更新一组列,而不进行首先返回记录的查询。它首先使用实体框架7代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | // This function receives an object type that can be a view model or an anonymous // object with the properties you want to change. // This is part of a repository for a Contacts object. public int Update(object entity) { var entityProperties = entity.GetType().GetProperties(); Contacts con = ToType(entity, typeof(Contacts)) as Contacts; if (con != null) { _context.Entry(con).State = EntityState.Modified; _context.Contacts.Attach(con); foreach (var ep in entityProperties) { // If the property is named Id, don't add it in the update. // It can be refactored to look in the annotations for a key // or any part named Id. if(ep.Name !="Id") _context.Entry(con).Property(ep.Name).IsModified = true; } } return _context.SaveChanges(); } public static object ToType<T>(object obj, T type) { // Create an instance of T type object object tmp = Activator.CreateInstance(Type.GetType(type.ToString())); // Loop through the properties of the object you want to convert foreach (PropertyInfo pi in obj.GetType().GetProperties()) { try { // Get the value of the property and try to assign it to the property of T type object tmp.GetType().GetProperty(pi.Name).SetValue(tmp, pi.GetValue(obj, null), null); } catch (Exception ex) { // Logging.Log.Error(ex); } } // Return the T type object: return tmp; } |
以下是完整的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | public interface IContactRepository { IEnumerable<Contacts> GetAllContats(); IEnumerable<Contacts> GetAllContactsWithAddress(); int Update(object c); } public class ContactRepository : IContactRepository { private ContactContext _context; public ContactRepository(ContactContext context) { _context = context; } public IEnumerable<Contacts> GetAllContats() { return _context.Contacts.OrderBy(c => c.FirstName).ToList(); } public IEnumerable<Contacts> GetAllContactsWithAddress() { return _context.Contacts .Include(c => c.Address) .OrderBy(c => c.FirstName).ToList(); } //TODO Change properties to lambda expression public int Update(object entity) { var entityProperties = entity.GetType().GetProperties(); Contacts con = ToType(entity, typeof(Contacts)) as Contacts; if (con != null) { _context.Entry(con).State = EntityState.Modified; _context.Contacts.Attach(con); foreach (var ep in entityProperties) { if(ep.Name !="Id") _context.Entry(con).Property(ep.Name).IsModified = true; } } return _context.SaveChanges(); } public static object ToType<T>(object obj, T type) { // Create an instance of T type object object tmp = Activator.CreateInstance(Type.GetType(type.ToString())); // Loop through the properties of the object you want to convert foreach (PropertyInfo pi in obj.GetType().GetProperties()) { try { // Get the value of the property and try to assign it to the property of T type object tmp.GetType().GetProperty(pi.Name).SetValue(tmp, pi.GetValue(obj, null), null); } catch (Exception ex) { // Logging.Log.Error(ex); } } // Return the T type object return tmp; } } public class Contacts { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } public string Company { get; set; } public string Title { get; set; } public Addresses Address { get; set; } } public class Addresses { [Key] public int Id { get; set; } public string AddressType { get; set; } public string StreetAddress { get; set; } public string City { get; set; } public State State { get; set; } public string PostalCode { get; set; } } public class ContactContext : DbContext { public DbSet<Addresses> Address { get; set; } public DbSet<Contacts> Contacts { get; set; } public DbSet<State> States { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var connString ="Server=YourServer;Database=ContactsDb;Trusted_Connection=True;MultipleActiveResultSets=true;"; optionsBuilder.UseSqlServer(connString); base.OnConfiguring(optionsBuilder); } } |
您应该使用。entry()方法,用于更新对象中的所有字段。还要记住,您不能更改字段ID(键),因此在编辑时,首先将ID设置为一些。
1 2 3 4 5 6 7 8 9 10 11 12 13 | using(var context = new ...()) { var EditedObj = context .Obj .Where(x => x. ....) .First(); NewObj.Id = EditedObj.Id; //This is important when we first create an object (NewObj), in which the default Id = 0. We can not change an existing key. context.Entry(EditedObj).CurrentValues.SetValues(NewObj); context.SaveChanges(); } |
这里是这个问题的最佳解决方案:在视图中添加所有ID(键)。考虑命名多个表(第一、第二和第三)
1 2 3 4 5 | @Html.HiddenFor(model=>model.FirstID) @Html.HiddenFor(model=>model.SecondID) @Html.HiddenFor(model=>model.Second.SecondID) @Html.HiddenFor(model=>model.Second.ThirdID) @Html.HiddenFor(model=>model.Second.Third.ThirdID) |
在C代码中,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | [HttpPost] public ActionResult Edit(First first) { if (ModelState.Isvalid) { if (first.FirstID > 0) { datacontext.Entry(first).State = EntityState.Modified; datacontext.Entry(first.Second).State = EntityState.Modified; datacontext.Entry(first.Second.Third).State = EntityState.Modified; } else { datacontext.First.Add(first); } datacontext.SaveChanges(); Return RedirectToAction("Index"); } return View(first); } |
1 2 3 4 5 6 7 8 9 10 11 12 | using(var myDb = new MyDbEntities()) { user user = new user(); user.username ="me"; user.email ="[email protected]"; myDb.Users.Add(user); myDb.users.Attach(user); myDb.Entry(user).State = EntityState.Modified;//this is for modiying/update existing entry myDb.SaveChanges(); } |
您应该删除
我找到了一个可行的方法。
1 2 3 4 5 6 | var Update = context.UpdateTables.Find(id); Update.Title = title; // Mark as Changed context.Entry(Update).State = System.Data.Entity.EntityState.Modified; context.SaveChanges(); |
试试吧…
更新模型(书);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | var book = new Model.Book { BookNumber = _book.BookNumber, BookName = _book.BookName, BookTitle = _book.BookTitle, }; using (var db = new MyContextDB()) { var result = db.Books.SingleOrDefault(b => b.BookNumber == bookNumber); if (result != null) { try { UpdateModel(book); db.Books.Attach(book); db.Entry(book).State = EntityState.Modified; db.SaveChanges(); } catch (Exception ex) { throw; } } } |
如果是实体框架6.2.0。
如果您有一个特定的
1 2 3 4 5 6 7 8 9 10 11 12 | var name = getNameFromService(); var current = _dbContext.Names.Find(name.BusinessSystemId, name.NameNo); if (current == null) { _dbContext.Names.Add(name); } else { _dbContext.Entry(current).CurrentValues.SetValues(name); } _dbContext.SaveChanges(); |
但是,这也可以用于具有单个主键或复合主键的通用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | var allNames = NameApiService.GetAllNames(); GenericAddOrUpdate(allNames,"BusinessSystemId","NameNo"); public virtual void GenericAddOrUpdate<T>(IEnumerable<T> values, params string[] keyValues) where T : class { foreach (var value in values) { try { var keyList = new List<object>(); //Get key values from T entity based on keyValues property foreach (var keyValue in keyValues) { var propertyInfo = value.GetType().GetProperty(keyValue); var propertyValue = propertyInfo.GetValue(value); keyList.Add(propertyValue); } GenericAddOrUpdateDbSet(keyList, value); //Only use this when debugging to catch save exceptions //_dbContext.SaveChanges(); } catch { throw; } } _dbContext.SaveChanges(); } public virtual void GenericAddOrUpdateDbSet<T>(List<object> keyList, T value) where T : class { //Get a DbSet of T type var someDbSet = Set(typeof(T)); //Check if any value exists with the key values var current = someDbSet.Find(keyList.ToArray()); if (current == null) { someDbSet.Add(value); } else { Entry(current).CurrentValues.SetValues(value); } } |
以下是我的RIA后实体更新方法(对于EF6时间框架):
1 2 3 4 5 6 7 8 9 10 11 12 13 | public static void UpdateSegment(ISegment data) { if (data == null) throw new ArgumentNullException("The expected Segment data is not here."); var context = GetContext(); var originalData = context.Segments.SingleOrDefault(i => i.SegmentId == data.SegmentId); if (originalData == null) throw new NullReferenceException("The expected original Segment data is not here."); FrameworkTypeUtility.SetProperties(data, originalData); context.SaveChanges(); } |
注意,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public static void SetProperties<TIn, TOut>(TIn input, TOut output, ICollection<string> includedProperties) where TIn : class where TOut : class { if ((input == null) || (output == null)) return; Type inType = input.GetType(); Type outType = output.GetType(); foreach (PropertyInfo info in inType.GetProperties()) { PropertyInfo outfo = ((info != null) && info.CanRead) ? outType.GetProperty(info.Name, info.PropertyType) : null; if (outfo != null && outfo.CanWrite && (outfo.PropertyType.Equals(info.PropertyType))) { if ((includedProperties != null) && includedProperties.Contains(info.Name)) outfo.SetValue(output, info.GetValue(input, null), null); else if (includedProperties == null) outfo.SetValue(output, info.GetValue(input, null), null); } } } |
如雷纳所说,删除:
此外,将结果查询更改为使用"asnotracking",因为此查询正在丢弃实体框架的模型状态。它认为"结果"就是现在要追踪的书,而你不想这样。
1 | var result = db.Books.AsNoTracking().SingleOrDefault(b => b.BookNumber == bookNumber); |
对于.NET内核
1 2 3 | context.Customer.Add(customer); context.Entry(customer).State = Microsoft.EntityFrameworkCore.EntityState.Modified; context.SaveChanges(); |
我知道已经回答了好几次了,但我喜欢下面的方法。我希望它能帮助别人。
1 2 3 4 5 6 7 8 | //attach object (search for row) TableName tn = _context.TableNames.Attach(new TableName { PK_COLUMN = YOUR_VALUE}); // set new value tn.COLUMN_NAME_TO_UPDATE = NEW_COLUMN_VALUE; // set column as modified _context.Entry<TableName>(tn).Property(tnp => tnp.COLUMN_NAME_TO_UPDATE).IsModified = true; // save change _context.SaveChanges(); |