我希望确定完成以下内容的最干净/最佳做法:
我使用EF,代码优先,存储库模式。我有一个名为Project的实体,它有一个描述项目的标签或关键字列表:
public class Tag {
public int TagID { get; set; }
public int ProjectID { get; set; }
public string TagValue { get; set; }
}
我在强类型Razor视图中使用此数据,并在Project标题下方显示Tags。执行此操作时,我希望每个标记指示它在数据库中出现的次数,如:
一些项目标题
C#(5),实体框架(17)
在我看来,最好的计划是向实体添加计算属性:
public class Tag {
public int TagID { get; set; }
public int ProjectID { get; set; }
public string TagValue { get; set; }
public int TagCount { get { _context.Tags("Some Filter on TagValue").Count() }}
}
或者,我正在考虑在控制器中填充TagCount属性,调用TagRepository中的方法,如:
public int countTags(string TagValue);
意识到我可能完全忽视了这里的大局,我的问题是:这些方法中的任何一种都在正确的轨道上吗?
更新:按要求添加项目模型。
摘要项目:
public abstract class Project {
public int ProjectID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
已实施项目类型:
public class Scientific : Project {
public int ScientificProjectNumber { get; set; }
public string FileNumber { get; set; }
public int Year { get; set; }
public DateTime StartDate { get; set; }
}
更新 我的解决方案基于Brian Cauthon的回答是:
- 我继承了我正在扩展的类,而不是创建一个新的网络类: 注意:我必须创建一个额外的属性TagsView,因为我无法覆盖Scientific:Project类的虚拟属性。
public class ScientificView : Scientific {
public virtual ICollection<TagView> TagsView { get; set; }
}
- 我为TagView做了同样的事情,扩展了类而不是复制它 - 希望在这些对象发展过程中为我节省一些努力:
public class TagView : Tag {
public int TagCount { get; set; }
}
- 增加了建议的TagRepository方法:
public Dictionary<string, int> countTags(IEnumerable<string> tags) {
Dictionary<string, int> result = new Dictionary<string, int>();
var query = from o in _context.Tags
group o by o.TagValue into tagGroup
select new {TagText = tagGroup.Key,
TagCount = tagGroup.Count()};
foreach (var tagGroup in query) {
result.Add(tagGroup.TagText, tagGroup.TagCount);
}
return result;
}
-Updated全部从Controller执行。感谢您提供优秀AutoMapper项目的链接:
public ViewResult Scientific(int projectID) {
Scientific project= _scientificRepository.Scientific.FirstOrDefault(l => l.ProjectID == projectID);
Dictionary<string, int> tagCounts = _tagRepository.countTags(project.Tags.Select(t => t.TagValue));
Mapper.CreateMap<Scientific, ScientificView>();
ScientificView sv = Mapper.Map<Scientific, ScientificView>(project);
Mapper.CreateMap<Tag, TagView>();
sv.TagsView = new List<TagView>();
foreach (Tag t in project.Tags) {
TagView tv = Mapper.Map<Tag, TagView>(t);
tv.TagCount = tagCounts[tv.TagValue];
sv.TagsView.Add(tv);
}
return View(sv);
}
答案 0 :(得分:1)
对于实际问题,我个人会说知道如何实现业务逻辑并不是模型的业务,而是让模型上的方法执行业务逻辑。如果标签计数是从模型外部计算的(即从存储过程中),那么我可能会沿着你已经开始的路线前进,但是将其定义为计算列(discussed here)
然而,对于您要尝试实现的目标可能会产生问题,因为您可能会为数据库调用数百个时间来获取相同数据_context.Tags("").Count()
,因为每个项目中加载的每个Tag都将执行此调用。
答案 1 :(得分:1)
我会从标记库中提取计数。由于您可能会一次为多个标签提取计数,因此我会将您的存储库方法更改为同时提取所有标记。
我会为您的视图创建特定的视图模型,然后使用Automapper将Project
和Tag
映射到它们。
public class ProjectView {
public int ProjectID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public virtual ICollection<TagView> Tags { get; set; }
}
public class ProjectTagView {
public int TagID { get; set; }
public string TagValue { get; set; }
public int TagCount { get; set; }
}
然后在你的控制器中,你会有这样的东西。
var model = AutoMapper.Map<Project,ProjectView>(project);
Dictionary<string,int> tagCounts = tagRepository.getCounts(model.Tags.Select(t=>t.TagValue));
foreach(var t in model.Tags){
t.TagCount = tagCounts[t.TagValue];
}