EF 4自定义存储库

时间:2011-11-18 15:39:28

标签: c# entity-framework architecture orm

这是我第一次使用EF,所以我可能会做一些愚蠢的事情。欢迎任何关于架构的评论。

所以我有典型的用户类。用户拥有用户名和角色列表:

 public class User
 {
     public string UserID{ get; set; }
     public List<Role> Roles { get; set; }
     public int Id { get; set; }
     public User()
     {
         Roles = new List<Role>();
     }
}

我的域对象与他们的存储库的接口一起存在于他们自己的代码库中。所以在这种情况下,会有一个IUserRepository包含所有CRUD方法以及我可能需要的任何专用数据访问方法。我要做的是在另一个类库中使用EF4实现这些存储库接口。到目前为止,这个设计有任何问题吗?

现在在db(sql server)中我有一些典型的表:用户,角色和多对多表将用户映射到角色UsersRoles。

我已经在EF lib中成功设置了大多数CRUD方法。这是Save的样子

public void Save(Drc.Domain.Entities.Staff.User member)
    {
        using (var ctx = new DrcDataContext())
        {
            var efUser = MapFromDomainObject(member);
            if(member.Id < 1)
            {                    
                ctx.Users.AddObject(efUser);                    
            }
            else
            {                             
                ctx.Users.Attach(efUser);
                ctx.ObjectStateManager.ChangeObjectState(efUser, EntityState.Modified);
            }          
            ctx.SaveChanges();
            member.Id = efUser.UserId;                
        }            
    }

现在我不确定这是否是实现这一目标的正确方法,但它确实有效。但是,在执行删除时遇到问题。问题在于相关表格

public void Delete(Drc.Domain.Entities.Staff.User member)
    {
        using (var ctx = new DrcDataContext())
        {
            var efUser = MapFromDomainObject(member);    ctx.Users.Attach(efUser);
            while (efUser.Roles.Count > 0)
            {
                ctx.ObjectStateManager.ChangeObjectState(efUser.Roles.First(), EntityState.Deleted);
            }                        
            ctx.SaveChanges();
            ctx.ObjectStateManager.ChangeObjectState(efUser, EntityState.Deleted);
            ctx.SaveChanges();
        }
    }

如果我不删除while循环中的角色,则会出现与引用约束错误的DELETE冲突。如果我运行上面的代码,它确实删除了多对多表中的正确行,但它也删除了Roles表中的行。我现在处于死胡同,正在考虑抓住ORM的想法并将我的存储库实现编写在良好可靠的ADO.net中。

- 编辑我猜这不是用EF实现存储库的正确方法。是不是可以不用乱扔垃圾的东西乱扔你的域名?

1 个答案:

答案 0 :(得分:0)

简单地使用标准方法,不要乱用实体状态:

public void Delete(Drc.Domain.Entities.Staff.User member)
{
    using (var ctx = new DrcDataContext())
    {
        var efUser = MapFromDomainObject(member);
        ctx.Users.Attach(efUser);
        ctx.Users.DeleteObject(efUser);
        ctx.SaveChanges();
    }
}

数据库中从User表到连接表通常会有级联删除(如果你没有手动禁用它)。因此,删除用户也将删除连接表中的相应行(当然不是角色)。

将实体的状态设置为Deleted与调用DeleteObject不同。它只会将父项设置为已删除,并将子项保留在上下文中的未删除状态,从而导致约束违例异常。 DeleteObject还会将上下文中的孩子标记为Deleted,从而避免例外。