2

有很多关于这方面的信息,但即使在阅读了几个小时之后,我似乎也无法让它按照我想要的方式工作。

我试图通过传入一个用户对象来更新一个用户对象,并一般比较我从数据库中提取的用户对象的更改。使用此方法时,我总是最终得到 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

我的仓库非常精简,唯一的工作就是与数据库交互。我在 repo 之上构建了一个服务层,它做了更多的工作

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 回答