উত্তর:
লাডিসালভের উত্তর 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 যথেষ্ট স্মার্ট এবং এটি প্রয়োজনীয় এমন যে কেবল আপডেটগুলি পরিচালনা করতে এটি একটি টি-এসকিউএল বিবৃতি তৈরি করবে।
Password
প্রদত্ত জন্য কলামটি আপডেট করুন UserId
এবং অন্য কিছুই নয় - মূলত সঞ্চালিত হয় UPDATE dbo.Users SET Password = @Password WHERE UserId = @UserId
) এবং আপনি আপনার EF মডেলের সেই সঞ্চিত পদ্ধতির জন্য একটি ফাংশন আমদানি তৈরি করেন এবং আপনি এটি কল করেন উপরে বর্ণিত পদক্ষেপগুলি না করে ফাংশন করুনসত্তা ফ্রেমওয়ার্ক কোর ইন, 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; }
}
অ্যাক্সেসর কোড:
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();
এই সমস্যার সমাধান অনুসন্ধান করার সময়, প্যাট্রিক দেসজার্ডিন্স ব্লগের মাধ্যমে গনিয়েলের উত্তরে আমি একটি ভিন্নতা পেয়েছি :
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();
}
" আপনি দেখতে পাচ্ছেন যে এটির দ্বিতীয় পরামিতিটি কোনও ক্রিয়াকলাপের একটি অভিব্যক্তি হিসাবে লাগে This এটি লাম্বডা এক্সপ্রেশনটিতে নির্দিষ্ট করে কোন সম্পত্তি আপডেট করতে হবে তা নির্দিষ্ট করে এই পদ্ধতিটি ব্যবহার করবে " "
...Update(Model, d=>d.Name);
//or
...Update(Model, d=>d.Name, d=>d.SecondProperty, d=>d.AndSoOn);
(কিছুটা অনুরূপ সমাধান এখানেও দেওয়া হয়েছে: https://stackoverflow.com/a/5749469/2115384 )
আমি বর্তমানে নিজের কোডটিতে যে পদ্ধতিটি ব্যবহার করছি তা হ্যান্ডেল করার জন্যও প্রসারিত (লিঙ্ক) প্রকারের এক্সপ্রেশন 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
পরিবর্তিত ক্ষেত্রগুলির জন্য এটি কেবলমাত্র বিবৃতি , যেমন আপনি একটি "সাদা তালিকা" ধারণার মাধ্যমে যা স্পষ্টভাবে তা সংজ্ঞায়িত করেন যা যাইহোক ওয়েব ফর্ম ইঞ্জেকশন রোধ করতে আরও সুরক্ষিত।
আমার আইসেশন ডেটা সংগ্রহস্থলের একটি অংশ:
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;
}
এটি একটি চেষ্টাতে আবৃত হতে পারে .c আপনি চাইলে ধরুন, তবে আমি ব্যক্তিগতভাবে আমার কলারটিকে এই দৃশ্যের ব্যতিক্রমগুলি সম্পর্কে জানতে পছন্দ করি।
এটি এই ফ্যাশন মত কিছু বলা হবে (আমার জন্য, এটি একটি ASP.NET ওয়েব API এর মাধ্যমে ছিল):
if (!session.Update(franchiseViewModel.Franchise, new[]
{
"Name",
"StartDate"
}))
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
UpdateModel
কমান্ডের জন্য প্রয়োজনীয় সাদা তালিকার মতো ), আপনি নিশ্চিত হন যে হ্যাকার ফর্ম ইঞ্জেকশনটি ঘটতে পারে না এবং তারা ক্ষেত্রগুলি আপডেট করতে পারে না যেগুলি আপডেট করার অনুমতি নেই are তবে যদি কেউ স্ট্রিং অ্যারেটিকে কোনও ধরণের ল্যাম্বডা এক্সপ্রেশন প্যারামিটারে রূপান্তর করতে পারে এবং এর সাথে Update<T>
দুর্দান্ত কাজ করতে পারে
var entity=_context.Set<T>().Attach(item);
অনুসৃত দ্বারা entity.Property(propertyName).IsModified = true;
লুপ কাজ করা উচিত।
সত্তা কাঠামো ডিবিটি কনটেক্সট দ্বারা ডেটাবেস থেকে জিজ্ঞাসা করা বস্তুগুলিতে আপনার পরিবর্তনগুলি ট্র্যাক করে। উদাহরণস্বরূপ, আপনি যদি DbContext উদাহরণের নাম dbContext হয়
public void ChangePassword(int userId, string password){
var user = dbContext.Users.FirstOrDefault(u=>u.UserId == userId);
user.password = password;
dbContext.SaveChanges();
}
আমি জানি এটি একটি পুরানো থ্রেড তবে আমিও অনুরূপ সমাধান খুঁজছিলাম এবং ঠিক করলাম @ ডোকু-যেমন সরবরাহিত সমাধানটি নিয়ে যাব। আমি ইমরান রিজভীর জিজ্ঞাসা করা প্রশ্নের উত্তর দিতে আমি মন্তব্য করছি, আমি @ ডোকু-সো লিঙ্কটি অনুসরণ করেছি যা একই রকম বাস্তবায়ন দেখায়। @ ইমরান রিজভীর প্রশ্ন ছিল যে প্রদত্ত সমাধানটি 'লাম্বডা এক্সপ্রেশনটিকে টাইপ' এক্সপ্রেশন> [] 'তে রূপান্তর করতে পারবেন না কারণ এটি কোনও প্রতিনিধি প্রকার নয় using আমি @ ডকু-সো এর সমাধানটিতে একটি ছোট্ট পরিবর্তন চাইছিলাম যা এই ত্রুটিটি ঠিক করে যদি অন্য কেউ এই পোস্ট জুড়ে আসে এবং @ ডোকু-এর সমাধানটি ব্যবহার করার সিদ্ধান্ত নেয়।
সমস্যাটি আপডেট পদ্ধতিতে দ্বিতীয় যুক্তি,
public int Update(T entity, Expression<Func<T, object>>[] properties).
প্রদত্ত সিনট্যাক্স ব্যবহার করে এই পদ্ধতিটি কল করতে ...
Update(Model, d=>d.Name, d=>d.SecondProperty, d=>d.AndSoOn);
দ্বিতীয় তর্কের সামনে আপনাকে অবশ্যই 'প্যারামস' কীওয়ার্ডটি যুক্ত করতে হবে।
public int Update(T entity, params Expression<Func<T, object>>[] properties)
অথবা আপনি যদি পদ্ধতিটির স্বাক্ষর পরিবর্তন করতে না চান তবে আপডেট পদ্ধতিটি কল করার জন্য আপনাকে যুক্ত করতে হবে ' নতুন ' কীওয়ার্ড যুক্ত করতে হবে, অ্যারের আকার নির্দিষ্ট করতে হবে, তবে শেষ পর্যন্ত প্রতিটি সম্পত্তি হিসাবে দেখা হিসাবে আপডেট করার জন্য সংগ্রহ অবজেক্ট ইনিশিয়ালাইজার সিনট্যাক্সটি ব্যবহার করুন নিচে.
Update(Model, new Expression<Func<T, object>>[3] { d=>d.Name }, { d=>d.SecondProperty }, { d=>d.AndSoOn });
@ ডোকু-এর উদাহরণে তিনি এক্সপ্রেশনগুলির একটি অ্যারে নির্দিষ্ট করে দিচ্ছেন যাতে আপনাকে অ্যারে আপডেট করার জন্য বৈশিষ্ট্যগুলি পাস করতে হবে কারণ অ্যারের কারণে আপনাকে অবশ্যই অ্যারের আকারও নির্দিষ্ট করতে হবে। এটি এড়ানোর জন্য আপনি অ্যারের পরিবর্তে আইনিম্যারেবল ব্যবহার করতে অভিব্যক্তি যুক্তিটিও পরিবর্তন করতে পারেন।
এখানে আমার @ ডকু-এর সমাধানের বাস্তবায়ন।
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);
@ ডোকু তাই জেনেরিকটি ব্যবহার করে একটি দুর্দান্ত দৃষ্টিভঙ্গি সরবরাহ করেছিল, আমি আমার সমস্যাটি সমাধান করার জন্য ধারণাটি ব্যবহার করেছি তবে আপনি কেবলমাত্র ডোকু-সলিউশনটি ব্যবহার করতে পারবেন না এবং এই পোস্ট এবং লিঙ্কযুক্ত পোস্টে ব্যবহার ত্রুটির প্রশ্নের উত্তর কেউই দেয়নি।
entityEntry.State = EntityState.Unchanged;
প্যারামিটারের সমস্ত আপডেট হওয়া মানগুলি entityEntry
অ্যান্টিটি ফ্রেমওয়ার্ক কোর ২.x এ কোনও প্রয়োজন নেই Attach
:
// get a tracked entity
var entity = context.User.Find(userId);
entity.someProp = someValue;
// other property changes might come here
context.SaveChanges();
এসকিউএল সার্ভারে এটি চেষ্টা করে এবং এটি প্রোফাইলিং:
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
অনুসন্ধানটি নিশ্চিত করে যে ইতিমধ্যে লোড হওয়া সত্তাগুলি কোনও নির্বাচনকে ট্রিগার না করে এবং প্রয়োজনে স্বয়ংক্রিয়ভাবে সত্তাকে সংযুক্ত করে (ডক্স থেকে):
/// 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
নিম্নলিখিত ব্যবহার করে ডাটাবেস সত্তায় বাইন্ডিং মডেলকে ইনজেক্ট করতে নুগেট ব্যবহার করি :
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();
}
বিশ্বাস করুন এটি আমার জন্য কবজির মতো কাজ করে।
এটি আমি কাস্টম ইনজেক্টননল (ওজেক্ট ডেস্ট, ওজেক্ট এসসিআর) ব্যবহার করে এটি এটিকে সম্পূর্ণ নমনীয় করে তুলি
[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
, আপনি মানে পাসওয়ার্ড হ্যাশ মানে, তাই না? :-)