นี่คือตาราง
ผู้ใช้
UserId
UserName
Password
EmailAddress
และรหัส ..
public void ChangePassword(int userId, string password){
//code to update the password..
}
นี่คือตาราง
ผู้ใช้
UserId
UserName
Password
EmailAddress
และรหัส ..
public void ChangePassword(int userId, string password){
//code to update the password..
}
คำตอบ:
คำตอบของ Ladislav ได้รับการอัพเดตเพื่อใช้ DbContext (แนะนำใน EF 4.1):
public void ChangePassword(int userId, string password)
{
var user = new User() { Id = userId, Password = password };
using (var db = new MyEfContextName())
{
db.Users.Attach(user);
db.Entry(user).Property(x => x.Password).IsModified = true;
db.SaveChanges();
}
}
db.Entry(user).Property(x => x.Password).IsModified = true;
และไม่db.Entry(user).Property("Password").IsModified = true;
db.Configuration.ValidateOnSaveEnabled = false;
คุณอาจต้องการตรวจสอบความถูกต้องของเขตข้อมูลที่คุณกำลังอัปเดต:if (db.Entry(user).Property(x => x.Password).GetValidationErrors().Count == 0)
คุณสามารถบอก EF ได้ว่าจะต้องปรับปรุงคุณสมบัติใดด้วยวิธีนี้:
public void ChangePassword(int userId, string password)
{
var user = new User { Id = userId, Password = password };
using (var context = new ObjectContext(ConnectionString))
{
var users = context.CreateObjectSet<User>();
users.Attach(user);
context.ObjectStateManager.GetObjectStateEntry(user)
.SetModifiedProperty("Password");
context.SaveChanges();
}
}
คุณมีสองตัวเลือกโดยทั่วไป:
userId
ให้ - วัตถุทั้งหมดได้รับการโหลดpassword
สนาม.SaveChanges()
วิธีการของบริบทในกรณีนี้มันขึ้นอยู่กับวิธีการจัดการรายละเอียดของ EF ฉันเพิ่งทดสอบสิ่งนี้และในกรณีที่ฉันเปลี่ยนเพียงฟิลด์เดียวของวัตถุสิ่งที่ EF สร้างขึ้นก็เป็นสิ่งที่คุณต้องการสร้างด้วยตนเองเช่นกัน:
`UPDATE dbo.Users SET Password = @Password WHERE UserId = @UserId`
ดังนั้น EF จึงฉลาดพอที่จะคิดได้ว่าคอลัมน์ใดมีการเปลี่ยนแปลงจริง ๆ และจะสร้างคำสั่ง T-SQL เพื่อจัดการเฉพาะการอัปเดตที่จำเป็นจริง ๆ
Password
คอลัมน์สำหรับสิ่งที่ให้UserId
และไม่มีอะไรอื่น - ดำเนินการโดยทั่วไปUPDATE dbo.Users SET Password = @Password WHERE UserId = @UserId
) และคุณสร้างการนำเข้าฟังก์ชั่นสำหรับโพรซีเดอร์ที่เก็บในโมเดล EF ของคุณ ฟังก์ชั่นแทนการทำตามขั้นตอนที่อธิบายไว้ข้างต้นใน Entity Framework Core ให้Attach
ส่งคืนรายการดังนั้นสิ่งที่คุณต้องการคือ:
var user = new User { Id = userId, Password = password };
db.Users.Attach(user).Property(x => x.Password).IsModified = true;
db.SaveChanges();
ฉันกำลังใช้สิ่งนี้:
นิติบุคคล:
public class Thing
{
[Key]
public int Id { get; set; }
public string Info { get; set; }
public string OtherStuff { get; set; }
}
dbcontext:
public class MyDataContext : DbContext
{
public DbSet<Thing > Things { get; set; }
}
รหัส accessor:
MyDataContext ctx = new MyDataContext();
// FIRST create a blank object
Thing thing = ctx.Things.Create();
// SECOND set the ID
thing.Id = id;
// THIRD attach the thing (id is not marked as modified)
db.Things.Attach(thing);
// FOURTH set the fields you want updated.
thing.OtherStuff = "only want this field updated.";
// FIFTH save that thing
db.SaveChanges();
ในขณะที่ค้นหาวิธีแก้ปัญหานี้ฉันพบความหลากหลายของคำตอบของ GONeale ผ่านบล็อกของ Patrick Desjardins :
public int Update(T entity, Expression<Func<T, object>>[] properties)
{
DatabaseContext.Entry(entity).State = EntityState.Unchanged;
foreach (var property in properties)
{
var propertyName = ExpressionHelper.GetExpressionText(property);
DatabaseContext.Entry(entity).Property(propertyName).IsModified = true;
}
return DatabaseContext.SaveChangesWithoutValidation();
}
" อย่างที่คุณเห็นมันใช้พารามิเตอร์ที่สองเป็นการแสดงออกของฟังก์ชั่นซึ่งจะช่วยให้ใช้วิธีนี้ได้โดยการระบุนิพจน์แลมบ์ดาซึ่งคุณสมบัติในการอัปเดต "
...Update(Model, d=>d.Name);
//or
...Update(Model, d=>d.Name, d=>d.SecondProperty, d=>d.AndSoOn);
(มีวิธีแก้ปัญหาที่ค่อนข้างคล้ายกันที่นี่: https://stackoverflow.com/a/5749469/2115384 )
วิธีการที่ผมใช้ในรหัสของตัวเอง , การขยายไปยังจัดการ (Linq) ExpressionType.Convert
นิพจน์ประเภท นี่เป็นสิ่งจำเป็นในกรณีของฉันเช่นกับGuid
และคุณสมบัติวัตถุอื่น ๆ เหล่านั้นถูก 'ห่อ' ในแปลง () System.Web.Mvc.ExpressionHelper.GetExpressionText
และดังนั้นจึงไม่จัดการโดย
public int Update(T entity, Expression<Func<T, object>>[] properties)
{
DbEntityEntry<T> entry = dataContext.Entry(entity);
entry.State = EntityState.Unchanged;
foreach (var property in properties)
{
string propertyName = "";
Expression bodyExpression = property.Body;
if (bodyExpression.NodeType == ExpressionType.Convert && bodyExpression is UnaryExpression)
{
Expression operand = ((UnaryExpression)property.Body).Operand;
propertyName = ((MemberExpression)operand).Member.Name;
}
else
{
propertyName = System.Web.Mvc.ExpressionHelper.GetExpressionText(property);
}
entry.Property(propertyName).IsModified = true;
}
dataContext.Configuration.ValidateOnSaveEnabled = false;
return dataContext.SaveChanges();
}
ฉันมาช้าไปที่เกม แต่นี่เป็นวิธีที่ฉันทำฉันใช้เวลาสักครู่เพื่อค้นหาวิธีการแก้ปัญหาที่ฉันพอใจ สิ่งนี้ก่อให้เกิดUPDATE
คำสั่งเฉพาะสำหรับเขตข้อมูลที่มีการเปลี่ยนแปลงตามที่คุณกำหนดสิ่งที่พวกเขาจะผ่านแนวคิด "รายการสีขาว" ซึ่งมีความปลอดภัยมากขึ้นเพื่อป้องกันการฉีดแบบฟอร์มบนเว็บ
ข้อความที่ตัดตอนมาจากที่เก็บข้อมูล ISession ของฉัน:
public bool Update<T>(T item, params string[] changedPropertyNames) where T
: class, new()
{
_context.Set<T>().Attach(item);
foreach (var propertyName in changedPropertyNames)
{
// If we can't find the property, this line wil throw an exception,
//which is good as we want to know about it
_context.Entry(item).Property(propertyName).IsModified = true;
}
return true;
}
สิ่งนี้สามารถห่อด้วยการลอง .. จับถ้าคุณต้องการ แต่ฉันส่วนตัวชอบโทรของฉันที่จะรู้เกี่ยวกับข้อยกเว้นในสถานการณ์นี้
มันจะถูกเรียกในลักษณะเช่นนี้ (สำหรับฉันนี่คือผ่าน ASP.NET Web API):
if (!session.Update(franchiseViewModel.Franchise, new[]
{
"Name",
"StartDate"
}))
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
UpdateModel
คำสั่งของ ASP.NET MVC ) วิธีการที่คุณมั่นใจได้ว่าการฉีดฟอร์มแฮ็กเกอร์ไม่สามารถเกิดขึ้นได้และพวกเขาไม่สามารถอัปเดตฟิลด์ต่างๆ หากใครบางคนสามารถแปลงอาร์เรย์สตริงเป็นพารามิเตอร์ของแลมบ์ดานิพจน์และทำงานกับมันได้ในสิ่งUpdate<T>
ที่ยอดเยี่ยม
var entity=_context.Set<T>().Attach(item);
ตามด้วยentity.Property(propertyName).IsModified = true;
ในลูปควรใช้งานได้
Entity Framework ติดตามการเปลี่ยนแปลงของคุณกับวัตถุที่คุณสอบถามจากฐานข้อมูลผ่าน DbContext ตัวอย่างเช่นถ้าคุณ DbContext ชื่ออินสแตนซ์คือ dbContext
public void ChangePassword(int userId, string password){
var user = dbContext.Users.FirstOrDefault(u=>u.UserId == userId);
user.password = password;
dbContext.SaveChanges();
}
ฉันรู้ว่านี่เป็นเธรดเก่า แต่ฉันก็กำลังมองหาโซลูชันที่คล้ายกันและตัดสินใจใช้โซลูชัน @ Doku ที่ให้มาด้วย ฉันแสดงความคิดเห็นเพื่อตอบคำถามที่ถามโดย @Imran Rizvi ฉันติดตาม @ Doku-so ลิงก์ที่แสดงการใช้งานที่คล้ายกัน คำถามของ @Imran Rizvi คือเขาได้รับข้อผิดพลาดโดยใช้โซลูชันที่ให้ไว้ 'ไม่สามารถแปลงนิพจน์แลมบ์ดาเป็นประเภท' Expression> [] 'เนื่องจากไม่ใช่ประเภทตัวแทน ฉันต้องการนำเสนอการแก้ไขเล็กน้อยที่ฉันทำกับโซลูชันของ @ Doku-so ที่แก้ไขข้อผิดพลาดนี้ในกรณีที่มีผู้อื่นมาโพสต์นี้และตัดสินใจที่จะใช้โซลูชันของ @ Doku-so
ปัญหาคืออาร์กิวเมนต์ที่สองในวิธีการอัพเดต
public int Update(T entity, Expression<Func<T, object>>[] properties).
เพื่อเรียกวิธีนี้โดยใช้ไวยากรณ์ที่ให้ไว้ ...
Update(Model, d=>d.Name, d=>d.SecondProperty, d=>d.AndSoOn);
คุณต้องเพิ่มคำหลัก 'params' ต่อหน้า arugment ที่สองด้วย
public int Update(T entity, params Expression<Func<T, object>>[] properties)
หรือถ้าคุณไม่ต้องการเปลี่ยนลายเซ็นของเมธอดจากนั้นจะเรียกเมธอด Update ที่คุณต้องเพิ่มคีย์เวิร์ด ' ใหม่ ' ระบุขนาดของอาเรย์จากนั้นใช้สุดท้ายคอลเลกชันวัตถุเริ่มต้นของไวยากรณ์สำหรับแต่ละคุณสมบัติเพื่ออัพเดตตามที่เห็น ด้านล่าง
Update(Model, new Expression<Func<T, object>>[3] { d=>d.Name }, { d=>d.SecondProperty }, { d=>d.AndSoOn });
ในตัวอย่างของ @ Doku-so เขากำลังระบุอาร์เรย์ของนิพจน์ดังนั้นคุณต้องผ่านคุณสมบัติเพื่ออัปเดตในอาร์เรย์เนื่องจากอาร์เรย์คุณต้องระบุขนาดของอาร์เรย์ด้วย เพื่อหลีกเลี่ยงปัญหานี้คุณสามารถเปลี่ยนอาร์กิวเมนต์ expression เพื่อใช้ IEnumerable แทน array
นี่คือการใช้งานโซลูชันของ @ Doku-so ของฉัน
public int Update<TEntity>(LcmsEntities dataContext, DbEntityEntry<TEntity> entityEntry, params Expression<Func<TEntity, object>>[] properties)
where TEntity: class
{
entityEntry.State = System.Data.Entity.EntityState.Unchanged;
properties.ToList()
.ForEach((property) =>
{
var propertyName = string.Empty;
var bodyExpression = property.Body;
if (bodyExpression.NodeType == ExpressionType.Convert
&& bodyExpression is UnaryExpression)
{
Expression operand = ((UnaryExpression)property.Body).Operand;
propertyName = ((MemberExpression)operand).Member.Name;
}
else
{
propertyName = System.Web.Mvc.ExpressionHelper.GetExpressionText(property);
}
entityEntry.Property(propertyName).IsModified = true;
});
dataContext.Configuration.ValidateOnSaveEnabled = false;
return dataContext.SaveChanges();
}
การใช้งาน:
this.Update<Contact>(context, context.Entry(modifiedContact), c => c.Active, c => c.ContactTypeId);
@ Doku- ให้วิธีการที่ยอดเยี่ยมในการใช้งานทั่วไปฉันใช้แนวคิดในการแก้ปัญหาของฉัน แต่คุณไม่สามารถใช้โซลูชันของ @ Doku-so ตามที่เป็นอยู่และในทั้งโพสต์นี้และโพสต์ที่เชื่อมโยงไม่มีใครตอบคำถามข้อผิดพลาดการใช้งาน
entityEntry.State = EntityState.Unchanged;
ค่าที่อัปเดตทั้งหมดในพารามิเตอร์entityEntry
รับการย้อนกลับดังนั้นจึงไม่มีการบันทึกการเปลี่ยนแปลงคุณช่วยได้โปรดขอบคุณ
ใน EntityFramework Core 2.x ไม่จำเป็นต้องมีAttach
:
// get a tracked entity
var entity = context.User.Find(userId);
entity.someProp = someValue;
// other property changes might come here
context.SaveChanges();
พยายามทำสิ่งนี้ใน SQL Server และทำโปรไฟล์:
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [User] SET [someProp] = @p0
WHERE [UserId] = @p1;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 bit',@p1=1223424,@p0=1
ค้นหาทำให้แน่ใจว่าเอนทิตีที่โหลดแล้วไม่ได้เรียกใช้ SELECT และยังแนบเอนทิตีโดยอัตโนมัติหากจำเป็น (จากเอกสาร):
/// Finds an entity with the given primary key values. If an entity with the given primary key values
/// is being tracked by the context, then it is returned immediately without making a request to the
/// database. Otherwise, a query is made to the database for an entity with the given primary key values
/// and this entity, if found, is attached to the context and returned. If no entity is found, then
/// null is returned.
การรวมคำแนะนำหลายข้อฉันขอเสนอดังต่อไปนี้
async Task<bool> UpdateDbEntryAsync<T>(T entity, params Expression<Func<T, object>>[] properties) where T : class
{
try
{
var entry = db.Entry(entity);
db.Set<T>().Attach(entity);
foreach (var property in properties)
entry.Property(property).IsModified = true;
await db.SaveChangesAsync();
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("UpdateDbEntryAsync exception: " + ex.Message);
return false;
}
}
เรียกโดย
UpdateDbEntryAsync(dbc, d => d.Property1);//, d => d.Property2, d => d.Property3, etc. etc.);
หรือโดย
await UpdateDbEntryAsync(dbc, d => d.Property1);
หรือโดย
bool b = UpdateDbEntryAsync(dbc, d => d.Property1).Result;
ฉันใช้ ValueInjecter
nuget เพื่อฉีด Binding Model ลงใน Entity ของฐานข้อมูลโดยใช้สิ่งต่อไปนี้
public async Task<IHttpActionResult> Add(CustomBindingModel model)
{
var entity= await db.MyEntities.FindAsync(model.Id);
if (entity== null) return NotFound();
entity.InjectFrom<NoNullsInjection>(model);
await db.SaveChangesAsync();
return Ok();
}
สังเกตการใช้งานของการประชุมที่กำหนดเองที่ไม่ได้ปรับปรุงคุณสมบัติถ้าพวกเขาเป็นโมฆะจากเซิร์ฟเวอร์
public class NoNullsInjection : LoopInjection
{
protected override void SetValue(object source, object target, PropertyInfo sp, PropertyInfo tp)
{
if (sp.GetValue(source) == null) return;
base.SetValue(source, target, sp, tp);
}
}
การใช้งาน:
target.InjectFrom<NoNullsInjection>(source);
ค้นหา คำตอบนี้
คุณจะไม่ทราบว่าทรัพย์สินถูกลบโดยเจตนาหรือไม่และไม่มีค่าใด ๆ กล่าวอีกนัยหนึ่งค่าคุณสมบัติสามารถถูกแทนที่ด้วยค่าอื่น แต่ไม่ได้เคลียร์
ฉันกำลังมองหาที่เดียวกันและในที่สุดก็พบทางออก
using (CString conn = new CString())
{
USER user = conn.USERs.Find(CMN.CurrentUser.ID);
user.PASSWORD = txtPass.Text;
conn.SaveChanges();
}
เชื่อฉันมันทำงานให้ฉันเหมือนมีเสน่ห์
นี่คือสิ่งที่ฉันใช้โดยใช้ InjectNonNull แบบกำหนดเอง (obj dest, obj src) ทำให้มีความยืดหยุ่นอย่างเต็มที่
[HttpPost]
public async Task<IActionResult> Post( [FromQuery]Models.Currency currency ) {
if ( ModelState.IsValid ) {
// find existing object by Key
Models.Currency currencyDest = context.Currencies.Find( currency.Id );
context.Currencies.Attach( currencyDest );
// update only not null fields
InjectNonNull( currencyDest, currency );
// save
await context.SaveChangesAsync( );
}
return Ok();
}
// Custom method
public static T InjectNonNull<T>( T dest, T src ) {
foreach ( var propertyPair in PropertyLister<T, T>.PropertyMap ) {
var fromValue = propertyPair.Item2.GetValue( src, null );
if ( fromValue != null && propertyPair.Item1.CanWrite ) {
propertyPair.Item1.SetValue( dest, fromValue, null );
}
}
return dest;
}
public async Task<bool> UpdateDbEntryAsync(TEntity entity, params Expression<Func<TEntity, object>>[] properties)
{
try
{
this.Context.Set<TEntity>().Attach(entity);
EntityEntry<TEntity> entry = this.Context.Entry(entity);
entry.State = EntityState.Modified;
foreach (var property in properties)
entry.Property(property).IsModified = true;
await this.Context.SaveChangesAsync();
return true;
}
catch (Exception ex)
{
throw ex;
}
}
public void ChangePassword(int userId, string password)
{
var user = new User{ Id = userId, Password = password };
using (var db = new DbContextName())
{
db.Entry(user).State = EntityState.Added;
db.SaveChanges();
}
}
Password
คุณหมายถึงรหัสผ่านแฮชใช่มั้ย? :-)