열이 존재하는지 확인하는 방법 SqlDataReader
개체에 ? 내 데이터 액세스 계층에서 여러 저장 프로 시저 호출에 대해 동일한 개체를 작성하는 메서드를 만들었습니다. 저장 프로 시저 중 하나에 다른 저장 프로 시저에서 사용하지 않는 추가 열이 있습니다. 모든 시나리오에 맞게 방법을 수정하고 싶습니다.
내 응용 프로그램은 C #으로 작성되었습니다.
답변
public static class DataRecordExtensions
{
public static bool HasColumn(this IDataRecord dr, string columnName)
{
for (int i=0; i < dr.FieldCount; i++)
{
if (dr.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
return true;
}
return false;
}
}
Exception
다른 답변과 마찬가지로 제어 논리에 s를 사용하는 것은 나쁜 습관 으로 간주됩니다 성능 비용이 있습니다. 또한 발생 된 예외 # 개에 대해 오탐 (false positive)을 전송하고 예외 발생시 디버거를 설정하는 사람이 누구든지 도와줍니다.
GetSchemaTable ()도 많은 답변에서 또 다른 제안입니다. 모든 버전에서 구현되지 않았기 때문에 필드의 존재 여부를 확인하는 바람직한 방법은 아닙니다 (추상적이고 일부 버전의 dotnetcore에서는 NotSupportedException이 발생 함). GetSchemaTable은 소스 를 체크 아웃 하면 꽤 무거운 기능이기 때문에 성능이 지나치게 뛰어납니다 .
필드를 많이 사용하면 필드를 루핑하면 성능이 약간 저하 될 수 있으며 결과 캐싱을 고려할 수 있습니다.
답변
이 부울 함수를 사용하는 것이 훨씬 좋습니다.
r.GetSchemaTable().Columns.Contains(field)
한 번의 전화-예외는 없습니다. 내부적으로 예외가 발생할 수 있지만 그렇게 생각하지 않습니다.
참고 : 아래 의견에서 우리는 이것을 알아 냈습니다 … 정확한 코드는 실제로 다음과 같습니다.
public static bool HasColumn(DbDataReader Reader, string ColumnName) {
foreach (DataRow row in Reader.GetSchemaTable().Rows) {
if (row["ColumnName"].ToString() == ColumnName)
return true;
} //Still here? Column not found.
return false;
}
답변
최선의 방법은 DataReader에서 GetOrdinal ( “columnName”) 을 먼저 호출 하고 열이 없으면 IndexOutOfRangeException을 잡는 것입니다.
실제로 확장 방법을 만들어 봅시다 :
public static bool HasColumn(this IDataRecord r, string columnName)
{
try
{
return r.GetOrdinal(columnName) >= 0;
}
catch (IndexOutOfRangeException)
{
return false;
}
}
편집하다
좋아,이 게시물은 최근에 몇 개의 다운 투표권을 얻었습니다. 허용 된 답변이기 때문에 삭제할 수 없으므로 업데이트 할 것이고 예외 처리 사용을 정당화하려고합니다. 제어 흐름.
Chad Grant가 게시 한 다른 방법은 DataReader의 각 필드를 반복하고 원하는 필드 이름을 대소 문자를 구분하지 않고 비교하는 것입니다. 이것은 실제로 잘 작동하며 실제로 위의 방법보다 성능이 좋을 것입니다. 확실히 나는 퍼포먼스가 문제가 된 루프 내에서 위의 방법을 사용하지 않을 것입니다.
루프가 작동하지 않는 try / GetOrdinal / catch 메소드가 작동하는 상황을 생각할 수 있습니다. 그러나 지금은 완전히 가상적인 상황이므로 매우 어설픈 정당화입니다. 어쨌든, 나와 함께 견디고 당신의 생각을보십시오.
테이블 내에서 열을 “별칭”으로 만들 수있는 데이터베이스를 상상해보십시오. “EmployeeName”이라는 열이있는 테이블을 정의 할 수 있지만 “EmpName”의 별칭을 제공 할 수 있으며 두 이름 중 하나를 선택하면 해당 열의 데이터가 반환됩니다. 지금까지 나와 함께?
이제 해당 데이터베이스에 대한 ADO.NET 공급자가 있고 열 별칭을 고려한 IDataReader 구현을 코딩했다고 가정합니다.
이제 dr.GetName(i)
Chad의 답변에 사용 된 것처럼 단일 문자열 만 반환 할 수 있으므로 열의 “별칭” 중 하나만 반환해야합니다 . 그러나이 GetOrdinal("EmpName")
공급자 필드의 내부 구현을 사용하여 원하는 이름의 각 열 별명을 확인할 수 있습니다.
이 가상의 “별칭 된 열”상황에서 try / GetOrdinal / catch 메서드는 결과 집합에서 열 이름의 모든 변형을 확인하는 유일한 방법입니다.
얇은? 확실한. 그러나 생각할 가치가 있습니다. 솔직히 IDataRecord에 대한 “공식적인”HasColumn 메소드를 사용하고 싶습니다.
답변
한 줄에서 DataReader 검색 후 이것을 사용하십시오.
var fieldNames = Enumerable.Range(0, dr.FieldCount).Select(i => dr.GetName(i)).ToArray();
그때,
if (fieldNames.Contains("myField"))
{
var myFieldValue = dr["myField"];
...
편집하다
스키마를로드 할 필요가없는 훨씬 효율적인 단일 라이너 :
var exists = Enumerable.Range(0, dr.FieldCount).Any(i => string.Equals(dr.GetName(i), fieldName, StringComparison.OrdinalIgnoreCase));
답변
Jasmin의 아이디어에 대한 실제 샘플은 다음과 같습니다.
var cols = r.GetSchemaTable().Rows.Cast<DataRow>().Select
(row => row["ColumnName"] as string).ToList();
if (cols.Contains("the column name"))
{
}
답변
이것은 나를 위해 작동합니다 :
bool hasColumnName = reader.GetSchemaTable().AsEnumerable().Any(c => c["ColumnName"] == "YOUR_COLUMN_NAME");
답변
다음은 간단하고 나를 위해 일했습니다.
bool hasMyColumn = (reader.GetSchemaTable().Select("ColumnName = 'MyColumnName'").Count() == 1);