2

これにはたくさんの情報がありますが、何時間も読んだ後でも、思い通りに動作させることができないようです。

User オブジェクトを渡し、データベースから取り出した User オブジェクトへの変更を一般的に比較することで、User オブジェクトを更新しようとしています。このメソッドを使用すると、常に NotSupportedException が発生します。

別の DataContext から読み込まれた可能性がある、新しくないエンティティをアタッチまたは追加しようとしました。これはサポートされていません。

これが私がそれをやろうとしている方法です:

    public void SaveUser(User User)
    {
        using (DataContext dataContext = new DataContext(WebConfigurationManager.ConnectionStrings["database"].ConnectionString))
        {
            // New user
            if (User.UserID == 0)
            {
                dataContext.Users.InsertOnSubmit(User);
            }
            // Existing user
            else
            {
                User dbUser = dataContext.Users.Single(u => u.UserID.Equals(User.UserID));
                Type t = dbUser.GetType();
                foreach (PropertyInfo p in t.GetProperties())
                {
                    if (p.CanWrite & p.GetValue(dbUser, null) != p.GetValue(User, null))
                    {
                        p.SetValue(dbUser, p.GetValue(User, null), null);
                    }
                }
                //dataContext.Refresh(RefreshMode.KeepCurrentValues, dbUser);
            }
            dataContext.SubmitChanges();
        }
    }

私が試したコメントアウトされた行もコメント解除しましたが、それは助けにはなりませんでした。

foreach() ループをコメントアウトして、dbUser.UserName = "Cheese"; のような行を追加するとします。データベース内のユーザー名を正常に更新します。これは、 foreach() ループが dbUser オブジェクトを変更してこれが失敗する原因であると私は信じています。

dbUser オブジェクトをデバッグすると、引数として渡された User オブジェクトからすべての変更が正しく取得されているように見えます。

オプティミスティック コンカレンシーについても調べて、タイムスタンプ データ型のテーブルに列を追加しましたが、効果もないようです。

ここで私は正確に何を間違っていますか?

何が変更されたかを一般的に検出し、データベースへの変更を正しく永続化するにはどうすればよいですか?

4

2 に答える 2

3

私の推測では、(遅延読み込みのため) 最初に読み込まれなかった、コピーしようとしている外部キー関係があると思います。コピー中に、それを読み込もうとしていますが、DataContext は既に破棄されています。

私は同様の問題に取り組んできました。プロパティのコピーを処理するために AutoMapper を使用することになりました。主キー フィールドと関係を無視するように AutoMapper を構成しました。何かのようなもの:

public void Update(User user)
{
     using (var db = new DataContext(...))
     {
         var userFromDb = db.Users.Where(x => x.Id == user.Id).Single();
         AutoMapper.Mapper.Map(user, userFromDb);
         db.SubmitChanges();
    }
}

私のオートマッパー構成は次のようなものです

AutoMapper.Mapper.Create<User, User>().ForMember(dest => dest.Id, opt => opt.Ignore())
                                      .ForMember(dest => dest.SomeRelation, opt => opt.Ignore());

ここで AutoMapper を見つけることができます: http://automapper.codeplex.com/

于 2011-01-30T00:17:15.663 に答える
0

私は自分のレポをかなりスリムに保ちます。唯一の仕事はデータベースとやり取りすることです。もう少し作業を行うレポの上にサービスレイヤーを構築します

public class EventRepository : IEventRepository
{

    private DBDataContext dc;
    public EventRepository()
    {
        dc = new DBDataContext();
    }

    public void Create(Event @event)
    {
        dc.Events.InsertOnSubmit(@event);
    }

    public System.Linq.IQueryable<Event> Read()
    {
        object events = (from e in dc.Eventse);
        return events.AsQueryable;
    }

    public void SubmitChanges()
    {
        dc.SubmitChanges();
    }

}

次に、サービス層からの対応する呼び出しは次のようになります

public void AddEvent(Event @event)
{
    _EventRepository.Create(@event);
}

public void SubmitChanges()
{
    _EventRepository.SubmitChanges();
}

そして、コントローラーから呼び出します。

// AutoMapper will allow us to map the ViewModel with the DomainModel
Mapper.CreateMap<Domain.ViewModels.EventsAddViewModel, Domain.Event>();
object @event = Mapper.Map<Domain.ViewModels.EventsAddViewModel, Domain.Event>(eventToAdd);

// Add the event to the database
EventService.AddEvent(@event);
EventService.SubmitChanges();
于 2011-01-30T00:29:43.843 に答える