放置方法的位置(实体或回购)

时间:2015-02-17 11:53:43

标签: c# entity-framework asp.net-mvc-3 oop design-patterns

我有两个EF生成的类。

public partial class admin
{
    public admin()
    {
        this.user = new HashSet<user>();
    }
    public int id { get; set; }//PK
    //Other properties omitted for brevity
    public virtual ICollection<user> user { get; set; }
}

public partial class user
{  
    public string username { get; set; }//PK
    public string passwd { get; set; }
    public int admin_id { get; set; }//FK
    //Other properties omitted for brevity
    public virtual admin admin { get; set; }
}

用户使用FK admin_id属于管理员。如果admin_id和username相等,则用户是admin。例如:用户&#39; Messi&#39;,&#39; Neymar&#39;,&#39; Suarez&#39; &安培; &#39; 123&#39;所有人都有admin_id 123.所以用户&#39; 123&#39;是管理员。 (也许不是最好的方法,但这与问题无关。)

由于这两个类是EF自动生成的,并且将来可以更改,我有另一个具有相同命名空间但在不同文件夹中的部分用户类(因此方法保持不变):

public partial class user
{
    public bool isAdmin()
    {
        return admin_id.ToString().Equals(username);
    }
}

我也有这个用户存储库:

public class EFUserRepo : IUserRepo
{
    private Entities context = new Entities();
    public IQueryable<user> Users { get { return context.user; } }
    public user getUserByPK(string username)
    { 
        return context.user.Find(username);
    }
    public user deleteUser(string username){ return null; }//Yet to implement
    public bool saveUser(user user){ return false; }//Yet to implement
}

我想制作另一种方法来获取给定用户的useradmin,如下所示:

public user getUserAdmin(string username){ }//Note the return type is user, not admin!



我的问题是,我在哪里放这个方法? 我可以把它放在EFUserRepo中:

public user getUserAdmin(string username)
{
    user user = getUserByPK(username);
    if (user == null) return null;
    return context.user.Find(user.admin_id);            
}

public user getUserAdmin(user user)//Not relevant for question, but might be insightful for others
{
    return getUserAdmin(user.username);
}

在我的控制器中称之为:

user adminUser = repo.getUserAdmin(loggedOnUser.username);//or use repo.getUserAdmin(loggedOnUser) for same result.

或者我可以把它放在像这样的部分用户类中:

public user getUserAdmin()
{
    return this.admin.user.Where(x => x.isAdmin()).FirstOrDefault();
    //Due to DB setup always returns 1 user.
}

在我的控制器中称之为:

user adminUser = loggedOnUser.getUserAdmin();



我绝对不知道什么是最好的方法 如果我还想制作一个类似的方法怎么办?

public admin getAdmin(string username){ }//Note the return type is admin here, not user

然后我可以将它添加到我的用户存储库:

public admin getAdmin(string username)
{
    user user = getUserByPK(username);
    if (user == null) return null;
    return user.admin;
    //return context.admin.Find(user.admin_id);//Also works, but is it best practise to access the admin collection from within the userrepo, think not
    //return new EFAdminRepo().getAdminByPK(user.admin_id)//Also works, but seams really ugly
}

public admin getAdmin(user user)//Again, not relevant for question, but might be insightful for others
{
    return getAdmin(user.username);
}

在我的控制器中称之为:

admin admin = repo.getAdmin(loggedOnUser.username);//or use repo.getAdmin(loggedOnUser) for same result.

或者我可以把它放在像这样的部分用户类中:

public admin getAdmin()
{
    return this.admin.user.Where(x => x.isAdmin()).First().admin;
}

在我的控制器中称之为:

admin admin = loggedOnUser.getAdmin();



真正的问题可能是,我使用

ObjectX obj = repo.methodForObtainingObjectX(entity.params);

ObjectX obj = entity.methodForObtainingObjectX();

3 个答案:

答案 0 :(得分:2)

首先,这是一个名称作为主键吗?帮自己一个忙:立即摆脱那种憎恶。一旦你说服自己没关系,你就会遇到一个情况,那就是有两个Joe Smith,或者Jane Doe会结婚,你会想要修改她的名字字段,而不能因为它是一把钥匙。只需给自己另一个int字段作为密钥,每条记录只需几个字节,并且总是正确的。

所以,不要让人们告诉你不要在模型类中添加任何逻辑,除了数据库或导航属性中的字段。模型一直代表IsAdmin之类的简单事物,而不必求助于单独的类。只需打上[NotMapped]就可以了。你很高兴。

关于在逻辑变得更复杂时放置这些方法的位置,我问自己这个问题:该方法有多大可能产生另一次数据库之旅(并考虑可能的延迟加载)?如果非常可能,它可能应该进入回购;如果你希望总是生成另一个针对数据库的查询,总是将它放在repo中。如果有疑问,请把它放在回购中。

现在这是坏消息:这一切都不适用于你的情况。

首先,您已经在getAdmin 上拥有相当于User的方法......这正是User.Admin所针对的,不是吗?只需使用您为此目的定义的关系。

其次,如果管理员总是有用户关联,您的模型中缺少关系:您需要(例如Admin.Self类型User来代表此项1一对一的关系,然后只是担心从先前提取的Admin获得AdminRepo.FindByKey()User.AdminUser} ...一旦你有{{{} 1}},Admin将始终为您提供相关的Admin.Self属性。

在考虑repos之类的任何抽象之前,确定实际模型中的所有属性和关系,这样你的repos就可以执行他们想做的简单CRUD操作。

答案 1 :(得分:1)

根据您的解释(以及使用ORM的事实,例如Entity Framework),保留EF对象的任何数据检索/修改功能是正确的。 EF对象被称为“模型”,因为它们是模型,它们唯一可以做的是BE模型,并将数据库结构表示为POCO类。

因此在其中加入一些逻辑(更不用说你必须修改* .tt文件以使这个逻辑持久并且不会在每次模型更新时松动)不是一个好主意。正如@Jenish已经说过的那样,保持模型结构尽可能简单。

另一方面,您的仓库应该提供所有必要的数据访问方法,因此您必须将此方法放在仓库中。

更新1

关于你的下一个问题,关于在哪里放置以及如何获得用户管理员。我认为如果你使用存储库模式,最好通过“subject”分解它,因此你将拥有userrepo,adminrepo等等。然而,根据逻辑归属,有些方法会转到userrepo,有些会转到adminrepo等等。

但通常,首先,您必须做出决定,您是在前端使用数据库模型,还是仅为视图呈现目的而使用单独的视图模型类。如果首先是真的,我个人看不到什么大不了,如果你只是通过导航属性返回用户的管理员。无论如何,您使用DB模型类对象作为容器。因此,我认为将其直接作为用户类的导航属性返回,或者通过专用的存储库方法返回它,不会发生任何重大变化。

另一方面,如果您将引入视图模型类并在视图模型之间进行一些转换&lt; - &gt; db模型对象比在专用repos上制动所有场景更有意义。

无论如何,我敢肯定,每个开发者必须始终记住的主要原则必须是“保持简单”。我个人不会添加任何复杂的层次,如果我不是100%确定我真的需要它。

答案 2 :(得分:0)

所以在存储库中它将是。 还有一个问题(或者我应该为此开始一个新主题?)

在EFUserRepo中使用此方法

public admin getAdmin(string username)
{
    user user = getUserByPK(username);
    if (user == null) return null;
    return user.admin;
    //return context.admin.Find(user.admin_id);//Also works, but is it best practise to access the admin collection from within the userrepo, think not
    //return new EFAdminRepo().getAdminByPK(user.admin_id)//Also works, but seams really ugly
}

我可以在控制器(或其他任何地方)

中执行此操作

选项1:

admin admin = EFUserRepo().getAdmin(loggedOnUser.username);

我可以使用语句&#34; return user.admin;&#34;在EFUserRepo中,因为admin是用户的导航属性,但是如果由于某种原因导航属性不存在该怎么办。然后我将不得不使用其中一个被注释掉的语句。

  • &#34; return context.admin.Find(user.admin_id);&#34;
  • &#34; return new EFAdminRepo().getAdminByPK(user.admin_id);&#34;

我发现这些陈述非常难看,这可能不是最佳做法? (请注意,这些语句位于user存储库中!) 一种解决方案是从EFUserRepo中删除getAdmin()方法并使用EFAdminRepo,因此我可以在我的控制器中执行此操作:

选项2:

user adminUser = EFUserRepo().getUserAdmin(loggedOnUser.username);
admin admin = EFAdminRepo().getAdminByPk(adminUser.admin_id);

我认为option2是正确的方法吗?请评论..

相关问题