/src/UnitTests/ExpressionBridge.cs

https://github.com/ngbrown/AutoMapper · C# · 310 lines · 267 code · 42 blank · 1 comment · 5 complexity · d17fba256d72a74db8280582f96465ec MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq.Expressions;
  4. using Should;
  5. using Xunit;
  6. using System.Linq;
  7. namespace AutoMapper.UnitTests
  8. {
  9. namespace ExpressionBridge
  10. {
  11. using QueryableExtensions;
  12. public class SimpleProductDto
  13. {
  14. public string Name { set; get; }
  15. public string ProductSubcategoryName { set; get; }
  16. public string CategoryName { set; get; }
  17. }
  18. public class ExtendedProductDto
  19. {
  20. public string Name { set; get; }
  21. public string ProductSubcategoryName { set; get; }
  22. public string CategoryName { set; get; }
  23. public List<BillOfMaterialsDto> BOM { set; get; }
  24. }
  25. public class ComplexProductDto
  26. {
  27. public string Name { get; set; }
  28. public ProductSubcategoryDto ProductSubcategory { get; set; }
  29. }
  30. public class ProductSubcategoryDto
  31. {
  32. public string Name { get; set; }
  33. public ProductCategoryDto ProductCategory { get; set; }
  34. }
  35. public class ProductCategoryDto
  36. {
  37. public string Name { get; set; }
  38. }
  39. public class AbstractProductDto
  40. {
  41. public string Name { set; get; }
  42. public string ProductSubcategoryName { set; get; }
  43. public string CategoryName { set; get; }
  44. public List<ProductTypeDto> Types { get; set; }
  45. }
  46. public abstract class ProductTypeDto { }
  47. public class ProdTypeA : ProductTypeDto {}
  48. public class ProdTypeB : ProductTypeDto {}
  49. public class ProductTypeConverter : TypeConverter<ProductType, ProductTypeDto>
  50. {
  51. protected override ProductTypeDto ConvertCore(ProductType source)
  52. {
  53. if (source.Name == "A")
  54. return new ProdTypeA();
  55. if (source.Name == "B")
  56. return new ProdTypeB();
  57. throw new ArgumentException();
  58. }
  59. }
  60. public class ProductType
  61. {
  62. public string Name { get; set; }
  63. }
  64. public class BillOfMaterialsDto
  65. {
  66. public int BillOfMaterialsID { set; get; }
  67. }
  68. public class Product
  69. {
  70. public string Name { get; set; }
  71. public ProductSubcategory ProductSubcategory { get; set; }
  72. public List<BillOfMaterials> BillOfMaterials { set; get; }
  73. public List<ProductType> Types { get; set; }
  74. }
  75. public class ProductSubcategory
  76. {
  77. public string Name { get; set; }
  78. public ProductCategory ProductCategory { get; set; }
  79. }
  80. public class ProductCategory
  81. {
  82. public string Name { get; set; }
  83. }
  84. public class BillOfMaterials
  85. {
  86. public int BillOfMaterialsID { set; get; }
  87. }
  88. public class When_mapping_using_expressions : NonValidatingSpecBase
  89. {
  90. private List<Product> _products;
  91. private Expression<Func<Product, SimpleProductDto>> _simpleProductConversionLinq;
  92. private Expression<Func<Product, ExtendedProductDto>> _extendedProductConversionLinq;
  93. private Expression<Func<Product, AbstractProductDto>> _abstractProductConversionLinq;
  94. private List<SimpleProductDto> _simpleProducts;
  95. private List<ExtendedProductDto> _extendedProducts;
  96. protected override void Establish_context()
  97. {
  98. Mapper.Initialize(cfg =>
  99. {
  100. cfg.CreateMap<Product, SimpleProductDto>()
  101. .ForMember(m => m.CategoryName, dst => dst.MapFrom(p => p.ProductSubcategory.ProductCategory.Name));
  102. cfg.CreateMap<Product, ExtendedProductDto>()
  103. .ForMember(m => m.CategoryName, dst => dst.MapFrom(p => p.ProductSubcategory.ProductCategory.Name))
  104. .ForMember(m => m.BOM, dst => dst.MapFrom(p => p.BillOfMaterials));
  105. cfg.CreateMap<BillOfMaterials, BillOfMaterialsDto>();
  106. cfg.CreateMap<Product, ComplexProductDto>();
  107. cfg.CreateMap<ProductSubcategory, ProductSubcategoryDto>();
  108. cfg.CreateMap<ProductCategory, ProductCategoryDto>();
  109. cfg.CreateMap<Product, AbstractProductDto>();
  110. cfg.CreateMap<ProductType, ProductTypeDto>()
  111. //.ConvertUsing(x => ProductTypeDto.GetProdType(x));
  112. .ConvertUsing<ProductTypeConverter>();
  113. });
  114. _simpleProductConversionLinq = Mapper.Engine.CreateMapExpression<Product, SimpleProductDto>();
  115. _extendedProductConversionLinq = Mapper.Engine.CreateMapExpression<Product, ExtendedProductDto>();
  116. _abstractProductConversionLinq = Mapper.Engine.CreateMapExpression<Product, AbstractProductDto>();
  117. _products = new List<Product>()
  118. {
  119. new Product
  120. {
  121. Name = "Foo",
  122. ProductSubcategory = new ProductSubcategory
  123. {
  124. Name = "Bar",
  125. ProductCategory = new ProductCategory
  126. {
  127. Name = "Baz"
  128. }
  129. },
  130. BillOfMaterials = new List<BillOfMaterials>
  131. {
  132. new BillOfMaterials
  133. {
  134. BillOfMaterialsID = 5
  135. }
  136. }
  137. ,
  138. Types = new List<ProductType>
  139. {
  140. new ProductType() { Name = "A" },
  141. new ProductType() { Name = "B" },
  142. new ProductType() { Name = "A" }
  143. }
  144. }
  145. };
  146. }
  147. protected override void Because_of()
  148. {
  149. var queryable = _products.AsQueryable();
  150. _simpleProducts = queryable.Select(_simpleProductConversionLinq).ToList();
  151. _extendedProducts = queryable.Select(_extendedProductConversionLinq).ToList();
  152. }
  153. [Fact]
  154. public void Should_map_and_flatten()
  155. {
  156. _simpleProducts.Count.ShouldEqual(1);
  157. _simpleProducts[0].Name.ShouldEqual("Foo");
  158. _simpleProducts[0].ProductSubcategoryName.ShouldEqual("Bar");
  159. _simpleProducts[0].CategoryName.ShouldEqual("Baz");
  160. _extendedProducts.Count.ShouldEqual(1);
  161. _extendedProducts[0].Name.ShouldEqual("Foo");
  162. _extendedProducts[0].ProductSubcategoryName.ShouldEqual("Bar");
  163. _extendedProducts[0].CategoryName.ShouldEqual("Baz");
  164. _extendedProducts[0].BOM.Count.ShouldEqual(1);
  165. _extendedProducts[0].BOM[0].BillOfMaterialsID.ShouldEqual(5);
  166. }
  167. [Fact]
  168. public void Should_use_extension_methods()
  169. {
  170. var queryable = _products.AsQueryable();
  171. var simpleProducts = queryable.Project().To<SimpleProductDto>().ToList();
  172. simpleProducts.Count.ShouldEqual(1);
  173. simpleProducts[0].Name.ShouldEqual("Foo");
  174. simpleProducts[0].ProductSubcategoryName.ShouldEqual("Bar");
  175. simpleProducts[0].CategoryName.ShouldEqual("Baz");
  176. var extendedProducts = queryable.Project().To<ExtendedProductDto>().ToList();
  177. extendedProducts.Count.ShouldEqual(1);
  178. extendedProducts[0].Name.ShouldEqual("Foo");
  179. extendedProducts[0].ProductSubcategoryName.ShouldEqual("Bar");
  180. extendedProducts[0].CategoryName.ShouldEqual("Baz");
  181. extendedProducts[0].BOM.Count.ShouldEqual(1);
  182. extendedProducts[0].BOM[0].BillOfMaterialsID.ShouldEqual(5);
  183. var complexProducts = queryable.Project().To<ComplexProductDto>().ToList();
  184. complexProducts.Count.ShouldEqual(1);
  185. complexProducts[0].Name.ShouldEqual("Foo");
  186. complexProducts[0].ProductSubcategory.Name.ShouldEqual("Bar");
  187. complexProducts[0].ProductSubcategory.ProductCategory.Name.ShouldEqual("Baz");
  188. }
  189. #if !SILVERLIGHT
  190. [Fact(Skip = "Won't work for normal query providers")]
  191. public void List_of_abstract_should_be_mapped()
  192. {
  193. var mapped = Mapper.Map<AbstractProductDto>(_products[0]);
  194. mapped.Types.Count.ShouldEqual(3);
  195. var queryable = _products.AsQueryable();
  196. var abstractProducts = queryable.Project().To<AbstractProductDto>().ToList();
  197. abstractProducts[0].Types.Count.ShouldEqual(3);
  198. abstractProducts[0].Types[0].GetType().ShouldEqual(typeof (ProdTypeA));
  199. abstractProducts[0].Types[1].GetType().ShouldEqual(typeof (ProdTypeB));
  200. abstractProducts[0].Types[2].GetType().ShouldEqual(typeof (ProdTypeA));
  201. }
  202. #endif
  203. }
  204. #if !NETFX_CORE && !SILVERLIGHT
  205. namespace CircularReferences
  206. {
  207. public class A
  208. {
  209. public int AP1 { get; set; }
  210. public string AP2 { get; set; }
  211. public virtual B B { get; set; }
  212. }
  213. public class B
  214. {
  215. public B()
  216. {
  217. BP2 = new HashSet<A>();
  218. }
  219. public int BP1 { get; set; }
  220. public virtual ICollection<A> BP2 { get; set; }
  221. }
  222. public class AEntity
  223. {
  224. public int AP1 { get; set; }
  225. public string AP2 { get; set; }
  226. public virtual BEntity B { get; set; }
  227. }
  228. public class BEntity
  229. {
  230. public BEntity()
  231. {
  232. BP2 = new HashSet<AEntity>();
  233. }
  234. public int BP1 { get; set; }
  235. public virtual ICollection<AEntity> BP2 { get; set; }
  236. }
  237. public class C
  238. {
  239. public C Value { get; set; }
  240. }
  241. public class When_mapping_circular_references : AutoMapperSpecBase
  242. {
  243. private IQueryable<BEntity> _bei;
  244. protected override void Establish_context()
  245. {
  246. Mapper.CreateMap<BEntity, B>().MaxDepth(3);
  247. Mapper.CreateMap<AEntity, A>().MaxDepth(3);
  248. }
  249. protected override void Because_of()
  250. {
  251. var be = new BEntity();
  252. be.BP1 = 3;
  253. be.BP2.Add(new AEntity() { AP1 = 1, AP2 = "hello", B = be });
  254. be.BP2.Add(new AEntity() { AP1 = 2, AP2 = "two", B = be });
  255. var belist = new List<BEntity>();
  256. belist.Add(be);
  257. _bei = belist.AsQueryable();
  258. }
  259. [Fact]
  260. public void Should_not_throw_exception()
  261. {
  262. typeof(StackOverflowException).ShouldNotBeThrownBy(() => _bei.Project().To<B>());
  263. }
  264. }
  265. }
  266. #endif
  267. }
  268. }