2011-01-30 69 views
1

这里有大量的信息,但即使在阅读了几个小时和几个小时之后,我似乎也无法按照我想要的方式工作。Linq to Sql - 如何使用存储库模式更新对象?

我试图更新一个用户对象,通过传递一个用户对象,并一般地比较用户对象的变化,我拉出数据库。我总是最后使用此方法时得到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对象的所有更改。

我也对乐观并发做了一些阅读,并在数据类型时间戳表中添加了一列,但这似乎也没有任何影响。

我究竟在做什么错在这里?

我怎样才能得到这个一般性地检测到什么已经改变,并正确地坚持对数据库的更改?

回答

2

我的猜测是有一个外键关系,你试图复制,最初没有加载(因为延迟加载)在复制过程中,它试图加载它,但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配置是一样的东西

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

你可以在这里找到AutoMapper:http://automapper.codeplex.com/

+0

这看起来不错,但我建议使用`SubmitChanges()`作为自己的方法。通过这种方式,您可以在提交数据之前堆积几个数据库调用。 – 2011-01-30 00:23:56

+0

是的,我完全同意SubmitChanges()它自己的方法。以上只是该模式的快速伪代码。我也会让我的资源库将通用方法暴露给服务层。如果@Sgraffite愿意,我可以扩展更多。 – mfanto 2011-01-30 00:45:13

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(); 
相关问题