我有一个宠物项目(GitHub上的开源),我建立了一个学习练习。这是一个歌词web应用程序构建在.NET Core中。
在网站的艺术家页面上(查看移动大小的视图,目前只对手机进行了优化),我按字母顺序列出了所有的艺术家。这些艺术家是按字母分组的。
生成该页的代码如下:
[Route("artists")]
public async Task<IActionResult> Index()
{
IDictionary<char, List<LibraryArtistViewModel>> viewModel = await _artistsService
.GetAllArtistsAsync();
return View(viewModel);
}public async Task<IDictionary<char, List<LibraryArtistViewModel>>> GetAllArtistsAsync()
{
List<LibraryArtistViewModel> artists = new List<LibraryArtistViewModel>();
await using NpgsqlConnection connection = new NpgsqlConnection(databaseOptions.ConnectionString);
await connection.OpenAsync();
await using NpgsqlCommand command = new NpgsqlCommand("select a.first_name, a.last_name, \"as\".name as primary_slug, ai.data as image_data, count(l.title) as number_of_lyrics from artists a left join artist_images ai on ai.artist_id = a.id inner join artist_slugs \"as\" on \"as\".artist_id = a.id left join lyrics l on l.artist_id = a.id where a.is_approved = true and a.is_deleted = false and \"as\".is_primary = true and l.is_approved = true and l.is_deleted = false group by a.id, \"as\".name, ai.data order by a.first_name asc;", connection);
await using NpgsqlDataReader reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
LibraryArtistViewModel artist = new LibraryArtistViewModel();
string firstName = Convert.ToString(reader[0]);
string lastName = Convert.ToString(reader[1]);
string fullName = textInfo.ToTitleCase($"{firstName} {lastName}");
string primarySlug = Convert.ToString(reader[2]);
bool hasImage = reader[3] != System.DBNull.Value;
int numberOfLyrics = Convert.ToInt32(reader[4]);
artist.FirstName = firstName;
artist.LastName = lastName;
artist.FullName = fullName;
artist.PrimarySlug = primarySlug;
artist.HasImage = hasImage;
artist.NumberOfLyrics = numberOfLyrics;
artists.Add(artist);
}
IDictionary<char, List<LibraryArtistViewModel>> dictionary = BuildDictionary(artists);
return dictionary;
}
private IDictionary<char, List<LibraryArtistViewModel>> BuildDictionary(List<LibraryArtistViewModel> artists)
{
List<char> letters = new List<char>();
IDictionary<char, List<LibraryArtistViewModel>> dictionary =
new Dictionary<char, List<LibraryArtistViewModel>>();
foreach (LibraryArtistViewModel artist in artists)
{
char firstLetter = char.ToUpper(artist.FirstName[0]);
if (!letters.Contains(firstLetter))
{
letters.Add(firstLetter);
dictionary.Add(firstLetter, new List<LibraryArtistViewModel>());
}
}
foreach (char letter in letters)
{
foreach (LibraryArtistViewModel artist in artists)
{
char firstLetter = char.ToUpper(artist.FirstName[0]);
if (letter == firstLetter)
{
List<LibraryArtistViewModel> artistsBeginningWithTheLetter = dictionary[letter];
artistsBeginningWithTheLetter.Add(artist);
}
}
}
return dictionary;
}上面的代码工作,但我觉得它是没有效率的。我觉得有更好的方法。
而且,我对我提供图像的方式也很不确定。我的图像目前以字节形式存储在数据库中,并且我有一个控制器为图像提供服务。这似乎真的在扼杀我在https://web.dev上的性能指标。
我做这个项目是为了学习东西。所以我真的很乐意学习如何“正确”地做事情,即使他们被认为是过分的。
我很感激上面的一些建议,以及我如何能够改善艺术家形象的情况。

发布于 2020-09-15 22:38:40
嗯,你有一个很好的learning exercise项目。下面是您提供的最优秀代码的一些注释:
string查询,它打开SQL Injections。要克服这一问题,首先需要将查询标记为const或readonly,并以分号结束查询(您确实这样做了),并确保查询本身没有任何可能以不适当方式使用的SQL错误。但是,如果您想要正确地管理数据库,可以使用Object-relational Mapping AKA ORM (如Entity Framework )。images/artists/someartist.png,那么您只需像https://www.somewebsite.com/images/artists/someartist.png一样向其添加当前的web url。PNG图像用于web,因为png图像在质量和大小之间更加平衡,并且是比其他类型的web更好的选择。在您的代码中,不应该在表示层上执行排序操作,实际上,如果将排序操作移到早期应用程序阶段(如在您的示例中对艺术家进行排序),则您的应用程序具有按字母顺序过滤艺术家姓名的核心功能。这意味着,在将数据插入数据库之前,需要将此功能应用于数据,因为它被用作核心功能,而不是附加功能。
但是,有不同的方法可以这样做,一种方法是添加一个属性存储的名字字母如下:
public class LibraryArtistViewModel
{
public char FirstLetter => FirstName?.Length > 0 ? FirstName.ToUpper()[0] : char.MinValue;
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get; set; }
public string PrimarySlug { get; set; }
public bool HasImage { get; set; }
public int NumberOfLyrics { get; set; }
}然后,您可以在GetAllArtistsAsync()中这样做:
while (await reader.ReadAsync())
{
var artist = new LibraryArtistViewModel
{
FirstName = reader[0]?.ToString(),
LastName = reader[1]?.ToString(),
FullName = textInfo.ToTitleCase($"{reader[0]?.ToString()} {reader[1]?.ToString()}"),
PrimarySlug = reader[2]?.ToString(),
HasImage = reader[3] != System.DBNull.Value;
NumberOfLyrics = int.TryParse(reader[4]?.ToString(), out int number) ? number : 0;
};
artists.Add(artist);
}
var dictionary = artists.GroupBy(x=> x.FirstLetter).ToDictionary(x => x.Key, x => x.ToList()).OrderBy(x=> x.Key);虽然这会给你你想要的,但它会带来一些微小的表现。正如我前面所说的,由于您的艺术家应该被排序,所以您需要从插入数据的时间开始对其进行排序,要么从数据库中排序,要么从更快的数据库中排序,或者从CreateNewArtistAsync操作中排序。因此,在您的Get中,您不需要对每个请求重新排序。
https://codereview.stackexchange.com/questions/249408
复制相似问题