これがテーブルです
ユーザー
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..
}
DbContext(EF 4.1で導入)を使用するように更新されたLadislavの回答:
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();
}
}
次の方法で、どのプロパティを更新する必要があるかを 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();
}
}
Entity Framework Core ではAttach
、エントリを返すため、必要なのは次のとおりです。
var user = new User { Id = userId, Password = password };
db.Users.Attach(user).Property(x => x.Password).IsModified = true;
db.SaveChanges();
基本的に 2 つのオプションがあります。
userId
- オブジェクト全体がロードされますpassword
フィールドを更新する.SaveChanges()
メソッドを使用してオブジェクトを保存しますこの場合、これを詳細に処理する方法は EF 次第です。これをテストしたところ、オブジェクトの 1 つのフィールドのみを変更した場合、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モデルでそのストアドプロシージャの関数インポートを作成し、これを呼び出します上記の手順を実行する代わりに機能します私はこれを使用しています:
実在物:
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();
私はここでゲームに遅れていますが、これが私がやっている方法です。私は満足できる解決策を探すのにしばらく費やしました。これは、UPDATE
変更されたフィールドに対してのみステートメントを生成します。これは、とにかく Web フォーム インジェクションを防ぐためにより安全な「ホワイト リスト」の概念を使用してそれらが何であるかを明示的に定義するためです。
私の 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;
}
必要に応じて、これを try..catch でラップすることもできますが、個人的には、呼び出し元にこのシナリオの例外について知ってもらいたいと思っています。
次のような方法で呼び出されます (私にとっては、これは ASP.NET Web API 経由でした)。
if (!session.Update(franchiseViewModel.Franchise, new[]
{
"Name",
"StartDate"
}))
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
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
Find は、既に読み込まれているエンティティが 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.
エンティティ フレームワークは、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-so が提供するソリューションを使用することにしました。@Imran Rizvi からの質問に答えるためにコメントしています。同様の実装を示す @Doku-so リンクをたどりました。@Imran Rizvi の質問は、提供されたソリューション 'Cannot convert Lambda expression to Type 'Expression> [] ' because it is not a delegate type'' を使用してエラーが発生したというものでした。他の誰かがこの投稿に出くわし、@ Doku-so のソリューションを使用することにした場合に備えて、このエラーを修正する @ Doku-so のソリューションに行った小さな変更を提供したいと思いました。
問題は、Update メソッドの 2 番目の引数です。
public int Update(T entity, Expression<Func<T, object>>[] properties).
提供された構文を使用してこのメソッドを呼び出すには...
Update(Model, d=>d.Name, d=>d.SecondProperty, d=>d.AndSoOn);
そのため、2 番目の引数の前に「params」キーワードを追加する必要があります。
public int Update(T entity, params Expression<Func<T, object>>[] properties)
または、メソッド シグネチャを変更したくない場合は、Update メソッドを呼び出すには、' new ' キーワードを追加し、配列のサイズを指定してから、最後に各プロパティのコレクション オブジェクト初期化構文を使用して、表示どおりに更新する必要があります。下。
Update(Model, new Expression<Func<T, object>>[3] { d=>d.Name }, { d=>d.SecondProperty }, { d=>d.AndSoOn });
@Doku-so の例では、式の配列を指定しているため、更新するプロパティを配列で渡す必要があります。配列のため、配列のサイズも指定する必要があります。これを回避するには、配列の代わりに IEnumerable を使用するように式の引数を変更することもできます。
これが@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-so はジェネリックを使用したクールなアプローチを提供しました。私はこの概念を使用して問題を解決しましたが、@Doku-so のソリューションをそのまま使用することはできず、この投稿とリンクされた投稿の両方で、使用エラーの質問に誰も答えませんでした。