Docs Menu
Docs Home
/ / /
C#/.NET
/ /

POCO

이 페이지의 내용

  • 개요
  • POCO 생성
  • 사용자 지정 직렬화
  • 읽기 전용 속성 직렬화
  • 필드 이름 설정
  • 유형 표현 선택
  • 필드 순서 설정
  • Id 속성 식별
  • 빈 필드 생략
  • 기본값 사용자 지정
  • ID 생성기 지정
  • 날짜/시간 직렬화 사용자 지정
  • 사전 직렬화 사용자 지정
  • 예시
  • 추가 정보
  • API 문서

이 가이드에서는 작업 및 쿼리에 .NET/C# 드라이버와 함께 "Plain Old CLR/Class Objects" 또는 POCO를 사용하는 방법에 대해 알아볼 수 있습니다. POCO는 프레임워크별 기본 클래스나 인터페이스의 기능을 상속하지 않는 간단한 클래스 객체입니다. 관용적인 드라이버 사용을 준수하고 최상의 성능을 얻으려면 C# 코드에서 POCO를 사용하는 것이 좋습니다.

.NET/C# 드라이버에서 POCO를 사용하는 방법에 대해 자세히 알아보고 싶거나 드라이버의 기본 필드 매핑 동작을 조정해야 하는 경우 이 가이드를 읽어야 합니다.

인터페이스를 구현하지 않거나 프레임워크에서 클래스를 확장하지 않는 간단한 클래스를 정의하여 POCO를 만들 수 있습니다. POCO를 사용하여 읽기 또는 쓰기와 같은 작업을 실행하면 드라이버는 내부적으로 POCO를 BSON으로 직렬화하거나 변환합니다.

POCO 또는 BSON 탭을 선택하여 드라이버가 샘플 POCO를 BSON으로 직렬화하는 방법을 확인하세요.

public class Clothing
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public bool InStock { get; set; }
public double Price { get; set; }
public List<string> ColorSelection { get; set; }
}
{
"_id": ObjectId("..."),
"Name": "Long Sleeve Shirt",
"InStock": true,
"Price": 17.99,
"ColorSelection": [ "black", "navy", "red" ]
}

중첩된 객체, 배열, 목록 및 모든 데이터 유형을 포함하여 필요에 맞는 객체 구조로 POCO를 정의할 수 있습니다.

기본 필드 매핑 동작이 요구 사항을 충족하지 않는 경우 직렬화 관련 특성을 사용하여 사용자 지정 동작을 지정할 수 있습니다. 이러한 특성은 드라이버가 POCO의 각 속성을 직렬화하는 방식을 변경합니다. 이 섹션에서는 일반적인 직렬화 관련 특성 중 일부를 설명합니다.

속성이 읽기 전용인 경우 자동 매퍼는 직렬화를 위해 클래스 맵에 해당 속성을 포함하지 않습니다. 자동 매퍼가 클래스 맵에 속성을 포함하도록 하려면 해당 속성에 [BsonElement] 특성을 적용합니다.

다음 코드 예시에서는 [BsonElement] 특성을 Clothing 클래스의 Upc 속성에 적용합니다. Upcget 메서드는 있지만 set 메서드가 없으므로 읽기 전용 속성입니다.

public class Clothing
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public bool InStock { get; set; }
public double Price { get; set; }
public List<string> ColorSelection { get; set; }
[BsonElement]
public int Upc { get; }
}

다음 예시와 같이 클래스 맵을 등록할 때 읽기 전용 속성을 추가할 수도 있습니다.

BsonClassMap.RegisterClassMap<Clothing>(classMap =>
{
classMap.AutoMap();
classMap.MapProperty(c => c.Upc);
});

참고

.NET/C# 드라이버가 읽기 전용 속성을 직렬화할 때 속성과 해당 값은 데이터베이스에 저장되지만 다시 역직렬화되지는 않습니다.

드라이버는 POCO 속성을 필드 이름과 대소문자가 동일한 BSON 필드로 직렬화합니다. 속성을 다른 이름으로 저장하려면 [BsonElement()] 특성을 사용합니다. 다음 코드는 House 클래스의 YearBuilt 속성을 직렬화된 BSON 문서의 year_built 필드에 매핑합니다.

public class House
{
public Guid Id { get; set; }
[BsonElement("year_built")]
public int YearBuilt { get; set; }
}

C# 클래스를 정의할 때 파스칼 대소문자 명명 규칙을 사용하는 것이 일반적이지만 [BsonElement()] 특성을 사용하면 MongoDB 컬렉션에서 다른 또는 사용자 지정 명명 규칙을 선택할 수 있습니다.

사용자 지정 필드 이름 규칙 설정

사용자 지정 필드 이름으로 모든 속성을 직렬화하려면 [BsonElement()] 특성을 사용하는 대신 ConventionPack을 정의하면 됩니다. 예를 들어, 파스칼 대소문자 명명 규칙을 사용하여 클래스를 정의하는 경우 다음 코드를 사용하여 직렬화된 문서에서 카멜식 필드 이름을 사용할 수 있습니다.

var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() };
ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);

C# 속성을 특정 BSON type으로 직렬화하려면 [BsonRepresentation()] 특성을 사용합니다. 이는 C# 기본 유형을 지정한 BSON type으로 변환할 수 있는 경우에만 작동합니다. 다음 코드 샘플에서 C#에서 char로 정의된 YearBuilt 속성은 BSON Int32 유형으로 직렬화됩니다.

public class House
{
public Guid Id { get; set; }
[BsonRepresentation(BsonType.Int32)]
public char YearBuilt { get; set; }
}

유효한 유형 변환에 대한 자세한 내용은 C# 변환 사양을 참조하세요.

중요

NaN과 Infinity 직렬화

부동 소수점 Infinity 또는 NaN 값을 정수 표현으로 직렬화하거나 역직렬화하려고 하면 드라이버에서 OverflowException이 발생합니다.

드라이버는 POCO에 지정된 순서대로 BSON 필드에 속성을 직렬화합니다. 기존 스키마와 일치하도록 사용자 지정 순서로 속성을 저장하려면 [BsonElement()] 특성에 매개변수가 명명된 Order를 지정할 수 있습니다. 다음 코드 샘플에서 드라이버는 Style 속성 뒤에 YearBuilt 속성을 저장합니다.

public class House
{
public Guid Id { get; set; }
[BsonElement(Order = 2)]
public int YearBuilt { get; set; }
[BsonElement(Order = 1)]
public string Style { get; set; }
}

속성에 명시적 Order가 없는 경우 드라이버는 명시적 값이 있는 속성 다음에 해당 속성을 기본 순서로 직렬화합니다.

기본적으로 드라이버는 Id, id 또는 _id라는 공용 속성을 BSON _id 필드에 매핑합니다. _id 필드에 매핑할 속성을 명시적으로 선택하려면 [BsonId()] 특성을 사용합니다. 다음 코드 샘플에서는 Identifier 속성을 _id 필드에 매핑합니다.

public class House
{
[BsonId]
public string Identifier { get; set; }
}

경고

여러 ID 필드

[BsonId()] 특성을 사용하여 둘 이상의 속성을 _id 필드로 식별하면 드라이버는 DuplicateBsonMemberMapAttributeException을 발생시킵니다. 동일한 데이터베이스 필드를 두 번 이상 지정하는 경우(예시: POCO에 Id_id라는 속성이 포함된 경우) 드라이버는 BsonSerializationException을 발생시킵니다.

참고

중첩된 문서 ID

이 섹션에서 설명하는 _id 필드 매핑 로직은 루트 문서 에만 적용되며 중첩된 문서에는 적용 되지 않습니다.

기본적으로 드라이버는 정의되지 않은 속성을 null 값이 있는 필드로 직렬화합니다. 직렬화 중에 정의되지 않은 속성을 무시하려면 [BsonIgnore] 특성을 사용합니다. 다음 코드는 YearBuilt 속성이 정의되지 않은 경우 드라이버가 해당 속성을 직렬화하지 못하게 하는 방법을 보여줍니다.

public class House
{
public Guid Id { get; set; }
[BsonIgnore]
public int YearBuilt { get; set; }
public string Style { get; set; }
}

C#에서 속성은 값을 할당하기 전까지는 기본값이 있습니다. 기본값은 속성의 데이터 유형에 따라 다릅니다. 예를 들어, 참조 유형 속성의 기본값은 null입니다.

속성에 대해 다른 기본값을 지정하려면 [BsonDefaultValue()] 특성을 속성에 적용하고 원하는 기본값을 인수로 전달합니다.

다음 코드 예시에서는 [BsonDefaultValue()] 특성을 YearBuilt 속성에 적용합니다. 이 속성에 값이 할당될 때까지 해당 값은 1900입니다.

public class House
{
public Guid Id { get; set; }
[BsonDefaultValue(1900)]
public int YearBuilt { get; set; }
}

다음 예시와 같이 클래스 맵을 등록할 때 속성에 대해 다른 기본값을 지정할 수도 있습니다.

BsonClassMap.RegisterClassMap<House>(classMap =>
{
classMap.AutoMap();
classMap.MapMember(h => h.YearBuilt).SetDefaultValue(1900);
});

기본적으로 .NET/C# 드라이버는 기본값이 포함된 속성을 포함하여 모든 속성을 직렬화합니다. 기본값이 있는 속성을 무시하도록 드라이버에 지시하려면 [BsonIgnoreIfDefault] 특성을 사용합니다.

다음 코드 예시에서는 [BsonIgnoreIfDefault] 특성을 YearBuilt 속성에 적용합니다. 이 속성의 값이 데이터 유형의 기본값( int 속성의 경우 0)인 경우 드라이버는 이를 직렬화하지 않습니다.

public class House
{
public Guid Id { get; set; }
[BsonIgnoreIfDefault]
public int YearBuilt { get; set; }
}

다음 예시와 같이 클래스 맵을 등록할 때 기본값이 포함된 속성을 무시하도록 드라이버에 지시할 수도 있습니다.

BsonClassMap.RegisterClassMap<House>(classMap =>
{
classMap.AutoMap();
classMap.MapMember(h => h.YearBuilt).SetIgnoreIfDefault(true);
});

속성에 다른 기본값을 지정하고 이 기본값이 포함된 경우 해당 속성을 무시하도록 드라이버에 지시할 수 있습니다. 이렇게 하려면 다음 코드 예시와 같이 [BsonDefaultValue()][BsonIgnoreIfDefault] 특성을 속성에 모두 적용합니다.

public class House
{
public Guid Id { get; set; }
[BsonDefaultValue(1900)]
[BsonIgnoreIfDefault]
public int YearBuilt { get; set; }
}

이전 코드 예시에서는 다음과 같은 직렬화 동작을 설정합니다.

  • YearBuilt 속성에 값이 할당되지 않은 경우 지정된 기본값은 1900입니다.

  • 1900이 속성의 기본값이므로 드라이버는 이 값이 있는 경우 속성을 무시합니다.

MongoDB 컬렉션의 모든 문서에는 고유 ID가 있어야 합니다. 객체를 컬렉션에 직렬화할 때 Id 속성에 해당 데이터 유형의 기본값이 포함되어 있으면 .NET/C# 드라이버는 해당 객체를 직렬화하지 않습니다. 대신 드라이버는 속성에 대한 고유 ID 값을 생성합니다.

Id 속성이 Guid, ObjectId 또는 string 유형인 경우 드라이버는 자체적으로 ID 값을 생성할 수 있습니다. Id 속성이 다른 데이터 유형인 경우 드라이버가 값을 생성하는 데 사용하는 IIdGenerator 유형을 지정해야 합니다. IIdGenerator 유형을 지정하려면 [BsonId(IdGenerator)] 특성을 속성에 적용하고 IIdGenerator 유형을 인수로 전달합니다.

.NET/C# 드라이버에는 다음과 같은 IIdGenerator 유형이 포함되어 있습니다.

Id 필드 데이터 유형
IIdGenerator 유형
Guid COMB 알고리즘에 의해 생성된 값
CombGuidGenerator
BsonObjectId
BsonObjectIdGenerator

다음 코드 예시에서 House 클래스의 Id 속성에 기본값(null)이 포함된 경우 드라이버는 직렬화 중에 COMB 알고리즘을 사용하여 고유한 값을 생성합니다.

public class House
{
[BsonId(IdGenerator = typeof(CombGuidGenerator))]
public Guid Id { get; set; }
}

참고

이전 코드 예시에서 Id 속성에 [BsonId(IdGenerator)] 특성이 없는 경우 드라이버는 Comb가 아닌 GUID를 생성하여 Id 필드에 할당합니다.

다음 예와 같이 클래스 맵을 등록하는 동안 IIdGenerator 유형을 지정할 수도 있습니다.

BsonClassMap.RegisterClassMap<House>(classMap =>
{
classMap.AutoMap();
classMap.MapIdMember(h => h.Id).SetIdGenerator(CombGuidGenerator.Instance);
});

여러 클래스에 대한 IIdGenerator 지정

RegisterIdGenerator() 메서드를 사용하여 특정 데이터 유형의 모든 Id 속성에 대해 단일 IIdGenerator를 지정할 수 있습니다. 다음 코드 예시는 드라이버가 모든 Guid ID에 대해 CombGuidGenerator 유형을 사용하도록 지시합니다.

BsonSerializer.RegisterIdGenerator(
typeof(Guid),
CombGuidGenerator.Instance
);

NET/C# 드라이버에는 Id 속성의 유효성을 검사하고 ID가 유효하지 않은 경우 예외를 발생시키는 IIdGenerator 유형도 포함되어 있습니다. 다음 표에는 이러한 유형이 나와 있습니다.

ID 유효성 검사
IIdGenerator 유형
null이 아님
NullIdChecker
0이 아님
ZeroIdChecker<T>

다음 코드 예시에서 House 클래스의 Id 속성에 기본값(null)이 포함된 경우 드라이버에서 예외가 발생합니다.

public class House
{
[BsonId(IdGenerator = typeof(NullIdChecker))]
public Guid Id { get; set; }
}

.NET/C# 드라이버가 DateTime 속성을 직렬화하는 방법을 사용자 지정하려면 [BsonDateTimeOptions()] 특성을 사용하고 원하는 설정을 인수로 지정합니다.

DateTime 속성이 날짜만 나타내는 경우 [BsonDateTimeOptions(DateOnly = true)] 특성을 적용할 수 있습니다. 그렇게 하면 드라이버는 값에 대해 시간대 변환을 수행하지 않습니다.

다음 코드 예시에서 PatientRecord 클래스는 DateOfBirth 속성에 DateTime을 사용합니다. [BsonDateTimeOptions(DateOnly = true)] 특성은 속성에 날짜만 포함되어 있음을 나타냅니다.

public class PatientRecord
{
public Guid Id { get; set; }
[BsonDateTimeOptions(DateOnly = true)]
public DateTime DateOfBirth { get; set; }
}

[BsonDateTimeOptions()] 특성을 사용하여 DateTime 속성의 DateTimeKind를 지정할 수도 있습니다. 다음 코드 예시에서 PatientRecord 클래스에는 DateTime 유형의 AppointmentTime 속성이 있습니다. [BsonDateTimeOptions(Kind = DateTimeKind.Local)] 특성은 속성 값의 시간 구성 요소가 현지 시간임을 나타냅니다. 드라이버는 이 속성을 직렬화할 때 시간을 MongoDB에 저장된 표준 시간 형식인 UTC로 변환합니다.

public class PatientRecord
{
public Guid Id { get; set; }
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
public DateTime AppointmentTime { get; set; }
}

클래스 맵을 등록할 때 이전 DateTime 옵션 중 하나 또는 둘 다를 지정할 수도 있습니다.

BsonClassMap.RegisterClassMap<House>(classMap =>
{
classMap.AutoMap();
classMap.MapMember(p => p.DateOfBirth)
.SetSerializer(new DateTimeSerializer(dateOnly: true));
classMap.MapMember(p => p.AppointmentTime)
.SetSerializer(new DateTimeSerializer(DateTimeKind.Local));
});

DateTimeKind Values

DateTimeKind 열거형은 .NET 프레임워크의 일부입니다. 해당 멤버에 대한 자세한 내용은 DateTimeKind 열거형에 대한 Microsoft 문서를 참조하세요.

DictionaryRepresentation 열거형은 .NET/C# 드라이버가 Dictionary 인스턴스를 직렬화할 수 있는 형식을 정의합니다. 이 열거형에는 다음 노드가 포함됩니다.

  • 문서: (기본값) 드라이버는 DictionaryBsonDocument로 직렬화합니다. 사전의 각 항목은 항목 키와 이름이 같고 값이 항목 값과 같은 BsonElement입니다. 사전의 모든 키가 유효한 BsonElement 이름이기도 한 문자열인 경우에만 이 표현을 사용할 수 있습니다.

  • ArrayOfArrays: 드라이버가 사전을 BsonArray로 직렬화합니다. 사전의 각 항목은 항목 키와 항목 값을 포함하는 중첩된 두 요소로 구성된 BsonArray입니다.

  • ArrayOfDocuments: 드라이버는 사전을 BsonArray로 직렬화합니다. 사전의 각 항목은 { k : key, v : value } 형식의 중첩된 BsonDocument입니다. 키와 값에 요소 이름이 태그되어 있으므로 이 형식은 ArrayOfArrays보다 더 직관적으로 쿼리할 수 있습니다.

다음 코드 예시에서 RoomSizes 속성은 집의 각 방과 해당 크기를 포함하는 사전입니다. [BsonDictionaryOptions()] 특성은 이 속성을 BsonArray 객체로, 사전의 각 항목을 { k : "<room>", v : <size> } 형식의 BsonDocument로 직렬화하도록 .NET/C# 드라이버에 지시합니다.

public class House
{
public Guid Id { get; set; }
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)]
public Dictionary<string, float> RoomSizes { get; set; }
}

다음 예시와 같이 클래스 맵을 등록할 때 사전의 직렬화 형식을 지정할 수도 있습니다.

BsonClassMap.RegisterClassMap<House>(classMap =>
{
classMap.AutoMap();
classMAp.MapMember(h => h.RoomSizes)
.SetSerializer(new DictionaryInterfaceImplementerSerializer<Dictionary<string, float>>
(DictionaryRepresentation.ArrayOfDocuments));
});

다음 예에서는 사용자 지정 필드 매핑 사양이 있는 Clothing 문서를 MongoDB에 삽입하는 방법을 보여줍니다.

다음 코드는 이러한 직렬화 관련 특성을 가진 Clothing 클래스를 정의합니다.

  • [BsonElement()]카멜식 명명 규칙으로 사용자 지정 필드 이름을 지정합니다.

  • [BsonRepresentation()]BSON Double 유형으로 Price 필드의 직렬화를 지정합니다.

  • [BsonDefaultValue()]값이 할당되지 않은 경우 Name 속성을 "Generic item"으로 설정합니다.

  • [BsonDateTimeOptions(DateOnly = true)]DateTime 속성이 관련된 시간 없이 날짜 값만 나타내도록 지정합니다.

public class Clothing
{
public ObjectId Id { get; set; }
[BsonElement("name")]
[BsonDefaultValue("Generic item")]
public string Name { get; set; }
[BsonElement("inStock")]
public bool InStock { get; set; }
[BsonElement("price")]
[BsonRepresentation(BsonType.Decimal128)]
public decimal Price { get; set; }
[BsonElement("colorSelection")]
public List<string> ColorSelection { get; set; }
[BsonElement("listedDate")]
[BsonDateTimeOptions(DateOnly = true)]
public DateTime ListedDate { get; set; }
[BsonElement("sizeGuide")]
public Dictionary<string, string> SizeGuide { get; set; }
}

다음 코드는 Clothing 객체를 인스턴스화하고 문서를 컬렉션에 삽입합니다.

var doc = new Clothing
{
Name = "Denim Jacket",
InStock = false,
Price = 32.99m,
ColorSelection = new List<string> { "dark wash", "light wash" },
ListedDate = DateTime.Parse("Jan 1, 2007"),
SizeGuide = new Dictionary<string, string>()
{
{"Small", "Chest: 38\", Waist: 38\", Shoulders: 15\""},
{"Medium", "Chest: 40\", Waist: 40\", Shoulders: 15.5\""},
{"Large", "Chest: 42\", Waist: 40\", Shoulders: 16\""}
}
};
_myColl.InsertOne(doc);

삽입된 문서의 BSON 표현은 다음과 같습니다.

{
"_id": ObjectId("..."),
"name": "Denim Jacket",
"inStock": false,
"price": 32.99,
"colorSelection": [ "dark wash", "light wash" ],
"listedDate" : ISODate("2007-01-01T00:00:00Z"),
"sizeGuide" : {
"Small" : "Chest: 38\", Waist: 38\", Shoulders: 15\"",
"Medium" : "Chest: 40\", Waist: 40\", Shoulders: 15.5\"",
"Large" : "Chest: 42\", Waist: 40\", Shoulders: 16\""
}
}

직렬화 관련 특성의 전체 목록은 Serialization.Attributes API(직렬화 특성 API) 문서를 참조하세요.

POCO를 사용한 추가 읽기 및 쓰기 작업 예시는 사용 예시 또는 CRUD 기본 사항 페이지를 참조하세요.

드라이버가 BSON 문서를 POCO에 매핑하는 방법에 대해 자세히 알아보려면 클래스 매핑을 참조하세요.

이 가이드에서 사용되는 메서드 또는 유형에 대해 자세히 알아보려면 다음 API 설명서를 참조하세요.

돌아가기

클래스 매핑