1

我正在寻找完成以下任务的最干净/最佳实践方式:

我正在使用 EF,代码优先,存储库模式。我有一个名为 Project 的实体,它又具有描述该项目的标签或关键字列表:

public class Tag {
   public int TagID { get; set; }
   public int ProjectID { get; set; }
   public string TagValue { get; set; }
}  

我在强类型 Razor 视图中使用此数据,并在项目标题下方显示标签。这样做时,我希望每个标签都指示它在数据库中出现的次数,例如:

一些项目名称

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;
    }

-更新全部从控制器执行。感谢您提供优秀 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);
    }
4

2 回答 2

1

对于实际的问题,我个人认为不是模型的业务知道如何实现业务逻辑,而是让模型上的方法做业务逻辑。如果标签计数是从模型外部计算的(即从存储过程),那么也许我会沿着您开始的路线走,但将其定义为计算列(在此处讨论

但是,对于您要实现的目标可能会产生疑问,因为目前您可能会为相同的数据调用数据库数百次,_context.Tags("").Count()因为加载到每个项目中的每个标签都将执行此调用。

于 2012-12-14T17:29:07.220 回答
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];
}
于 2012-12-14T17:29:23.057 回答