Entity Framework 6을 사용하여 레코드를 업데이트하는 방법은 무엇입니까?
EF6을 사용하여 레코드를 업데이트하려고합니다. 먼저 레코드를 찾으면 업데이트하십시오. 내 코드는 다음과 같습니다.
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 : 저장 업데이트, 삽입 또는 삭제 명령문이 예상치 않은 행 수 (0)에 영향을 미쳤습니다. 엔터티가로드 된 후 엔터티가 수정되거나 삭제되었을 수 있습니다. ObjectStateManager 항목 새로 고침
레코드를 업데이트하려고합니다 ( "기존 레코드의 값을 변경하고 다시 저장하십시오"라는 의미). 따라서 오브젝트를 검색하고 변경 한 후 저장해야합니다.
using (var db = new MyContextDB())
{
var result = db.Books.SingleOrDefault(b => b.BookNumber == bookNumber);
if (result != null)
{
result.SomeValue = "Some new value";
db.SaveChanges();
}
}
Entity Framework의 소스 코드를 검토하고 Key 속성을 알고 있으면 실제로 엔티티를 업데이트하는 방법을 찾았습니다.
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);
}
그렇지 않으면 AddOrUpdate 구현에서 아이디어를 확인하십시오 .
이 도움을 바랍니다!
다음 AddOrUpdate
방법을 사용할 수 있습니다 .
db.Books.AddOrUpdate(book); //requires using System.Data.Entity.Migrations;
db.SaveChanges();
따라서 업데이트 된 엔티티가 있으며 가장 적은 양의 코드로 데이터베이스에서 업데이트하려고합니다 ...
동시성은 항상 까다 롭지 만 업데이트를 받기를 원한다고 가정합니다. 다음은 동일한 사례에 대해 수행하고 클래스를 모방하기 위해 이름을 수정 한 방법입니다. 즉,로 변경 attach
하면 add
나를 위해 작동합니다.
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();
}
}
이 코드는 쿼리에서 레코드를 먼저 반환하지 않고 열 집합 만 업데이트하는 테스트 결과입니다. 먼저 Entity Framework 7 코드를 사용합니다.
// 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;
}
다음은 완전한 코드입니다.
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를 편집 한 것과 동일하게 설정하십시오.
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();
}
.net 코어
context.Customer.Add(customer);
context.Entry(customer).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
context.SaveChanges();
이 문제에 대한 최상의 해결책은 다음과 같습니다.보기에서 모든 ID (키)를 추가하십시오. 이름이 여러 개인 테이블 (첫 번째, 두 번째 및 세 번째)을 고려하십시오.
@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 # 코드에서
[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);
}
using(var myDb = new MyDbEntities())
{
user user = new user();
user.username = "me";
user.email = "me@me.com";
myDb.Users.Add(user);
myDb.users.Attach(user);
myDb.Entry(user).State = EntityState.Modified;//this is for modiying/update existing entry
myDb.SaveChanges();
}
제거해야합니다 db.Books.Attach(book);
잘 작동하는 방법을 찾았습니다.
var Update = context.UpdateTables.Find(id);
Update.Title = title;
// Mark as Changed
context.Entry(Update).State = System.Data.Entity.EntityState.Modified;
context.SaveChanges();
Attach
엔티티를 추적하면 추적 상태가로 설정됩니다 Unchanged
. 기존 엔터티를 업데이트하려면 추적 상태를로 설정하면됩니다 Modified
. EF6 문서 에 따르면 :
데이터베이스에 이미 존재하지만 변경이 이루어진 엔티티가있는 경우 컨텍스트에 엔티티를 첨부하고 상태를 수정 됨으로 설정할 수 있습니다. 예를 들면 다음과 같습니다.
var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" }; using (var context = new BloggingContext()) { context.Entry(existingBlog).State = EntityState.Modified; // Do some more work... context.SaveChanges(); }
다음은 Post-RIA 엔티티 업데이트 방법입니다 (Ef6 시간대).
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();
}
참고 FrameworkTypeUtility.SetProperties()
내가 NuGet에 AutoMapper 오래 전에 쓴 작은 유틸리티 기능은 다음과 같습니다
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);
}
}
}
Renat가 말했듯이 다음을 제거하십시오. db.Books.Attach(book);
또한이 쿼리는 엔터티 프레임 워크의 모델 상태를 무시하므로 "AsNoTracking"을 사용하도록 결과 쿼리를 변경하십시오. "결과"는 지금 추적 할 책이라고 생각하며 원하지 않습니다.
var result = db.Books.AsNoTracking().SingleOrDefault(b => b.BookNumber == bookNumber);
시도 해봐....
UpdateModel (책);
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;
}
}
}
이것은 Entity Framework 6.2.0의 경우입니다.
특정 DbSet
항목과 업데이트 또는 생성해야하는 항목이있는 경우 :
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();
그러나 DbSet
단일 기본 키 또는 복합 기본 키가 있는 일반에도 사용할 수 있습니다 .
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);
}
}
나는 그것이 이미 몇 번 잘 대답했다는 것을 알고 있지만, 나는 이것을하는 방법을 좋아합니다. 누군가에게 도움이되기를 바랍니다.
//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();
참고 URL : https://stackoverflow.com/questions/25894587/how-to-update-record-using-entity-framework-6
'IT story' 카테고리의 다른 글
Rails에서 모델의 테이블 이름 매핑을 명시 적으로 어떻게 지정합니까? (0) | 2020.04.23 |
---|---|
composer의 버전과 함께 설치된 모든 패키지 목록을 얻는 방법은 무엇입니까? (0) | 2020.04.23 |
파이썬에서리스트를 특정 길이로 초기화 (0) | 2020.04.23 |
페이지가로드 될 때 기능을 실행하는 방법은 무엇입니까? (0) | 2020.04.23 |
SQL Server에 "LIKE"와 "IN"결합 (0) | 2020.04.23 |