MongoDBRef.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /* Copyright 2010-present MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.Collections.Generic;
  17. using MongoDB.Bson;
  18. using MongoDB.Bson.IO;
  19. using MongoDB.Bson.Serialization;
  20. using MongoDB.Bson.Serialization.Attributes;
  21. using MongoDB.Bson.Serialization.Serializers;
  22. namespace MongoDB.Driver
  23. {
  24. /// <summary>
  25. /// Represents a DBRef (a convenient way to refer to a document).
  26. /// </summary>
  27. [BsonSerializer(typeof(MongoDBRefSerializer))]
  28. public class MongoDBRef : IEquatable<MongoDBRef>
  29. {
  30. // private fields
  31. private string _databaseName;
  32. private string _collectionName;
  33. private BsonValue _id;
  34. // constructors
  35. // default constructor is private and only used for deserialization
  36. private MongoDBRef()
  37. {
  38. }
  39. /// <summary>
  40. /// Creates a MongoDBRef.
  41. /// </summary>
  42. /// <param name="collectionName">The name of the collection that contains the document.</param>
  43. /// <param name="id">The Id of the document.</param>
  44. public MongoDBRef(string collectionName, BsonValue id)
  45. : this(null, collectionName, id)
  46. {
  47. }
  48. /// <summary>
  49. /// Creates a MongoDBRef.
  50. /// </summary>
  51. /// <param name="databaseName">The name of the database that contains the document.</param>
  52. /// <param name="collectionName">The name of the collection that contains the document.</param>
  53. /// <param name="id">The Id of the document.</param>
  54. public MongoDBRef(string databaseName, string collectionName, BsonValue id)
  55. {
  56. if (collectionName == null)
  57. {
  58. throw new ArgumentNullException("collectionName");
  59. }
  60. if (id == null)
  61. {
  62. throw new ArgumentNullException("id");
  63. }
  64. _databaseName = databaseName;
  65. _collectionName = collectionName;
  66. _id = id;
  67. }
  68. // public properties
  69. /// <summary>
  70. /// Gets the name of the database that contains the document.
  71. /// </summary>
  72. public string DatabaseName
  73. {
  74. get { return _databaseName; }
  75. }
  76. /// <summary>
  77. /// Gets the name of the collection that contains the document.
  78. /// </summary>
  79. public string CollectionName
  80. {
  81. get { return _collectionName; }
  82. }
  83. /// <summary>
  84. /// Gets the Id of the document.
  85. /// </summary>
  86. public BsonValue Id
  87. {
  88. get { return _id; }
  89. }
  90. // public operators
  91. /// <summary>
  92. /// Determines whether two specified MongoDBRef objects have different values.
  93. /// </summary>
  94. /// <param name="lhs">The first value to compare, or null.</param>
  95. /// <param name="rhs">The second value to compare, or null.</param>
  96. /// <returns>True if the value of lhs is different from the value of rhs; otherwise, false.</returns>
  97. public static bool operator !=(MongoDBRef lhs, MongoDBRef rhs)
  98. {
  99. return !MongoDBRef.Equals(lhs, rhs);
  100. }
  101. /// <summary>
  102. /// Determines whether two specified MongoDBRef objects have the same value.
  103. /// </summary>
  104. /// <param name="lhs">The first value to compare, or null.</param>
  105. /// <param name="rhs">The second value to compare, or null.</param>
  106. /// <returns>True if the value of lhs is the same as the value of rhs; otherwise, false.</returns>
  107. public static bool operator ==(MongoDBRef lhs, MongoDBRef rhs)
  108. {
  109. return MongoDBRef.Equals(lhs, rhs);
  110. }
  111. // public static methods
  112. /// <summary>
  113. /// Determines whether two specified MongoDBRef objects have the same value.
  114. /// </summary>
  115. /// <param name="lhs">The first value to compare, or null.</param>
  116. /// <param name="rhs">The second value to compare, or null.</param>
  117. /// <returns>True if the value of lhs is the same as the value of rhs; otherwise, false.</returns>
  118. public static bool Equals(MongoDBRef lhs, MongoDBRef rhs)
  119. {
  120. if ((object)lhs == null) { return (object)rhs == null; }
  121. return lhs.Equals(rhs);
  122. }
  123. // public methods
  124. /// <summary>
  125. /// Determines whether this instance and another specified MongoDBRef object have the same value.
  126. /// </summary>
  127. /// <param name="rhs">The MongoDBRef object to compare to this instance.</param>
  128. /// <returns>True if the value of the rhs parameter is the same as this instance; otherwise, false.</returns>
  129. public bool Equals(MongoDBRef rhs)
  130. {
  131. if ((object)rhs == null || GetType() != rhs.GetType()) { return false; }
  132. if ((object)this == (object)rhs) { return true; }
  133. // note: _databaseName can be null
  134. return string.Equals(_databaseName, rhs._databaseName) && _collectionName.Equals(rhs._collectionName) && _id.Equals(rhs._id);
  135. }
  136. /// <summary>
  137. /// Determines whether this instance and a specified object, which must also be a MongoDBRef object, have the same value.
  138. /// </summary>
  139. /// <param name="obj">The MongoDBRef object to compare to this instance.</param>
  140. /// <returns>True if obj is a MongoDBRef object and its value is the same as this instance; otherwise, false.</returns>
  141. public override bool Equals(object obj)
  142. {
  143. return Equals(obj as MongoDBRef); // works even if obj is null or of a different type
  144. }
  145. /// <summary>
  146. /// Returns the hash code for this MongoDBRef object.
  147. /// </summary>
  148. /// <returns>A 32-bit signed integer hash code.</returns>
  149. public override int GetHashCode()
  150. {
  151. // see Effective Java by Joshua Bloch
  152. int hash = 17;
  153. hash = 37 * hash + ((_databaseName == null) ? 0 : _databaseName.GetHashCode());
  154. hash = 37 * hash + _collectionName.GetHashCode();
  155. hash = 37 * hash + _id.GetHashCode();
  156. return hash;
  157. }
  158. /// <summary>
  159. /// Returns a string representation of the value.
  160. /// </summary>
  161. /// <returns>A string representation of the value.</returns>
  162. public override string ToString()
  163. {
  164. if (_databaseName == null)
  165. {
  166. return string.Format("new MongoDBRef(\"{0}\", {1})", _collectionName, _id);
  167. }
  168. else
  169. {
  170. return string.Format("new MongoDBRef(\"{0}\", \"{1}\", {2})", _databaseName, _collectionName, _id);
  171. }
  172. }
  173. }
  174. /// <summary>
  175. /// Represents a serializer for MongoDBRefs.
  176. /// </summary>
  177. public class MongoDBRefSerializer : ClassSerializerBase<MongoDBRef>, IBsonDocumentSerializer
  178. {
  179. // private constants
  180. private static class Flags
  181. {
  182. public const long CollectionName = 1;
  183. public const long Id = 2;
  184. public const long DatabaseName = 4;
  185. }
  186. // private fields
  187. private readonly SerializerHelper _helper;
  188. // constructors
  189. /// <summary>
  190. /// Initializes a new instance of the <see cref="MongoDBRefSerializer"/> class.
  191. /// </summary>
  192. public MongoDBRefSerializer()
  193. {
  194. _helper = new SerializerHelper
  195. (
  196. new SerializerHelper.Member("$ref", Flags.CollectionName),
  197. new SerializerHelper.Member("$id", Flags.Id),
  198. new SerializerHelper.Member("$db", Flags.DatabaseName, isOptional: true)
  199. );
  200. }
  201. // public methods
  202. /// <summary>
  203. /// Tries to get the serialization info for a member.
  204. /// </summary>
  205. /// <param name="memberName">Name of the member.</param>
  206. /// <param name="serializationInfo">The serialization information.</param>
  207. /// <returns>
  208. /// <c>true</c> if the serialization info exists; otherwise <c>false</c>.
  209. /// </returns>
  210. public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
  211. {
  212. string elementName;
  213. IBsonSerializer serializer;
  214. switch (memberName)
  215. {
  216. case "DatabaseName":
  217. elementName = "$db";
  218. serializer = new StringSerializer();
  219. break;
  220. case "CollectionName":
  221. elementName = "$ref";
  222. serializer = new StringSerializer();
  223. break;
  224. case "Id":
  225. elementName = "$id";
  226. serializer = BsonValueSerializer.Instance;
  227. break;
  228. default:
  229. serializationInfo = null;
  230. return false;
  231. }
  232. serializationInfo = new BsonSerializationInfo(elementName, serializer, serializer.ValueType);
  233. return true;
  234. }
  235. // protected methods
  236. /// <summary>
  237. /// Deserializes a value.
  238. /// </summary>
  239. /// <param name="context">The deserialization context.</param>
  240. /// <param name="args">The deserialization args.</param>
  241. /// <returns>The value.</returns>
  242. protected override MongoDBRef DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args)
  243. {
  244. var bsonReader = context.Reader;
  245. string databaseName = null;
  246. string collectionName = null;
  247. BsonValue id = null;
  248. _helper.DeserializeMembers(context, (elementName, flag) =>
  249. {
  250. switch (flag)
  251. {
  252. case Flags.CollectionName: collectionName = bsonReader.ReadString(); break;
  253. case Flags.Id: id = BsonValueSerializer.Instance.Deserialize(context); break;
  254. case Flags.DatabaseName: databaseName = bsonReader.ReadString(); break;
  255. }
  256. });
  257. return new MongoDBRef(databaseName, collectionName, id);
  258. }
  259. /// <summary>
  260. /// Serializes a value.
  261. /// </summary>
  262. /// <param name="context">The serialization context.</param>
  263. /// <param name="args">The serialization args.</param>
  264. /// <param name="value">The value.</param>
  265. protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, MongoDBRef value)
  266. {
  267. var bsonWriter = context.Writer;
  268. bsonWriter.WriteStartDocument();
  269. bsonWriter.WriteString("$ref", value.CollectionName);
  270. bsonWriter.WriteName("$id");
  271. BsonValueSerializer.Instance.Serialize(context, value.Id);
  272. if (value.DatabaseName != null)
  273. {
  274. bsonWriter.WriteString("$db", value.DatabaseName);
  275. }
  276. bsonWriter.WriteEndDocument();
  277. }
  278. }
  279. }