#c# #sql #database
#c# #sql #База данных
Вопрос:
Когда я получаю название страны, я хочу выполнить поиск по списку названий стран в моей базе данных и получить связанный идентификатор с названием страны. В настоящее время у меня есть;
public static int GetCountryId(string countryName)
{
int countryId = 0;
if (!string.IsNullOrEmpty(countryName))
{
var listOfCountries = GetCountries();
var match = listOfCountries.FirstOrDefault(item => (item.Name).Contains(countryName));
if (match != null)
{
countryId = match.Id;
}
}
return countryId;
}
private static List<Country> GetCountries()
{
string query = $"SELECT Id, Name FROM Countries";
List<Country> cases = Common.GetCollection<Country>(Properties.Settings.Default.DbConnectionString, query);
return cases;
}
Но, как вы можете видеть, мне приходится запрашивать базу данных каждый раз, когда я хочу получить список названий стран. Я хочу, чтобы этот список хранился в словаре, и вместо этого я мог просто получить доступ к словарю.
Кто-нибудь знает, как я мог бы улучшить свой код, чтобы мне не приходилось каждый раз обращаться к базе данных?
Ответ №1:
Измените свой метод следующим образом:
private static List<Country> countries;
private static List<Country> GetCountries()
{
if (countries == null || countries.Count == 0)
{
string query = $"SELECT Id, Name FROM Countries";
countries = Common.GetCollection<Country>(Properties.Settings.Default.DbConnectionString, query);
}
return countries;
}
Ответ №2:
Как насчет создания статического конструктора для заполнения словаря идентификаторов стран при первом запуске вашей программы, чтобы вам приходилось запрашивать базу данных только один раз. Тогда вызовы GetCountryId могут просто использовать этот словарь?
private static Dictionary<string, int> CountryIds;
public static NameOfYourClass(){
CountryIds = new Dictionary<string, int>();
string query = $"SELECT Id, Name FROM Countries";
List<Country> cases = Common.GetCollection<Country>(Properties.Settings.Default.DbConnectionString, query);
foreach (country Country in cases)
{
CountryIDs.Add(Country.Name, Country.Id);
}
}
public static int GetCountryId(string countryName)
{
if(!CountryIds.Contains(countryName) return 0;
return CountryIds[countryName];
}
Ответ №3:
Давайте сделаем для этого отложенную загрузку!
private Dictionary<string, Country> _countryNames = null;
public Dictionary<string, Country> CountryNames
{
get
{
if(_countryNames == null)
{
_countryNames = new Dictionary<int, Country>();
foreach(var country in GetCountries())
{
_countryNames.Add(country.Name, country)
}
}
return _countryNames;
}
}
public static int GetCountryId(string countryName)
{
Country resu<
CountryNames.TryGetValue(countryName, out result);
if (result == null) return 0;
return result.Id;
}
private static IEnumerable<Country> GetCountries()
{
string query = "SELECT Id, Name FROM Countries";
return Common.GetCollection<Country>(Properties.Settings.Default.DbConnectionString, query);
}
Но обычно еще лучше позволить базе данных делать свое дело: запускать запрос там по мере необходимости, где вы передаете строку фильтра в базу данных. К сожалению, Common.GetCollection<T>()
скрывает от нас эту возможность. query
Переменная должна выглядеть примерно так:
string query = "SELECT Id, Name FROM Countries WHERE Name = @CountryName";
но из вопроса здесь не ясно, как указать @CountryName
значение параметра. Чего вы НЕ должны делать, так это использовать подстановку строк или интерполяцию, чтобы включить значение непосредственно в строку запроса. Это было бы очень плохо; это создает серьезную проблему безопасности, которая называется SQL-инъекцией.
Комментарии:
1. Спасибо за подробный ответ! Мне очень любопытно, что вы имеете в виду подстановку строк. Если бы я дал
@CountryName
параметр, как это может быть угрозой безопасности? Я слышал о SQL-инъекции, но я не знаю, как это применимо к этой ситуации?2. Почему бы не использовать только одну строку с
Lazy<>
?3. Если вы просто замените значение @countryName строкой, вы будете безумно уязвимы для атак. Параметризованные запросы отправляют данные параметров на сервер базы данных отдельно от командной строки sql. Но вы должны каким-то образом сообщить приложению об этом параметре, чтобы все было подключено.
Ответ №4:
У вас может быть общедоступный словарь, подобный этому:
public static Dictionary<int, string> countries = new Dictionary<int, string>();
Метод заполняет словарь, если он не был заполнен ранее;
private static void GetCountries()
{
if(countries.Count == 0)
{
string query = $"SELECT Id, Name FROM Countries";
countries = Common.GetCollection<Country>(Properties.Settings.Default.DbConnectionString, query)
.ToDictionary(x => x.Id, x=> x.Name);
}
}
public static int GetCountryId(string countryName)
{
return countries.Contains(countryName) CountryIds[countryName] : 0;
}
Комментарии:
1. Не удается получить доступ к нестатическим элементам из статических методов.
2. проверьте ответ еще раз. я исправил это.
3. Вы знаете, как
GetCountryId
метод изменится при этом?4. @user180708 Я только что отредактировал свой ответ. пожалуйста, взгляните.