Надеюсь, это то, что вы ищете.Из того, что я могу расшифровать, цель состоит в том, чтобы «сгладить» данные из данных «классов».Я собираюсь отказаться от экспорта в Excel, так как это, похоже, другая проблема.Существуют «классы», я предполагаю, что метод вернул DataTable
или любой тип «коллекции», который вы пожелаете.Я предполагаю, что это упростит процесс экспорта в Excel.
В классе Catergory
он имеет «коллекцию» Article’s
.Каждый Article
представляет «строку» в коллекции (электронная таблица Excel).Каждый Article
имеет «коллекцию» ArticleReviews
, называемую Reviews
.Как вы заявили…
Одна из моих проблем - динамическое изменение столбца «Точка обзора», поскольку в одной статье может быть 3 столбца (как на верхнем изображении), а в другой может быть 4 или 5 Точек обзора.
Похоже, что для каждого Article
может быть много рецензентов. Кроме того, не все рецензенты обязательно «рецензируют» все статьи.Учитывая это и требование «сгладить» эти данные, будет означать создание столбца для «каждого» рецензента.Кроме того, я предполагаю, что в списке есть только рецензенты, которые рецензировали одну из статей, иначе было бы просто создать колонку для каждого рецензента.Я предполагаю, что цель состоит в том, чтобы иметь только те столбцы, в которых рецензент «рецензировал» хотя бы одну (1) статью.
С учетом сказанного, я предполагаю, что первая проблема состоит в том, чтобы выяснить «сколько» столбцовпотребность в рецензентах и «что», имена этих рецензентов.Нам понадобится какой-то способ определить, «какой» столбец принадлежит рецензенту.Я использую имя Reviewer
, чтобы определить правильный столбец.Итак, как нам найти рецензентов ...
Удобно, что класс Category
имеет список Artlicle
s.Если был создан метод, который просматривал каждую статью, а затем проходил каждую рецензию статьи, собирал всех рецензентов и игнорировал дубликаты… это должно дать нам список «рецензентов», для которых нам нужно добавить столбцы.Если метод перенастроил список Reviewer
, мы могли бы использовать это, чтобы определить не только, сколько столбцов нам нужно, но и каковы должны быть имена этих столбцов.
Одна из возможных проблем заключается в том, что порядок столбцов может быть непредсказуемым.В зависимости от того, какая статья является первой, собирается определить порядок столбцов.Поэтому я рекомендую некоторую «сортировку» столбцов, чтобы поддерживать некоторый порядок.
Я добавил класс Reviewer
, который должен помочь в сортировке и сравнении имен столбцов.Это простой Reviewer
класс, как показано ниже.Обратите внимание на метод compareTo
, который используется сортировкой.Сортировка по идентификатору рецензентов.Это сохранит тот же порядок столбцов.
public class Reviewer : IComparable<Reviewer> {
public int ReviewerID { get; set; }
public string ReviewerName { get; set; }
public Reviewer() {
}
public Reviewer(int reviewerID, string reviewerName) {
ReviewerID = reviewerID;
ReviewerName = reviewerName;
}
public override string ToString() {
return "ReviewerID: " + ReviewerID.ToString();
}
public override bool Equals(object obj) {
return this.ReviewerName.Equals(((Reviewer)obj).ReviewerName);
}
public override int GetHashCode() {
return ReviewerName.GetHashCode();
}
public int CompareTo(Reviewer other) {
return this.ReviewerID.CompareTo(other.ReviewerID);
}
}
Это повлияет на класс ArticleReview
, и в нем потребуются некоторые изменения.Некоторые переменные кажутся ненужными, и отображаются только необходимые переменные.Основным изменением является объект Reviewer
сверху для определения рецензента.
public class ArticleReview {
public long ArticleId { get; set; }
public Reviewer TheReviewer { get; set; }
public int ReviewPoint { get; set; }
public ArticleReview() {
}
public ArticleReview (long articleId, Reviewer reviewerId, int reviewPoint) {
ArticleId = articleId;
TheReviewer = reviewerId;
ReviewPoint = reviewPoint;
}
}
Следующий класс Article
.Он содержит все рецензии на эту статью.Похоже, что есть столбец под названием «Средняя точка».Это выглядит как «вычисленное» значение из обзоров.Поэтому я предполагаю, что для класса Article
было бы удобно «вычислить» это значение для нас.Здесь есть все отзывы ... все, что нужно, это сложить все пункты и поделить на количество отзывов.Этот метод добавлен в класс Article
.
public class Article {
public long ArticleId { get; set; }
public string ArticleTitle { get; set; }
public int NumberOfComment { get; set; }
public int NumberOfView { get; set; }
public virtual ICollection<ArticleReview> Reviews { get; set; }
public Article() {
}
public Article(long articleId, string articleTitle, int numberOfComment, int numberOfView, ICollection<ArticleReview> reviews) {
ArticleId = articleId;
ArticleTitle = articleTitle;
NumberOfComment = numberOfComment;
NumberOfView = numberOfView;
Reviews = reviews;
}
public decimal GetAverage() {
if (Reviews.Count <= 0)
return 0;
decimal divisor = Reviews.Count;
int totPoints = 0;
foreach (ArticleReview review in Reviews) {
totPoints += review.ReviewPoint;
}
return totPoints / divisor;
}
}
Наконец, класс Category
содержит все Article
s.Этот класс - то, где мы должны сделатьвсе вещи столбца, описанные ранее.Первая часть - это получение List<Reviewer>
без дубликатов.Для этого потребуется просмотреть все статьи, а затем просмотреть все обзоры в каждой статье.В этом процессе мы можем исследовать «рецензентов» и создать недублированный список всех пользователей.Код создает новый пустой List<Reviewer>
, затем проходит по каждой статье, цикл по каждому обзору.Выполняется проверка, чтобы убедиться, что «рецензент» уже есть в списке, если нет, то добавьте их, в противном случае игнорируйте дубликат «рецензента». Список отсортирован для поддержания порядка столбцов, а затем возвращается.
Полагаю, этот список можно было бы использовать разными способами для решения загадки «столбцы».В этом примере в класс Category
добавлен другой метод.Метод GetDataTable
возвращает DataTable
из данных в статьях.Для начала в таблицу добавляются первые четыре столбца: «Заголовок», «#ofView», «#ofComment» и «Средняя точка». Далее следует цикл по всем рецензентам, чтобы добавить столбцы рецензентов.Имя рецензента используется в качестве имени столбца.Вот как мы определяем, какой столбец принадлежит рецензенту при добавлении данных.
Наконец, цикл для каждого Article
добавляет данные.Каждая статья создает новую строку.Первые три столбца в строке могут быть установлены ... Заголовок, просмотр, комментарий и Среднее.Далее мы перебираем все отзывы.Для каждого отзыва targetName
задается имя рецензента, затем цикл по каждому столбцу, пока он не найдет имя столбца, соответствующее имени рецензента.Найдя, мы знаем, что это столбец, к которому принадлежат данные. Добавьте значение и вырвитесь из цикла столбцов и получите следующий обзор.
public class Category {
public long CategoryId { get; set; }
public string CategoryTitle { get; set; }
//...
public virtual ICollection<Article> Articles { get; set; }
public Category() {
}
public Category(long categoryId, string categoryTitle, ICollection<Article> articles) {
CategoryId = categoryId;
CategoryTitle = categoryTitle;
Articles = articles;
}
public DataTable GetDataTable() {
List<Reviewer> allReviewers = GetNumberOfReviewers();
DataTable dt = new DataTable();
dt.Columns.Add("Title", typeof(string));
dt.Columns.Add("#ofView", typeof(long));
dt.Columns.Add("#ofComment", typeof(long));
dt.Columns.Add("Average point", typeof(decimal));
foreach (Reviewer reviewer in allReviewers) {
dt.Columns.Add(reviewer.ReviewerName, typeof(long));
}
foreach (Article article in Articles) {
DataRow newRow = dt.NewRow();
newRow["Title"] = article.ArticleTitle;
newRow["#ofView"] = article.NumberOfView;
newRow["#ofComment"] = article.NumberOfComment;
newRow["Average point"] = article.GetAverage();
foreach (ArticleReview review in article.Reviews) {
string targetName = review.TheReviewer.ReviewerName;
for (int i = 4; i < dt.Columns.Count; i++) {
if (targetName == dt.Columns[i].ColumnName) {
newRow[review.TheReviewer.ReviewerName] = review.ReviewPoint;
break;
}
}
}
dt.Rows.Add(newRow);
}
return dt;
}
private List<Reviewer> GetNumberOfReviewers() {
// we need a list of all the different reviewers
List<Reviewer> reviewers = new List<Reviewer>();
foreach (Article article in Articles) {
foreach (ArticleReview review in article.Reviews) {
if (!reviewers.Contains(review.TheReviewer)) {
reviewers.Add(review.TheReviewer);
}
}
}
reviewers.Sort();
return reviewers;
}
}
Собрав все это вместе, приведенный ниже код создает некоторые данныепоказывать.Затем DataTable
используется от DataSource
до DataGridView
.Надеюсь, это поможет.
DataTable dt;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
Category cat = new Category();
cat.CategoryId = 1;
cat.CategoryTitle = "Category 1";
cat.Articles = GetArticles();
dt = cat.GetDataTable();
dataGridView1.DataSource = dt;
}
private List<Article> GetArticles() {
List<Article> articles = new List<Article>();
Article art = new Article(1, "Article 1 Title", 10, 1200, GetReviews(1));
articles.Add(art);
art = new Article(2, "Article 2 Title", 32, 578, GetReviews(2));
articles.Add(art);
art = new Article(3, "Article 3 Title", 15, 132, GetReviews(3));
articles.Add(art);
art = new Article(4, "Article 4 Title", 13, 133, GetReviews(4));
articles.Add(art);
art = new Article(5, "Article 5 Title", 55, 555, GetReviews(5));
articles.Add(art);
art = new Article(6, "Article 6 Title", 0, 0, GetReviews(6));
articles.Add(art);
return articles;
}
private ICollection<ArticleReview> GetReviews(int reviewId) {
ICollection<ArticleReview> reviews = new List<ArticleReview>();
ArticleReview ar;
Reviewer Reviewer1 = new Reviewer(1, "Reviewer 1");
Reviewer Reviewer2 = new Reviewer(2, "Reviewer 2");
Reviewer Reviewer3 = new Reviewer(3, "Reviewer 3");
Reviewer Reviewer4 = new Reviewer(4, "Reviewer 4");
Reviewer Reviewer5 = new Reviewer(5, "Reviewer 5");
Reviewer Reviewer6 = new Reviewer(6, "Reviewer 6");
switch (reviewId) {
case 1:
ar = new ArticleReview(1, Reviewer1, 15);
reviews.Add(ar);
ar = new ArticleReview(1, Reviewer2, 35);
reviews.Add(ar);
ar = new ArticleReview(1, Reviewer3, 80);
reviews.Add(ar);
ar = new ArticleReview(1, Reviewer5, 55);
reviews.Add(ar);
ar = new ArticleReview(1, Reviewer6, 666);
reviews.Add(ar);
break;
case 2:
ar = new ArticleReview(2, Reviewer1, 50);
reviews.Add(ar);
ar = new ArticleReview(2, Reviewer2, 60);
reviews.Add(ar);
ar = new ArticleReview(2, Reviewer3, 40);
reviews.Add(ar);
break;
case 3:
ar = new ArticleReview(3, Reviewer1, 60);
reviews.Add(ar);
ar = new ArticleReview(3, Reviewer2, 60);
reviews.Add(ar);
ar = new ArticleReview(3, Reviewer3, 80);
reviews.Add(ar);
break;
case 4:
ar = new ArticleReview(4, Reviewer1, 30);
reviews.Add(ar);
ar = new ArticleReview(4, Reviewer2, 70);
reviews.Add(ar);
ar = new ArticleReview(4, Reviewer3, 70);
reviews.Add(ar);
break;
case 5:
ar = new ArticleReview(5, Reviewer3, 44);
reviews.Add(ar);
break;
case 6:
break;
default:
break;
}
return reviews;
}
Используя EPPlus, ниже приведен один из способов использования DataTable
выше и экспорта DataTable
в лист Excel.
private void btn_ExportToExcel_Click(object sender, EventArgs e) {
using (var p = new ExcelPackage()) {
var ws = p.Workbook.Worksheets.Add("MySheet");
ws.Cells["A1"].LoadFromDataTable(dt, true);
p.SaveAs(new FileInfo(@"D:\Test\ExcelFiles\EpplusExport.xlsx"));
}
}