我有两个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();
答案 0 :(得分:2)
首先,这是一个名称作为主键吗?帮自己一个忙:立即摆脱那种憎恶。一旦你说服自己没关系,你就会遇到一个情况,那就是有两个Joe Smith,或者Jane Doe会结婚,你会想要修改她的名字字段,而不能因为它是一把钥匙。只需给自己另一个int
字段作为密钥,每条记录只需几个字节,并且总是正确的。
所以,不要让人们告诉你不要在模型类中添加任何逻辑,除了数据库或导航属性中的字段。模型一直代表IsAdmin
之类的简单事物,而不必求助于单独的类。只需打上[NotMapped]
就可以了。你很高兴。
关于在逻辑变得更复杂时放置这些方法的位置,我问自己这个问题:该方法有多大可能产生另一次数据库之旅(并考虑可能的延迟加载)?如果非常可能,它可能应该进入回购;如果你希望它总是生成另一个针对数据库的查询,总是将它放在repo中。如果有疑问,请把它放在回购中。
现在这是坏消息:这一切都不适用于你的情况。
首先,您已经在getAdmin
上拥有相当于User
的方法......这正是User.Admin
所针对的,不是吗?只需使用您为此目的定义的关系。
其次,如果管理员总是有用户关联,您的模型中缺少关系:您需要(例如Admin.Self
类型User
来代表此项1一对一的关系,然后只是担心从先前提取的Admin
获得AdminRepo.FindByKey()
(User.Admin
或User
} ...一旦你有{{{} 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是用户的导航属性,但是如果由于某种原因导航属性不存在该怎么办。然后我将不得不使用其中一个被注释掉的语句。
return context.admin.Find(user.admin_id);
&#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是正确的方法吗?请评论..