├── .gitattributes ├── .gitignore ├── CHANGELOG.md ├── License.txt ├── README.md └── src ├── LinqToExcel.Tests ├── App.config ├── CSV_IntegrationTests.cs ├── CSV_SQLStatements_UnitTests.cs ├── CellTest.cs ├── ColumnMappings_IntegrationTests.cs ├── ColumnMappings_SQLStatements_UnitTests.cs ├── Company.cs ├── CompanyBadWithAllowFieldTypeConversionExceptions.cs ├── CompanyGoodWithAllowFieldTypeConversionExceptions.cs ├── CompanyNameWithUnmappedCells.cs ├── CompanyNullable.cs ├── CompanyWithCity.cs ├── CompanyWithColumnAnnotations.cs ├── ConfiguredWorksheetName_IntegrationTests.cs ├── ConfiguredWorksheetName_SQLStatements_UnitTests.cs ├── ConnectionString_UnitTests.cs ├── Convention_IntegrationTests.cs ├── Convention_SQLStatements_UnitTests.cs ├── Excel2007_IntegrationTests.cs ├── ExcelFiles │ ├── Companies.csv │ ├── Companies.xls │ ├── Companies.xlsb │ ├── Companies.xlsm │ ├── Companies.xlsx │ ├── EmptyRows.xls │ ├── NamedRanges.xlsx │ ├── NoHeader.csv │ ├── NoHeader.xls │ └── WorksheetNames.xlsx ├── ExcelQueryFactoryTests.cs ├── IMEX_Tests.cs ├── IndexToColumnNamesTests.cs ├── InvalidCastTests.cs ├── InvalidColumnNamesUsed.cs ├── LinqToExcel.Tests.csproj ├── LogManagerFactory.cs ├── NamedRange_IntegrationTests.cs ├── NamedRange_SQLStatements_UnitTests.cs ├── NoHeader_IntregrationTests.cs ├── NoHeader_SQLStatements_UnitTests.cs ├── PersistentConnection_IntegrationTests.cs ├── Range_IntegrationTests.cs ├── Range_SQLStatements_UnitTests.cs ├── RowTest.cs ├── Row_IntegrationTests.cs ├── Row_SQLStatement_UnitTests.cs ├── SQLLogStatements_Helper.cs ├── SkipEmptyRows_UnitTests.cs ├── Transformations.cs ├── UnSupportedMethods.cs └── WorkSheetNameTests.cs ├── LinqToExcel.sln └── LinqToExcel ├── Attributes └── ExcelColumnAttribute.cs ├── Domain ├── Cell.cs ├── IAllowFieldTypeConversionExceptions.cs ├── IContainsUnmappedCells.cs ├── Row.cs ├── RowNoHeader.cs └── StrictMappingException.cs ├── ExcelQueryFactory.cs ├── Exceptions └── ExcelException.cs ├── Extensions └── CommonExtensions.cs ├── IExcelQueryFactory.cs ├── License.txt ├── LinqToExcel.csproj ├── LinqToExcel.snk ├── Logging ├── ILogManagerFactory.cs └── ILogProvider.cs └── Query ├── ExcelQueryArgs.cs ├── ExcelQueryConstructorArgs.cs ├── ExcelQueryExecutor.cs ├── ExcelQueryable.cs ├── ExcelUtilities.cs ├── OleDbServices.cs ├── ProjectorBuildingExpressionTreeVisitor.cs ├── ResultObjectMapping.cs ├── SqlGeneratorQueryModelVisitor.cs ├── SqlParts.cs ├── StrictMappingType.cs ├── TrimSpacesType.cs └── WhereClauseExpressionTreeVisitor.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | # correctly commit line endings 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | bin64/ 3 | obj/ 4 | tests/ 5 | *.suo 6 | LinqToExcel.xml 7 | *ReSharper* 8 | *.zip 9 | *.nupkg 10 | src/packages/ 11 | *.DotSettings.user 12 | *.csproj.user 13 | .vs/ 14 | *.csproj.user 15 | *.DotSettings.user 16 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ### 2.0.0 (PRERELEASE-2) 4 | * Allow connstring suppression of TransactionScope. Thanks **@freakingawesome**. 5 | * Allow lazy queries using yield statements. Thanks **@freakingawesome**. 6 | * Add means to gather exceptions instead of throwing. Thanks **@freakingawesome**. 7 | * Implemented Source Link for easier debugging. Thanks **@MagicAndre1981**. 8 | 9 | ### 2.0.0 (PRERELEASE) 10 | 11 | * Remove support for Microsoft Jet as it was deprecated many years ago, and only works in 32-bit applications. 12 | * MS Ace driver is now a *requirement*. 13 | * Target AnyCPU 14 | * Target .Net Framework v3.5, v4.5.1, and v4.6. 15 | * Fix `ExcelQueryFactory` not being disposed properly. 16 | * Fix incorrect worksheet names that contain a `$`. 17 | * Remotion.Linq updated, and no longer bundled with project. 18 | * Added support for unary expressions in Linq aggregate functions. 19 | * Added support for primitive value type results to be cast to `Nullable` counterparts. 20 | * Fix "item already inserted" issue in AddTransformation. Thanks **@tkestowicz**. 21 | * Throw Exception with row number and column name/number. Thanks **@achvaicer**. 22 | * Added a method of gathering "unmapped cells". Thanks **@freakingawesome**. 23 | 24 | * Other notes: 25 | * Thanks to **@cuongtranba** for helping to move the project to Nunit. 26 | 27 | 28 | ### 1.11.0 29 | 30 | * Refactorings 31 | * Remove dependency on log4net. 32 | 33 | ### 1.10.1 34 | 35 | * Refactorings 36 | * Manually removing log4net.dll from the package lib folder since it's not needed with the NuGet dependency on log4net 37 | 38 | ### 1.10 39 | 40 | * Refactorings 41 | * Added Log4Net as a dependency in the NuGet file 42 | 43 | ### 1.9 44 | 45 | * Enhancements 46 | * Added support for named ranges (by nkilian) 47 | 48 | ### 1.8.1 49 | 50 | * Refactorings 51 | * Referencing Log4Net through its NuGet package 52 | 53 | ### 1.8 54 | 55 | * enhancements 56 | * added **UsePersistentConnection** option to re-use the same connection for multiple queries. (by acorkery) 57 | * added **ReadOnly** option to open the file in readonly mode 58 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | copyright (c) 2008-2010 Paul Yoder 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | :warning: **This project is not currently being maintained.** :warning: 4 | 5 | It is recommended you find/use an alternate solution. There are newer more capable projects that exist today. 6 | 7 |
8 | 9 | [![Build status](https://ci.appveyor.com/api/projects/status/vdbhqae4b2h86k96?svg=true)](https://ci.appveyor.com/project/mrworkman/linqtoexcel) 10 | [![Open Source Helpers](https://www.codetriage.com/paulyoder/linqtoexcel/badges/users.svg)](https://www.codetriage.com/paulyoder/linqtoexcel) 11 | 12 | # Welcome to the LinqToExcel project 13 | 14 | Linq to Excel is a .Net library that allows you to query Excel spreadsheets using the LINQ syntax. 15 | 16 | Checkout the [introduction video.](http://www.youtube.com/watch?v=t3BEUP0OTFM) 17 | 18 | ## Adding LinqToExcel to your project 19 | 20 | #### NuGet 21 | You can use NuGet to quickly add LinqToExcel to your project. Just search for `linqtoexcel` and install the package. 22 | 23 | #### Access Database Engine 24 | In order to use LinqToExcel, you need to install the Microsoft [Microsoft Access Database Engine 2010 Redistributable](https://www.microsoft.com/en-in/download/details.aspx?id=13255). If it's not installed, you'll get the following exception: 25 | 26 | The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.' 27 | 28 | *Both a 32-bit and 64-bit version are available, select the one that matches your project settings.* You can only have one of them installed at a time. 29 | 30 | ## Query a worksheet with a header row 31 | 32 | The default query expects the first row to be the header row containing column names that match the property names on the generic class being used. It also expects the data to be in the worksheet named "Sheet1". 33 | 34 | ```c# 35 | var excel = new ExcelQueryFactory("excelFileName"); 36 | var indianaCompanies = from c in excel.Worksheet() 37 | where c.State == "IN" 38 | select c; 39 | ``` 40 | 41 | ## Query a specific worksheet by name 42 | 43 | Data from the worksheet named "Sheet1" is queried by default. To query a worksheet with a different name, pass the worksheet name in as an argument. 44 | 45 | ```c# 46 | var excel = new ExcelQueryFactory("excelFileName"); 47 | var oldCompanies = from c in excel.Worksheet("US Companies") //worksheet name = 'US Companies' 48 | where c.LaunchDate < new DateTime(1900, 1, 1) 49 | select c; 50 | ``` 51 | 52 | ## Property to column mapping 53 | 54 | Column names from the worksheet can be mapped to specific property names on the class by using the `AddMapping()` method. The property name can be passed in as a string or a compile time safe expression. 55 | 56 | ```c# 57 | var excel = new ExcelQueryFactory("excelFileName"); 58 | excel.AddMapping(x => x.State, "Providence"); //maps the "State" property to the "Providence" column 59 | excel.AddMapping("Employees", "Employee Count"); //maps the "Employees" property to the "Employee Count" column 60 | 61 | var indianaCompanies = from c in excel.Worksheet() 62 | where c.State == "IN" && c.Employees > 500 63 | select c; 64 | ``` 65 | 66 | Column names can alternately be mapped using the `ExcelColumn` attribute on properties of the class. 67 | 68 | ```c# 69 | public class Company 70 | { 71 | [ExcelColumn("Company Title")] //maps the "Name" property to the "Company Title" column 72 | public string Name { get; set; } 73 | 74 | [ExcelColumn("Providence")] //maps the "State" property to the "Providence" column 75 | public string State { get; set; } 76 | 77 | [ExcelColumn("Employee Count")] //maps the "Employees" property to the "Employee Count" column 78 | public string Employees { get; set; } 79 | } 80 | ``` 81 | 82 | ## Using the LinqToExcel.Row class 83 | 84 | Query results can be returned as LinqToExcel.Row objects which allows you to access a cell's value by using the column name in the string index. Just use the `Worksheet()` method without a generic argument. 85 | 86 | ```c# 87 | var excel = new ExcelQueryFactory("excelFileName"); 88 | var indianaCompanies = from c in excel.Worksheet() 89 | where c["State"] == "IN" || c["Zip"] == "46550" 90 | select c; 91 | ``` 92 | 93 | The LinqToExcel.Row class allows you to easily cast a cell's value by using its `Cast<>()` method 94 | 95 | ```c# 96 | var excel = new ExcelQueryFactory("excelFileName"); 97 | var largeCompanies = from c in excel.Worksheet() 98 | where c["EmployeeCount"].Cast() > 500 99 | select c; 100 | ``` 101 | 102 | ## Query a worksheet without a header row 103 | 104 | Worksheets that do not contain a header row can also be queried by using the `WorksheetNoHeader()` method. The cell values are referenced by index. 105 | 106 | ```c# 107 | var excel = new ExcelQueryFactory("excelFileName"); 108 | var indianaCompanies = from c in excel.WorksheetNoHeader() 109 | where c[2] == "IN" //value in 3rd column 110 | select c; 111 | ``` 112 | 113 | ## Query a named range within a worksheet 114 | 115 | A query can be scoped to only include data from within a named range. 116 | 117 | ```c# 118 | var excel = new ExcelQueryFactory("excelFileName"); 119 | var indianaCompanies = from c in excel.NamedRange("NamedRange") //Selects data within the range named 'NamedRange' 120 | where c.State == "IN" 121 | select c; 122 | ``` 123 | 124 | ## Query a specific range within a worksheet 125 | 126 | Data from only a specific range of cells within a worksheet can be queried as well. (This is not the same as a named range, which is noted above) 127 | 128 | If the first row of the range contains a header row, then use the `WorksheetRange()` method 129 | 130 | ```c# 131 | var excel = new ExcelQueryFactory("excelFileName"); 132 | var indianaCompanies = from c in excel.WorksheetRange("B3", "G10") //Selects data within the B3 to G10 cell range 133 | where c.State == "IN" 134 | select c; 135 | ``` 136 | 137 | If the first row of the range is not a header row, then use the `WorksheetRangeNoHeader()` method 138 | 139 | ```c# 140 | var excel = new ExcelQueryFactory("excelFileName"); 141 | var indianaCompanies = from c in excel.WorksheetRangeNoHeader("B3", "G10") //Selects data within the B3 to G10 cell range 142 | where c[2] == "IN" //value in 3rd column (D column in this case) 143 | select c; 144 | ``` 145 | 146 | ## Query a specific worksheet by index 147 | 148 | A specific worksheet can be queried by its index in relation to the other worksheets in the spreadsheet. 149 | 150 | The worsheets index order is based on their names alphabetically; not the order they appear in Excel. For example, if a spreadsheet contains 2 worksheets: "ten" and "eleven". Although "eleven" is the second worksheet in Excel, it is actually the first index. 151 | 152 | ```c# 153 | var excel = new ExcelQueryFactory("excelFileName"); 154 | var oldCompanies = from c in excel.Worksheet(1) //Queries the second worksheet in alphabetical order 155 | where c.LaunchDate < new DateTime(1900, 1, 1) 156 | select c; 157 | ``` 158 | 159 | ## Apply transformations 160 | 161 | Transformations can be applied to cell values before they are set on the class properties. The example below transforms "Y" values in the "IsBankrupt" column to a boolean value of true. 162 | 163 | ```c# 164 | var excel = new ExcelQueryFactory("excelFileName"); 165 | excel.AddTransformation(x => x.IsBankrupt, cellValue => cellValue == "Y"); 166 | 167 | var bankruptCompanies = from c in excel.Worksheet() 168 | where c.IsBankrupt == true 169 | select c; 170 | ``` 171 | 172 | ## Query CSV files 173 | 174 | Data from CSV files can be queried the same way spreadsheets are queried. 175 | 176 | ```c# 177 | var csv = new ExcelQueryFactory("csvFileName"); 178 | var indianaCompanies = from c in csv.Worksheet() 179 | where c.State == "IN" 180 | select c; 181 | ``` 182 | 183 | ## Query Worksheet Names 184 | 185 | The `GetWorksheetNames()` method can be used to retrieve the list of worksheet names in a spreadsheet. 186 | 187 | ```c# 188 | var excel = new ExcelQueryFactory("excelFileName"); 189 | var worksheetNames = excel.GetWorksheetNames(); 190 | ``` 191 | 192 | ## Query Column Names 193 | 194 | The `GetColumnNames()` method can be used to retrieve the list of column names in a worksheet. 195 | 196 | ```c# 197 | var excel = new ExcelQueryFactory("excelFileName"); 198 | var columnNames = excel.GetColumnNames("worksheetName"); 199 | ``` 200 | 201 | ## Strict Mapping 202 | 203 | The `StrictMapping` property can be set to: 204 | * 'WorksheetStrict' in order to enforce all worksheet columns are mapped to a class property. 205 | * 'ClassStrict' to enforce all class properties are mapped to a worksheet column. 206 | * 'Both' to enforce all worksheet columns map to a class property and vice versa. 207 | 208 | The implied default StrictMapping value is 'None'. A `StrictMappingException` is thrown when the specified mapping condition isn't satisified. 209 | 210 | ```c# 211 | var excel = new ExcelQueryFactory("excelFileName"); 212 | excel.StrictMapping = StrictMappingType.Both; 213 | ``` 214 | 215 | ### Retaining Values from Unmapped Columns 216 | 217 | If you are using `None` or `ClassStrict` mapping, you can retain unmapped columns by implementing the `IContainsUnmappedCells` interface. This will put all values from the unmapped columns into a dictionary on your class named `UnmappedCells`. 218 | 219 | Let's say the only field you're guaranteed to have is a `Name` column, and the rest of the columns can be different per spreadsheet. You could write your `Company` class like this, implementing `IContainsUnmappedCells`: 220 | 221 | ```c# 222 | public class Company : IContainsUnmappedCells 223 | { 224 | public string Name { get; set; } 225 | public IDictionary UnmappedCells { get; } = new Dictionary(); 226 | } 227 | ``` 228 | 229 | Given the following data set: 230 | 231 | Name | CEO | EmployeeCount | StartDate 232 | -------------------------------------- | ------------- | ------------- | ---------- 233 | ACME | Bugs Bunny | 25 | 1918-11-11 234 | Word Made Flesh | Chris Heuertz | | 1994-08-08 235 | Anderson University | James Edwards | | 1917-09-01 236 | 237 | You can query normally and all other fields will be available in the `UnmappedCells` dictionary: 238 | 239 | ```c# 240 | var company = from c in excel.Worksheet() 241 | where c.Name == "ACME" 242 | select c; 243 | 244 | // company.UnmappedCells["CEO"] == "Bugs Bunny" 245 | // company.UnmappedCells["EmployeeCount"].Cast() == 25 246 | // company.UnmappedCells["StartDate"].Cast() == new DateTime(1918, 11, 11) 247 | ``` 248 | 249 | ## Manually setting the database engine 250 | 251 | LinqToExcel can use the Jet or Ace database engine, and it automatically determines the database engine to use by the file extension. You can manually set the database engine with the `DatabaseEngine` property 252 | 253 | ```c# 254 | var excel = new ExcelQueryFactory("excelFileName"); 255 | excel.DatabaseEngine == DatabaseEngine.Ace; 256 | ``` 257 | 258 | ## Trim White Space 259 | 260 | The `TrimSpaces` property can be used to automatically trim leading and trailing white spaces. 261 | 262 | ```c# 263 | var excel = new ExcelQueryFactory("excelFileName"); 264 | excel.TrimSpaces = TrimSpacesType.Both; 265 | ``` 266 | 267 | There are 4 options for TrimSpaces: 268 | * None - does not trim any white space. This is the default 269 | * Both - trims white space from the beginning and end 270 | * Start - trims white space from only the beginning 271 | * End - trims white space from only the end 272 | 273 | ## Persistent Connection 274 | 275 | By default a new connection is created and disposed of for each query ran. If you want to use the same connection on all queries performed by the IExcelQueryFactory then set the `UsePersistentConnection` property to true. 276 | 277 | Make sure you properly dispose the ExcelQueryFactory if you use a persistent connection. 278 | 279 | ```c# 280 | var excel = new ExcelQueryFactory("excelFileName"); 281 | excel.UsePersistentConnection = true; 282 | 283 | try 284 | { 285 | var allCompanies = from c in excel.Worksheet() 286 | select c; 287 | } 288 | finally 289 | { 290 | excel.Dispose(); 291 | } 292 | ``` 293 | 294 | ## ReadOnly Mode 295 | 296 | Set the `ReadOnly` property to true to open the file in readonly mode. The default value is false. 297 | 298 | ```c# 299 | var excel = new ExcelQueryFactory("excelFileName"); 300 | excel.ReadOnly = true; 301 | ``` 302 | 303 | ## Lazy Mode 304 | 305 | Set the `Lazy` property to true to read rows one at a time instead of pulling everything into memory at once. Under the 306 | hood, this is accomplished using C# `yield` statements. 307 | 308 | If you read lazily, you will want to make sure you dispose of the `IEnumerator` when finished. C# will do this 309 | automatically for you in `foreach` statements and most, if not all, LINQ statements (e.g. `FirstOrDefault()` reads the 310 | first row and disposes automatically). 311 | 312 | ```c# 313 | var excel = new ExcelQueryFactory("excelFileName"); 314 | excel.Lazy = true; 315 | ``` 316 | 317 | ## Continuing on Type Conversion Errors 318 | 319 | When mapping a field to a type, if there is a type conversion error, an exception is thrown. You can overcome the 320 | default exception throwing behavior by implementing the `IAllowFieldTypeConversionExceptions` interface on your class. 321 | Any class that implements this interface must carry a non-null list of `ExcelException` in `FieldTypeConversionExceptions`. 322 | If any exceptions occur during the field type conversion, it will be added to this list rather than thrown. 323 | 324 | Note that you should check the exceptions list before accessing any values on your strongly typed row, since any 325 | fields listed in the exception list will be in an indeterminate state. 326 | 327 | ## Suppressing TransactionScope 328 | 329 | By default, the OLE DB Provider will try to enlist in an open TransactionScope and will fail because Excel does not 330 | allow for transactions. To avoid this behavior and opt out of TransactionScope for the connection, set `OleDbServices` 331 | to `AllServicesExceptPoolingAndAutoEnlistment`. 332 | 333 | See [Pooling in the Microsoft Data Access 334 | Components](https://msdn.microsoft.com/en-us/library/ms810829.aspx#Troubleshooting%20MDAC%20Pooling) for more 335 | information. 336 | 337 | ```c# 338 | var excel = new ExcelQueryFactory("excelFileName"); 339 | excel.OleDbServices = Query.OleDbServices.AllServicesExceptPoolingAndAutoEnlistment; 340 | ``` 341 | 342 | ## Encoding 343 | 344 | If the file is in a different encoding use the CodePageIdentifer so the setting is passed to the engine. 345 | 346 | See [Code Page Identifiers](https://docs.microsoft.com/en-us/windows/desktop/intl/code-page-identifiers) for a complete 347 | listing of Code Page Identifiers and their corresponding encoding. 348 | 349 | ```c# 350 | var excel = new ExcelQueryFactory("excelFileName"); 351 | //Set the encoding to UTF-8 352 | excel.CodePageIdentifier = 65001; 353 | ``` 354 | 355 | ## Skip empty rows 356 | 357 | The `SkipEmptyRows` property can be used to skip all rows that do not have any values. 358 | 359 | ```c# 360 | var excel = new ExcelQueryFactory("excelFileName"); 361 | excel.SkipEmptyRows = true; 362 | ``` 363 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/CSV_IntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using System.IO; 5 | 6 | namespace LinqToExcel.Tests 7 | { 8 | [Author("Paul Yoder", "paulyoder@gmail.com")] 9 | [Category("Integration")] 10 | [TestFixture] 11 | public class CSV_IntegrationTests 12 | { 13 | string _fileName; 14 | 15 | [OneTimeSetUp] 16 | public void fs() 17 | { 18 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 19 | var excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 20 | _fileName = Path.Combine(excelFilesDirectory, "Companies.csv"); 21 | } 22 | 23 | [Test] 24 | public void select_all() 25 | { 26 | var companies = from c in ExcelQueryFactory.Worksheet(null, _fileName, null, new LogManagerFactory()) 27 | select c; 28 | 29 | Assert.AreEqual(7, companies.ToList().Count); 30 | } 31 | 32 | [Test] 33 | public void where_contains_string_criteria() 34 | { 35 | var companies = from c in ExcelQueryFactory.Worksheet(null, _fileName, null, new LogManagerFactory()) 36 | where c.Name == "ACME" 37 | select c; 38 | 39 | Assert.AreEqual(1, companies.ToList().Count); 40 | } 41 | 42 | [Test] 43 | public void where_contains_int_criteria() 44 | { 45 | var companies = from c in ExcelQueryFactory.Worksheet(null, _fileName, null, new LogManagerFactory()) 46 | where c.EmployeeCount > 20 47 | select c; 48 | 49 | Assert.AreEqual(5, companies.ToList().Count); 50 | } 51 | 52 | [Test] 53 | public void where_contains_datetime_criteria() 54 | { 55 | var companies = from c in ExcelQueryFactory.Worksheet(null, _fileName, null, new LogManagerFactory()) 56 | where c.StartDate == new DateTime(1980, 8, 23) 57 | select c; 58 | 59 | Assert.AreEqual(1, companies.ToList().Count); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/CSV_SQLStatements_UnitTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using System.IO; 5 | using System.Data; 6 | 7 | namespace LinqToExcel.Tests 8 | { 9 | [Author("Paul Yoder", "paulyoder@gmail.com")] 10 | [Category("Unit")] 11 | [TestFixture] 12 | public class CSV_SQLStatements_UnitTests : SQLLogStatements_Helper 13 | { 14 | string _fileName; 15 | 16 | [OneTimeSetUp] 17 | public void fs() 18 | { 19 | _fileName = Path.Combine(Path.GetTempPath(), "spreadsheet.csv"); 20 | InstantiateLogger(); 21 | } 22 | 23 | [SetUp] 24 | public void s() 25 | { 26 | ClearLogEvents(); 27 | } 28 | 29 | [Test] 30 | public void Connection_string_data_source_is_directory_of_csv_file() 31 | { 32 | var people = from p in ExcelQueryFactory.Worksheet(null, _fileName, null, new LogManagerFactory()) 33 | select p; 34 | 35 | try { people.GetEnumerator(); } 36 | catch (DataException) { } 37 | 38 | var dataSource = GetDataSource(); 39 | Assert.AreEqual(Path.GetDirectoryName(_fileName), dataSource); 40 | } 41 | 42 | [Test] 43 | public void Connection_string_extended_properties_have_csv_settings() 44 | { 45 | var people = from p in ExcelQueryFactory.Worksheet(null, _fileName, null, new LogManagerFactory()) 46 | select p; 47 | 48 | try { people.GetEnumerator(); } 49 | catch (DataException) { } 50 | 51 | var extendedProperties = GetExtendedProperties(); 52 | 53 | Assert.AreEqual("\"text;Excel 12.0;HDR=YES;IMEX=1\"", extendedProperties); 54 | 55 | } 56 | 57 | [Test] 58 | public void Table_name_is_csv_file_name() 59 | { 60 | var people = from p in ExcelQueryFactory.Worksheet(null, _fileName, null, new LogManagerFactory()) 61 | select p; 62 | 63 | try { people.GetEnumerator(); } 64 | catch (DataException) { } 65 | 66 | var tableName = GetTableName(GetSQLStatement()); 67 | Assert.AreEqual(Path.GetFileName(_fileName), tableName); 68 | } 69 | 70 | private string GetTableName(string sqlStatement) 71 | { 72 | var words = sqlStatement.Split(" ".ToCharArray()); 73 | for (var i = 0; i < words.Length; i++) 74 | { 75 | if (words[i] == "FROM") 76 | return words[i + 1] 77 | .Replace("[", "") 78 | .Replace("]", ""); 79 | } 80 | return ""; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/CellTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | namespace LinqToExcel.Tests 4 | { 5 | [Author("Paul Yoder", "paulyoder@gmail.com")] 6 | [Category("Unit")] 7 | [TestFixture] 8 | public class CellTest 9 | { 10 | [Test] 11 | public void Cell_implicitly_converts_to_string() 12 | { 13 | var newCell = new Cell("some value"); 14 | Assert.IsTrue("some value" == newCell); 15 | } 16 | 17 | [Test] 18 | public void Constructor_sets_cell_value() 19 | { 20 | var newCell = new Cell("hello"); 21 | Assert.AreEqual("hello", newCell.Value); 22 | } 23 | 24 | [Test] 25 | public void As_converts_cell_value_type_to_generic_argument_type() 26 | { 27 | var newCell = new Cell("2"); 28 | Assert.AreEqual(2, newCell.Cast()); 29 | Assert.AreEqual(typeof(int), newCell.Cast().GetType()); 30 | } 31 | 32 | [Test] 33 | public void As_returns_default_generic_value_when_value_is_null() 34 | { 35 | var newCell = new Cell(null); 36 | Assert.AreEqual(0, newCell.Cast()); 37 | } 38 | 39 | [Test] 40 | public void ValueAs_returns_default_generic_value_when_value_is_DBNull() 41 | { 42 | var newCell = new Cell(DBNull.Value); 43 | Assert.AreEqual(0, newCell.Cast()); 44 | } 45 | 46 | [Test] 47 | public void to_string_returns_value_as_string() 48 | { 49 | var newCell = new Cell("hello"); 50 | Assert.AreEqual("hello", newCell.ToString()); 51 | } 52 | 53 | [Test] 54 | public void As_throws_exception_when_try_to_convert_invalid_value() 55 | { 56 | var newCell = new Cell("not a number"); 57 | Assert.Throws(() => newCell.Cast()); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ColumnMappings_IntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using System.IO; 5 | using log4net.Core; 6 | 7 | namespace LinqToExcel.Tests 8 | { 9 | [Author("Paul Yoder", "paulyoder@gmail.com")] 10 | [Category("Integration")] 11 | [TestFixture] 12 | public class ColumnMappings_IntegrationTests : SQLLogStatements_Helper 13 | { 14 | ExcelQueryFactory _repo; 15 | string _excelFileName; 16 | string _worksheetName; 17 | 18 | [OneTimeSetUp] 19 | public void fs() 20 | { 21 | InstantiateLogger(); 22 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 23 | var excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 24 | _excelFileName = Path.Combine(excelFilesDirectory, "Companies.xls"); 25 | _worksheetName = "ColumnMappings"; 26 | } 27 | 28 | [SetUp] 29 | public void s() 30 | { 31 | _repo = new ExcelQueryFactory(new LogManagerFactory()); 32 | _repo.FileName = _excelFileName; 33 | } 34 | 35 | [Test] 36 | public void all_properties_have_column_mappings() 37 | { 38 | _repo.AddMapping(x => x.Name, "Company Title"); 39 | _repo.AddMapping(x => x.CEO, "Boss"); 40 | _repo.AddMapping(x => x.EmployeeCount, "Number of People"); 41 | _repo.AddMapping(x => x.StartDate, "Initiation Date"); 42 | 43 | var companies = from c in _repo.Worksheet(_worksheetName) 44 | where c.Name == "Taylor University" 45 | select c; 46 | 47 | var rival = companies.ToList().First(); 48 | Assert.AreEqual(1, companies.ToList().Count, "Result Count"); 49 | Assert.AreEqual("Taylor University", rival.Name, "Name"); 50 | Assert.AreEqual("Your Mom", rival.CEO, "CEO"); 51 | Assert.AreEqual(400, rival.EmployeeCount, "EmployeeCount"); 52 | Assert.AreEqual(new DateTime(1988, 7, 26), rival.StartDate, "StartDate"); 53 | } 54 | 55 | [Test] 56 | public void some_properties_have_column_mappings() 57 | { 58 | _repo.AddMapping(x => x.CEO, "Boss"); 59 | _repo.AddMapping(x => x.StartDate, "Initiation Date"); 60 | 61 | var companies = from c in _repo.Worksheet(_worksheetName) 62 | where c.Name == "Anderson University" 63 | select c; 64 | 65 | Company rival = companies.ToList()[0]; 66 | Assert.AreEqual(1, companies.ToList().Count, "Result Count"); 67 | Assert.AreEqual("Anderson University", rival.Name, "Name"); 68 | Assert.AreEqual("Your Mom", rival.CEO, "CEO"); 69 | Assert.AreEqual(300, rival.EmployeeCount, "EmployeeCount"); 70 | Assert.AreEqual(new DateTime(1988, 7, 26), rival.StartDate, "StartDate"); 71 | } 72 | 73 | [Test] 74 | public void log_warning_when_property_with_column_mapping_not_in_where_clause_when_mapped_column_doesnt_exist() 75 | { 76 | _loggedEvents.Clear(); 77 | _repo.AddMapping(x => x.CEO, "The Big Cheese"); 78 | 79 | var companies = from c in _repo.Worksheet(_worksheetName) 80 | select c; 81 | 82 | companies.GetEnumerator(); 83 | int warningsLogged = 0; 84 | foreach (LoggingEvent logEvent in _loggedEvents.GetEvents()) 85 | { 86 | if ((logEvent.Level == Level.Warn) && 87 | (logEvent.RenderedMessage == "'The Big Cheese' column that is mapped to the 'CEO' property does not exist in the 'ColumnMappings' worksheet")) 88 | warningsLogged++; 89 | } 90 | Assert.AreEqual(1, warningsLogged); 91 | } 92 | 93 | [Test] 94 | public void column_mappings_with_transformation() 95 | { 96 | _repo.AddMapping(x => x.IsActive, "Active", x => x == "Y"); 97 | var companies = from c in _repo.Worksheet(_worksheetName) 98 | select c; 99 | 100 | foreach (var company in companies) 101 | Assert.AreEqual(company.StartDate > new DateTime(1980, 1, 1), company.IsActive); 102 | } 103 | 104 | [Test] 105 | public void transformation() 106 | { 107 | //Add transformation to change the Name value to 'Looney Tunes' if it is originally 'ACME' 108 | _repo.AddTransformation(p => p.Name, value => (value == "ACME") ? "Looney Tunes" : value); 109 | var firstCompany = (from c in _repo.Worksheet(_worksheetName) 110 | select c).First(); 111 | 112 | Assert.AreEqual("Looney Tunes", firstCompany.Name); 113 | } 114 | 115 | [Test] 116 | public void transformation_that_returns_null() 117 | { 118 | //Add transformation to change the Name value to 'Looney Tunes' if it is originally 'ACME' 119 | _repo.AddTransformation(p => p.Name, value => null); 120 | var firstCompany = (from c in _repo.Worksheet(_worksheetName) 121 | select c).First(); 122 | 123 | Assert.AreEqual(null, firstCompany.Name); 124 | } 125 | 126 | [Test] 127 | public void annotated_properties_map_to_columns() 128 | { 129 | var companies = from c in _repo.Worksheet(_worksheetName) 130 | where c.Name == "Taylor University" 131 | select c; 132 | 133 | var rival = companies.ToList().First(); 134 | Assert.AreEqual(1, companies.ToList().Count, "Result Count"); 135 | Assert.AreEqual("Taylor University", rival.Name, "Name"); 136 | Assert.AreEqual("Your Mom", rival.CEO, "CEO"); 137 | Assert.AreEqual(400, rival.EmployeeCount, "EmployeeCount"); 138 | Assert.AreEqual(new DateTime(1988, 7, 26), rival.StartDate, "StartDate"); 139 | Assert.AreEqual("N", rival.IsActive, "IsActive"); 140 | } 141 | 142 | [Test] 143 | public void two_transformations_with_the_same_property_but_in_different_types() 144 | { 145 | _repo.AddTransformation(x => x.Value, x => x); 146 | _repo.AddTransformation(x => x.Value, x => x); 147 | 148 | var value1 = _repo.Worksheet("Transformation1").First().Value; 149 | var value2 = _repo.Worksheet("Transformation2").First().Value; 150 | 151 | Assert.AreEqual(1, value1); 152 | Assert.AreEqual("some different value", value2); 153 | } 154 | 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ColumnMappings_SQLStatements_UnitTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using System.Data.OleDb; 5 | 6 | namespace LinqToExcel.Tests 7 | { 8 | [Author("Paul Yoder", "paulyoder@gmail.com")] 9 | [Category("Unit")] 10 | [TestFixture] 11 | public class ColumnMappings_SQLStatements_UnitTests : SQLLogStatements_Helper 12 | { 13 | private ExcelQueryFactory _repo; 14 | 15 | [OneTimeSetUp] 16 | public void fs() 17 | { 18 | InstantiateLogger(); 19 | } 20 | 21 | [SetUp] 22 | public void Setup() 23 | { 24 | _repo = new ExcelQueryFactory(new LogManagerFactory()); 25 | _repo.FileName = ""; 26 | ClearLogEvents(); 27 | } 28 | 29 | [Test] 30 | public void where_clause_contains_property_with_column_mapping() 31 | { 32 | _repo.AddMapping(x => x.CEO, "Boss"); 33 | 34 | var companies = from c in _repo.Worksheet() 35 | where c.CEO == "Paul" 36 | select c; 37 | 38 | try { companies.GetEnumerator(); } 39 | catch (OleDbException) { } 40 | string expectedSql = string.Format("SELECT * FROM [Sheet1$] WHERE ({0} = ?)", GetSQLFieldName("Boss")); 41 | Assert.AreEqual(expectedSql, GetSQLStatement()); 42 | } 43 | 44 | [Test] 45 | public void where_clause_contains_property_without_column_mapping() 46 | { 47 | _repo.AddMapping(x => x.CEO, "Boss"); 48 | 49 | var companies = from c in _repo.Worksheet() 50 | where c.Name == "ACME" 51 | select c; 52 | 53 | try { companies.GetEnumerator(); } 54 | catch (OleDbException) { } 55 | string expectedSql = string.Format("SELECT * FROM [Sheet1$] WHERE ({0} = ?)", GetSQLFieldName("Name")); 56 | Assert.AreEqual(expectedSql, GetSQLStatement()); 57 | } 58 | 59 | [Test] 60 | public void where_is_null() 61 | { 62 | _repo.AddMapping(x => x.CEO, "Boss"); 63 | 64 | var companies = from c in _repo.Worksheet() 65 | where c.CEO == null 66 | select c; 67 | 68 | try { companies.GetEnumerator(); } 69 | catch (OleDbException) { } 70 | string expectedSql = string.Format("SELECT * FROM [Sheet1$] WHERE ({0} IS NULL)", GetSQLFieldName("Boss")); 71 | Assert.AreEqual(expectedSql, GetSQLStatement()); 72 | } 73 | 74 | /// 75 | /// Expression body is UnaryExpression for non native types 76 | /// 77 | [Test] 78 | public void mapped_property_is_not_native_type() 79 | { 80 | _repo.AddMapping(x => x.StartDate, "Hired Date"); 81 | 82 | var companies = from c in _repo.Worksheet() 83 | where c.StartDate == new DateTime(2008, 1, 1) 84 | select c; 85 | 86 | try { companies.GetEnumerator(); } 87 | catch (OleDbException) { } 88 | string expectedSql = string.Format("SELECT * FROM [Sheet1$] WHERE ({0} = ?)", GetSQLFieldName("Hired Date")); 89 | Assert.AreEqual(expectedSql, GetSQLStatement()); 90 | } 91 | 92 | /// 93 | /// Expression body is MemberExpression for native types 94 | /// 95 | [Test] 96 | public void mapped_property_is_native_type() 97 | { 98 | _repo.AddMapping(x => x.CEO, "Da big Cheese"); 99 | 100 | var companies = from c in _repo.Worksheet() 101 | where c.CEO == "Paul" 102 | select c; 103 | 104 | try { companies.GetEnumerator(); } 105 | catch (OleDbException) { } 106 | string expectedSql = string.Format("SELECT * FROM [Sheet1$] WHERE ({0} = ?)", GetSQLFieldName("Da big Cheese")); 107 | Assert.AreEqual(expectedSql, GetSQLStatement()); 108 | } 109 | 110 | [Test] 111 | public void multiple_mapped_properties() 112 | { 113 | _repo.AddMapping(x => x.CEO, "Da big Cheese"); 114 | _repo.AddMapping(x => x.Name, "Legal Name"); 115 | 116 | var companies = from c in _repo.Worksheet() 117 | where c.CEO == "Paul" && c.Name == "ACME" 118 | select c; 119 | 120 | try { companies.GetEnumerator(); } 121 | catch (OleDbException) { } 122 | string expectedSql = string.Format("SELECT * FROM [Sheet1$] WHERE (({0} = ?) AND ({1} = ?))", 123 | GetSQLFieldName("Da big Cheese"), 124 | GetSQLFieldName("Legal Name")); 125 | Assert.AreEqual(expectedSql, GetSQLStatement()); 126 | } 127 | 128 | [Test] 129 | public void mapped_property_is_passed_in_as_a_string() 130 | { 131 | _repo.AddMapping("CEO", "Da big Cheese"); 132 | _repo.AddMapping("Name", "Legal Name"); 133 | 134 | var companies = from c in _repo.Worksheet() 135 | where c.CEO == "Paul" && c.Name == "ACME" 136 | select c; 137 | 138 | try { companies.GetEnumerator(); } 139 | catch (OleDbException) { } 140 | string expectedSql = string.Format("SELECT * FROM [Sheet1$] WHERE (({0} = ?) AND ({1} = ?))", 141 | GetSQLFieldName("Da big Cheese"), 142 | GetSQLFieldName("Legal Name")); 143 | Assert.AreEqual(expectedSql, GetSQLStatement()); 144 | } 145 | 146 | [Test] 147 | public void distinct() 148 | { 149 | _repo.AddMapping("Name", "FullName"); 150 | var companies = (from c in _repo.Worksheet() 151 | select c.Name).Distinct(); 152 | 153 | try { companies.ToList(); } 154 | catch (OleDbException) { } 155 | var expectedSql = "SELECT DISTINCT(FullName) FROM [Sheet1$]"; 156 | Assert.AreEqual(expectedSql, GetSQLStatement()); 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/Company.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinqToExcel.Tests 4 | { 5 | public class Company 6 | { 7 | public string Name { get; set; } 8 | public string CEO { get; set; } 9 | public int? EmployeeCount { get; set; } 10 | public DateTime StartDate { get; set; } 11 | public bool IsActive { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/CompanyBadWithAllowFieldTypeConversionExceptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using LinqToExcel.Exceptions; 4 | 5 | namespace LinqToExcel.Tests 6 | { 7 | class CompanyBadWithAllowFieldTypeConversionExceptions : IAllowFieldTypeConversionExceptions 8 | { 9 | public CompanyBadWithAllowFieldTypeConversionExceptions() 10 | { 11 | FieldTypeConversionExceptions = new List(); 12 | } 13 | 14 | public string Name { get; set; } 15 | 16 | /// 17 | /// The CEO column is actually a string and should fail type conversion to int. 18 | /// 19 | public int CEO { get; set; } 20 | 21 | /// 22 | /// The EmployeeCount column is actually a string and should fail type conversion to DateTime. 23 | /// 24 | public DateTime EmployeeCount { get; set; } 25 | 26 | public IList FieldTypeConversionExceptions { get; private set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/CompanyGoodWithAllowFieldTypeConversionExceptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using LinqToExcel.Exceptions; 3 | 4 | namespace LinqToExcel.Tests 5 | { 6 | class CompanyGoodWithAllowFieldTypeConversionExceptions : IAllowFieldTypeConversionExceptions 7 | { 8 | public CompanyGoodWithAllowFieldTypeConversionExceptions() 9 | { 10 | FieldTypeConversionExceptions = new List(); 11 | } 12 | 13 | public string Name { get; set; } 14 | public string CEO { get; set; } 15 | public int EmployeeCount { get; set; } 16 | 17 | public IList FieldTypeConversionExceptions { get; private set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/CompanyNameWithUnmappedCells.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.Collections.Generic; 3 | 4 | namespace LinqToExcel.Tests 5 | { 6 | class CompanyNameWithUnmappedCells : IContainsUnmappedCells 7 | { 8 | public CompanyNameWithUnmappedCells() 9 | { 10 | UnmappedCells = new Dictionary(); 11 | } 12 | 13 | public string Name { get; set; } 14 | public IDictionary UnmappedCells { get; private set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/CompanyNullable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinqToExcel.Tests 4 | { 5 | public class CompanyNullable 6 | { 7 | public string Name { get; set; } 8 | public string CEO { get; set; } 9 | public int? EmployeeCount { get; set; } 10 | public DateTime? StartDate { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/CompanyWithCity.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace LinqToExcel.Tests 3 | { 4 | class CompanyWithCity : Company 5 | { 6 | public string City { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/CompanyWithColumnAnnotations.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LinqToExcel.Attributes; 3 | 4 | namespace LinqToExcel.Tests 5 | { 6 | public class CompanyWithColumnAnnotations 7 | { 8 | [ExcelColumn("Company Title")] 9 | public string Name { get; set; } 10 | 11 | [ExcelColumn("Boss")] 12 | public string CEO { get; set; } 13 | 14 | [ExcelColumn("Number of People")] 15 | public int EmployeeCount { get; set; } 16 | 17 | [ExcelColumn("Initiation Date")] 18 | public DateTime StartDate { get; set; } 19 | 20 | [ExcelColumn("Active")] 21 | public string IsActive { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ConfiguredWorksheetName_IntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using System.IO; 5 | using System.Data; 6 | 7 | namespace LinqToExcel.Tests 8 | { 9 | [Author("Paul Yoder", "paulyoder@gmail.com")] 10 | [Category("Integration")] 11 | [TestFixture] 12 | public class ConfiguredWorksheetName_IntegrationTests : SQLLogStatements_Helper 13 | { 14 | private string _excelFileName; 15 | 16 | [OneTimeSetUp] 17 | public void fs() 18 | { 19 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 20 | var excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 21 | _excelFileName = Path.Combine(excelFilesDirectory, "Companies.xls"); 22 | InstantiateLogger(); 23 | } 24 | 25 | [SetUp] 26 | public void s() 27 | { 28 | ClearLogEvents(); 29 | } 30 | 31 | [Test] 32 | public void data_is_read_from_correct_worksheet() 33 | { 34 | var companies = from c in ExcelQueryFactory.Worksheet("More Companies", _excelFileName, new LogManagerFactory()) 35 | select c; 36 | 37 | Assert.AreEqual(3, companies.ToList().Count); 38 | } 39 | 40 | [Test] 41 | public void worksheetIndex_of_2_uses_third_table_name_orderedby_name() 42 | { 43 | var companies = (from c in ExcelQueryFactory.Worksheet(3, _excelFileName, new LogManagerFactory()) 44 | select c).ToList(); 45 | 46 | var expectedSql = "SELECT * FROM [More Companies$]"; 47 | Assert.AreEqual(expectedSql, GetSQLStatement(), "SQL Statement"); 48 | } 49 | 50 | [Test] 51 | public void worksheetIndex_too_high_throws_exception() 52 | { 53 | Assert.That(() => from c in ExcelQueryFactory.Worksheet(100, _excelFileName, new LogManagerFactory()) 54 | select c, 55 | Throws.TypeOf()); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ConfiguredWorksheetName_SQLStatements_UnitTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using NUnit.Framework; 3 | using System.Data.OleDb; 4 | 5 | namespace LinqToExcel.Tests 6 | { 7 | [Author("Paul Yoder", "paulyoder@gmail.com")] 8 | [Category("Unit")] 9 | [TestFixture] 10 | public class ConfiguredWorksheetName_SQLStatements_UnitTests : SQLLogStatements_Helper 11 | { 12 | [OneTimeSetUp] 13 | public void fs() 14 | { 15 | InstantiateLogger(); 16 | } 17 | 18 | [SetUp] 19 | public void Setup() 20 | { 21 | ClearLogEvents(); 22 | } 23 | 24 | [Test] 25 | public void table_name_in_sql_statement_matches_configured_table_name() 26 | { 27 | var companies = from c in ExcelQueryFactory.Worksheet("Company Worksheet", "", new LogManagerFactory()) 28 | select c; 29 | 30 | try { companies.GetEnumerator(); } 31 | catch (OleDbException) { } 32 | string expectedSql = "SELECT * FROM [Company Worksheet$]"; 33 | Assert.AreEqual(expectedSql, GetSQLStatement()); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/Convention_IntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using System.IO; 5 | using System.Data.OleDb; 6 | 7 | namespace LinqToExcel.Tests 8 | { 9 | [Author("Paul Yoder", "paulyoder@gmail.com")] 10 | [Category("Integration")] 11 | [TestFixture] 12 | public class Convention_IntegrationTests 13 | { 14 | string _excelFileName; 15 | 16 | [OneTimeSetUp] 17 | public void fs() 18 | { 19 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 20 | var excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 21 | _excelFileName = Path.Combine(excelFilesDirectory, "Companies.xls"); 22 | } 23 | 24 | [Test] 25 | public void select_all() 26 | { 27 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 28 | select c; 29 | 30 | //Using ToList() because using Count() first would change the sql 31 | //string to "SELECT COUNT(*)" which we're not testing here 32 | Assert.AreEqual(7, companies.ToList().Count); 33 | } 34 | 35 | [Test] 36 | public void where_string_equals() 37 | { 38 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 39 | where c.CEO == "Paul Yoder" 40 | select c; 41 | 42 | Assert.AreEqual(1, companies.ToList().Count); 43 | } 44 | 45 | [Test] 46 | public void where_string_not_equal() 47 | { 48 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 49 | where c.CEO != "Bugs Bunny" 50 | select c; 51 | 52 | Assert.AreEqual(6, companies.ToList().Count); 53 | } 54 | 55 | [Test] 56 | public void where_int_equals() 57 | { 58 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 59 | where c.EmployeeCount == 25 60 | select c; 61 | 62 | Assert.AreEqual(1, companies.ToList().Count); 63 | } 64 | 65 | [Test] 66 | public void where_int_not_equal() 67 | { 68 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 69 | where c.EmployeeCount != 98 70 | select c; 71 | 72 | Assert.AreEqual(6, companies.ToList().Count); 73 | } 74 | 75 | [Test] 76 | public void where_int_greater_than() 77 | { 78 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 79 | where c.EmployeeCount > 98 80 | select c; 81 | 82 | Assert.AreEqual(3, companies.ToList().Count); 83 | } 84 | 85 | [Test] 86 | public void where_int_greater_than_or_equal() 87 | { 88 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 89 | where c.EmployeeCount >= 98 90 | select c; 91 | 92 | Assert.AreEqual(4, companies.ToList().Count); 93 | } 94 | 95 | [Test] 96 | public void where_int_less_than() 97 | { 98 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 99 | where c.EmployeeCount < 300 100 | select c; 101 | 102 | Assert.AreEqual(4, companies.ToList().Count); 103 | } 104 | 105 | [Test] 106 | public void where_int_less_than_or_equal() 107 | { 108 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 109 | where c.EmployeeCount <= 300 110 | select c; 111 | 112 | Assert.AreEqual(5, companies.ToList().Count); 113 | } 114 | 115 | [Test] 116 | public void where_datetime_equals() 117 | { 118 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 119 | where c.StartDate == new DateTime(2008, 10, 9) 120 | select c; 121 | 122 | Assert.AreEqual(1, companies.ToList().Count); 123 | } 124 | 125 | [Test] 126 | public void where_null() 127 | { 128 | var companies = from c in ExcelQueryFactory.Worksheet("NullCells", _excelFileName + "x", null, new LogManagerFactory()) 129 | where c.EmployeeCount == null 130 | select c; 131 | 132 | Assert.AreEqual(2, companies.ToList().Count); 133 | } 134 | 135 | [Test] 136 | public void where_not_null() 137 | { 138 | var companies = from c in ExcelQueryFactory.Worksheet("NullCells", _excelFileName + "x", null, new LogManagerFactory()) 139 | where c.EmployeeCount != null 140 | select c; 141 | 142 | Assert.AreEqual(1, companies.ToList().Count); 143 | } 144 | 145 | [Test] 146 | public void no_exception_on_property_not_used_in_where_clause_when_column_doesnt_exist() 147 | { 148 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 149 | select c; 150 | 151 | foreach (var company in companies) 152 | Assert.IsTrue(String.IsNullOrEmpty(company.City)); 153 | } 154 | 155 | [Test] 156 | public void where_contains() 157 | { 158 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 159 | where c.CEO.Contains("Paul") 160 | select c; 161 | 162 | Assert.AreEqual(1, companies.ToList().Count); 163 | } 164 | 165 | [Test] 166 | public void where_string_IsNullOrEmpty() 167 | { 168 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 169 | where String.IsNullOrEmpty(c.CEO) 170 | select c; 171 | 172 | Assert.AreEqual(0, companies.ToList().Count); 173 | } 174 | 175 | [Test] 176 | public void where_not_string_IsNullOrEmpty() 177 | { 178 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 179 | where !String.IsNullOrEmpty(c.CEO) 180 | select c; 181 | 182 | Assert.AreEqual(7, companies.ToList().Count); 183 | } 184 | 185 | [Test] 186 | public void selection_projection() 187 | { 188 | var companyCities = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 189 | select new CompanyWithCity 190 | { 191 | CEO = c.CEO, 192 | City = "Omaha", 193 | }; 194 | foreach (var company in companyCities) 195 | { 196 | Assert.AreEqual("Omaha", company.City); 197 | Assert.AreEqual("Bugs Bunny", company.CEO); 198 | break; 199 | } 200 | } 201 | 202 | [Test] 203 | public void selection_row_projection() 204 | { 205 | var companyCities = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 206 | select new Company 207 | { 208 | CEO = c["CEO"], 209 | Name = c["Name"] 210 | }; 211 | 212 | foreach (var company in companyCities) 213 | { 214 | Assert.AreEqual("ACME", company.Name); 215 | Assert.AreEqual("Bugs Bunny", company.CEO); 216 | break; 217 | } 218 | } 219 | 220 | [Test] 221 | public void selection_row_to_anonymous_projection() 222 | { 223 | var companyCities = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 224 | select new 225 | { 226 | Employees = c["EmployeeCount"].Cast(), 227 | Name = c["Name"].ToString() 228 | }; 229 | 230 | foreach (var company in companyCities) 231 | { 232 | Assert.AreEqual("ACME", company.Name); 233 | Assert.AreEqual(25, company.Employees); 234 | break; 235 | } 236 | } 237 | 238 | [Test] 239 | public void first() 240 | { 241 | var firstCompany = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 242 | select c).First(); 243 | 244 | Assert.AreEqual("ACME", firstCompany.Name); 245 | } 246 | 247 | [Test] 248 | public void FirstOrDefault_returns_null_when_no_rows_returned() 249 | { 250 | var noCompany = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 251 | where c.CEO == "Nobody" 252 | select c).FirstOrDefault(); 253 | 254 | Assert.IsNull(noCompany); 255 | } 256 | 257 | [Test] 258 | public void count() 259 | { 260 | var companyCount = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 261 | select c).Count(); 262 | 263 | Assert.AreEqual(7, companyCount); 264 | } 265 | 266 | [Test] 267 | public void long_count() 268 | { 269 | var companyCount = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 270 | select c).LongCount(); 271 | 272 | Assert.AreEqual(7, companyCount); 273 | } 274 | 275 | [Test] 276 | public void sum() 277 | { 278 | var companySum = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 279 | select c).Sum(x => x.EmployeeCount); 280 | 281 | Assert.AreEqual(30723, companySum); 282 | } 283 | 284 | [Test] 285 | public void average() 286 | { 287 | var averageEmployees = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 288 | select c).Average(x => x.EmployeeCount); 289 | 290 | Assert.AreEqual(4389, averageEmployees); 291 | } 292 | 293 | [Test] 294 | public void max() 295 | { 296 | var maxEmployees = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 297 | select c).Max(x => x.EmployeeCount); 298 | 299 | Assert.AreEqual(29839, maxEmployees); 300 | } 301 | 302 | [Test] 303 | public void min() 304 | { 305 | var minEmployees = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 306 | select c).Min(x => x.EmployeeCount); 307 | 308 | Assert.AreEqual(1, minEmployees); 309 | } 310 | 311 | [Test] 312 | public void distinct() 313 | { 314 | var distinctCompanies = (from c in ExcelQueryFactory.Worksheet("Null Dates", _excelFileName, null, new LogManagerFactory()) 315 | select c.IsActive).Distinct(); 316 | 317 | Assert.AreEqual(2, distinctCompanies.ToList().Count); 318 | } 319 | 320 | [Test] 321 | public void oderby() 322 | { 323 | var minEmployees = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 324 | orderby c.EmployeeCount ascending 325 | select c; 326 | 327 | Assert.AreEqual(1, minEmployees.First().EmployeeCount); 328 | } 329 | 330 | [Test] 331 | public void oderby_desc() 332 | { 333 | var minEmployees = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 334 | orderby c.EmployeeCount descending 335 | select c; 336 | 337 | Assert.AreEqual(29839, minEmployees.First().EmployeeCount); 338 | } 339 | 340 | [Test] 341 | public void last() 342 | { 343 | var minEmployees = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 344 | select c; 345 | 346 | Assert.AreEqual(455, minEmployees.Last().EmployeeCount); 347 | } 348 | 349 | [Test] 350 | public void LastOrDefault_returns_null_when_no_rows_returned() 351 | { 352 | var noCompany = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 353 | where c.CEO == "Nobody" 354 | select c).LastOrDefault(); 355 | 356 | Assert.IsNull(noCompany); 357 | } 358 | 359 | [Test] 360 | public void take() 361 | { 362 | var threeEmployees = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 363 | select c).Take(3); 364 | 365 | Assert.AreEqual(3, threeEmployees.ToList().Count); 366 | } 367 | 368 | [Test] 369 | public void skip() 370 | { 371 | var threeEmployees = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 372 | select c).Skip(3); 373 | 374 | Assert.AreEqual(4, threeEmployees.ToList().Count); 375 | } 376 | 377 | [Test] 378 | public void reverse() 379 | { 380 | var reverse = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 381 | select c).Reverse().ToList(); 382 | 383 | Assert.AreEqual("Ontario Systems", reverse.First().Name); 384 | } 385 | 386 | 387 | [Test] 388 | public void convert_nullable_properties() 389 | { 390 | var companies = from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 391 | select c; 392 | 393 | //Using ToList() because using Count() first would change the sql 394 | //string to "SELECT COUNT(*)" which we're not testing here 395 | Assert.AreEqual(7, companies.ToList().Count); 396 | } 397 | 398 | [Test] 399 | public void dbnull_fields_return_null_and_dont_throw_exception() 400 | { 401 | var companies = from c in ExcelQueryFactory.Worksheet("Null Dates", _excelFileName, null, new LogManagerFactory()) 402 | select c; 403 | 404 | //Using ToList() because using Count() first would change the sql 405 | //string to "SELECT COUNT(*)" which we're not testing here 406 | Assert.IsNull(companies.ToList()[3].StartDate); 407 | } 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/Excel2007_IntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using LinqToExcel.Domain; 4 | using NUnit.Framework; 5 | using System.IO; 6 | 7 | namespace LinqToExcel.Tests 8 | { 9 | [Author("Paul Yoder", "paulyoder@gmail.com")] 10 | [Category("Integration")] 11 | [TestFixture] 12 | public class Excel2007_IntegrationTests 13 | { 14 | string _filesDirectory; 15 | 16 | [OneTimeSetUp] 17 | public void fs() 18 | { 19 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 20 | _filesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 21 | } 22 | 23 | [Test] 24 | public void xlsx() 25 | { 26 | var fileName = Path.Combine(_filesDirectory, "Companies.xlsx"); 27 | var companies = from c in ExcelQueryFactory.Worksheet("MoreCompanies", fileName, new LogManagerFactory()) 28 | select c; 29 | 30 | //Using ToList() because using Count() first would change the sql 31 | //string to "SELECT COUNT(*)" which we're not testing here 32 | Assert.AreEqual(3, companies.ToList().Count); 33 | } 34 | 35 | [Test] 36 | public void xlsm() 37 | { 38 | var fileName = Path.Combine(_filesDirectory, "Companies.xlsm"); 39 | var companies = from c in ExcelQueryFactory.Worksheet("MoreCompanies", fileName, null, new LogManagerFactory()) 40 | select c; 41 | 42 | //Using ToList() because using Count() first would change the sql 43 | //string to "SELECT COUNT(*)" which we're not testing here 44 | Assert.AreEqual(3, companies.ToList().Count); 45 | } 46 | 47 | [Test] 48 | public void xlsb() 49 | { 50 | var fileName = Path.Combine(_filesDirectory, "Companies.xlsb"); 51 | var companies = from c in ExcelQueryFactory.Worksheet(null, fileName, null, new LogManagerFactory()) 52 | select c; 53 | 54 | //Using ToList() because using Count() first would change the sql 55 | //string to "SELECT COUNT(*)" which we're not testing here 56 | Assert.AreEqual(7, companies.ToList().Count); 57 | } 58 | 59 | [Test] 60 | public void xls_with_Ace_DatabaseEngine() 61 | { 62 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 63 | var excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 64 | var excelFileName = Path.Combine(excelFilesDirectory, "Companies.xls"); 65 | 66 | var excel = new ExcelQueryFactory(excelFileName, new LogManagerFactory()); 67 | var companies = from c in excel.Worksheet() 68 | select c; 69 | 70 | Assert.AreEqual(7, companies.ToList().Count); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ExcelFiles/Companies.csv: -------------------------------------------------------------------------------- 1 | Name,CEO,EmployeeCount,StartDate 2 | ACME,Bugs Bunny,25,11/11/1918 3 | Word Made Flesh,Chris Heuertz,98,8/8/1994 4 | Anderson University,James Edwards,300,9/1/1917 5 | McDonalds,Ronald McDonald,29839,6/17/1952 6 | The Lemon Drop,George Smorge,5,9/23/1960 7 | Yoder Solutions,Paul Yoder,1,10/9/2008 8 | Ontario Systems,Tony Reisz,433,8/23/1980 9 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ExcelFiles/Companies.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulyoder/LinqToExcel/8759172638ce31c6a98eaf516427069379683947/src/LinqToExcel.Tests/ExcelFiles/Companies.xls -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ExcelFiles/Companies.xlsb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulyoder/LinqToExcel/8759172638ce31c6a98eaf516427069379683947/src/LinqToExcel.Tests/ExcelFiles/Companies.xlsb -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ExcelFiles/Companies.xlsm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulyoder/LinqToExcel/8759172638ce31c6a98eaf516427069379683947/src/LinqToExcel.Tests/ExcelFiles/Companies.xlsm -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ExcelFiles/Companies.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulyoder/LinqToExcel/8759172638ce31c6a98eaf516427069379683947/src/LinqToExcel.Tests/ExcelFiles/Companies.xlsx -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ExcelFiles/EmptyRows.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulyoder/LinqToExcel/8759172638ce31c6a98eaf516427069379683947/src/LinqToExcel.Tests/ExcelFiles/EmptyRows.xls -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ExcelFiles/NamedRanges.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulyoder/LinqToExcel/8759172638ce31c6a98eaf516427069379683947/src/LinqToExcel.Tests/ExcelFiles/NamedRanges.xlsx -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ExcelFiles/NoHeader.csv: -------------------------------------------------------------------------------- 1 | ACME2,Bugs Bunny,25,11/11/1918 2 | Word Made Flesh,Chris Heuertz,98,08/08/1994 3 | Anderson University,James Edwards,300,09/01/1917 4 | McDonalds,Ronald McDonald,29839,06/17/1952 5 | The Lemon Drop,George Smorge,5,09/23/1960 6 | Yoder Solutions,Paul Yoder,1,10/09/2008 7 | Ontario Systems,Tony Reisz,4554,08/23/1980 8 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ExcelFiles/NoHeader.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulyoder/LinqToExcel/8759172638ce31c6a98eaf516427069379683947/src/LinqToExcel.Tests/ExcelFiles/NoHeader.xls -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/ExcelFiles/WorksheetNames.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulyoder/LinqToExcel/8759172638ce31c6a98eaf516427069379683947/src/LinqToExcel.Tests/ExcelFiles/WorksheetNames.xlsx -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/IMEX_Tests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using System.IO; 5 | 6 | namespace LinqToExcel.Tests 7 | { 8 | [Author("Paul Yoder", "paulyoder@gmail.com")] 9 | [Category("Integration")] 10 | [TestFixture] 11 | public class IMEX_Tests 12 | { 13 | string _excelFileName; 14 | 15 | [OneTimeSetUp] 16 | public void fs() 17 | { 18 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 19 | var excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 20 | _excelFileName = Path.Combine(excelFilesDirectory, "Companies.xls"); 21 | } 22 | 23 | [Test] 24 | public void date_and_text_column_values_are_not_null() 25 | { 26 | var sheet = new ExcelQueryFactory(new LogManagerFactory()); 27 | sheet.FileName = _excelFileName; 28 | 29 | var names = (from x in sheet.Worksheet("IMEX Table") 30 | select x).ToList(); 31 | 32 | Assert.AreEqual("Bye", names.Last()["Date"].ToString()); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/IndexToColumnNamesTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace LinqToExcel.Tests 8 | { 9 | [TestFixture] 10 | [Category("Unit")] 11 | [Author("Alberto Chvaicer")] 12 | public class IndexToColumnNamesTests 13 | { 14 | [Test] 15 | public void valid_excel_column_indexes() 16 | { 17 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(1), "A"); 18 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(2), "B"); 19 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(3), "C"); 20 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(25), "Y"); 21 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(26), "Z"); 22 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(27), "AA"); 23 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(28), "AB"); 24 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(51), "AY"); 25 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(52), "AZ"); 26 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(53), "BA"); 27 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(54), "BB"); 28 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(701), "ZY"); 29 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(702), "ZZ"); 30 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(703), "AAA"); 31 | Assert.AreEqual(LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(704), "AAB"); 32 | } 33 | 34 | [Test] 35 | public void negative_integer_should_throw_exception() 36 | { 37 | Assert.That(() => LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(-1), Throws.ArgumentException, "Index should be a positive integer"); 38 | } 39 | 40 | [Test] 41 | public void zero_should_throw_exception() 42 | { 43 | Assert.That(() => LinqToExcel.Query.ExcelUtilities.ColumnIndexToExcelColumnName(-1), Throws.ArgumentException, "Index should be a positive integer"); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/InvalidCastTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace LinqToExcel.Tests 9 | { 10 | [Author("Alberto Chvaicer", "achvaicer@gmail.com")] 11 | [Category("Integration")] 12 | [TestFixture] 13 | public class InvalidCastTests 14 | { 15 | private IExcelQueryFactory _factory; 16 | private string _excelFileName; 17 | 18 | [OneTimeSetUp] 19 | public void fs() 20 | { 21 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 22 | var excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 23 | _excelFileName = Path.Combine(excelFilesDirectory, "Companies.xls"); 24 | 25 | } 26 | 27 | [SetUp] 28 | public void s() 29 | { 30 | _factory = new ExcelQueryFactory(_excelFileName, new LogManagerFactory()); 31 | } 32 | 33 | [Test] 34 | public void invalid_number_cast_with_header() 35 | { 36 | Assert.That(() => (from x in ExcelQueryFactory.Worksheet("Invalid Cast", _excelFileName, new LogManagerFactory()) 37 | select x).ToList(), Throws.TypeOf(), "Error on row 8 and column name 'EmployeeCount'."); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/InvalidColumnNamesUsed.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using System.IO; 5 | using System.Data; 6 | 7 | namespace LinqToExcel.Tests 8 | { 9 | [Author("Paul Yoder", "paulyoder@gmail.com")] 10 | [Category("Integration")] 11 | [TestFixture] 12 | public class InvalidColumnNamesUsed 13 | { 14 | private string _excelFileName; 15 | 16 | [SetUp] 17 | public void fs() 18 | { 19 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 20 | var excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 21 | _excelFileName = Path.Combine(excelFilesDirectory, "Companies.xls"); 22 | } 23 | 24 | [Test] 25 | public void row_column_in_where_clause() 26 | { 27 | Assert.That(() => (from x in ExcelQueryFactory.Worksheet("Sheet1", _excelFileName, new LogManagerFactory()) 28 | where x["Bad Column"].ToString() == "nothing" 29 | select x).ToList(), 30 | Throws.TypeOf(), "'Bad Column' is not a valid column name. " + 31 | "Valid column names are: 'Name', 'CEO', 'EmployeeCount', 'StartDate'"); 32 | } 33 | 34 | [Test] 35 | public void row_column_in_orderby_clause() 36 | { 37 | Assert.That(() => (from x in ExcelQueryFactory.Worksheet("Sheet1", _excelFileName, new LogManagerFactory()) 38 | select x) 39 | .OrderBy(x => x["Bad Column"]) 40 | .ToList(), 41 | Throws.TypeOf(), "'Bad Column' is not a valid column name. " + 42 | "Valid column names are: 'Name', 'CEO', 'EmployeeCount', 'StartDate'"); 43 | } 44 | 45 | [Test] 46 | public void bad_column_in_where_clause() 47 | { 48 | Assert.That(() => (from x in ExcelQueryFactory.Worksheet("Sheet1", _excelFileName, new LogManagerFactory()) 49 | where x.City == "Omaha" 50 | select x).ToList(), 51 | Throws.TypeOf(), "'City' is not a valid column name. " + 52 | "Valid column names are: 'Name', 'CEO', 'EmployeeCount', 'StartDate'"); 53 | } 54 | 55 | [Test] 56 | public void bad_column_mapping_in_where_clause() 57 | { 58 | var excel = new ExcelQueryFactory(_excelFileName, new LogManagerFactory()); 59 | excel.AddMapping(x => x.City, "Town"); 60 | Assert.That(() => (from x in excel.Worksheet("Sheet1") 61 | where x.City == "Omaha" 62 | select x).ToList(), 63 | Throws.TypeOf(), "'Town' is not a valid column name. " + 64 | "Valid column names are: 'Name', 'CEO', 'EmployeeCount', 'StartDate'"); 65 | } 66 | 67 | [Test] 68 | public void bad_column_in_orderby_clause() 69 | { 70 | var list = (from x in ExcelQueryFactory.Worksheet("Sheet1", _excelFileName, new LogManagerFactory()) 71 | select x) 72 | .OrderBy(x => x.City); 73 | Assert.That(() => list.ToList(), 74 | Throws.TypeOf(), "'City' is not a valid column name. " + 75 | "Valid column names are: 'Name', 'CEO', 'EmployeeCount', 'StartDate'"); 76 | } 77 | 78 | [Test] 79 | public void bad_column_mapping_in_orderby_clause() 80 | { 81 | var excel = new ExcelQueryFactory(_excelFileName, new LogManagerFactory()); 82 | excel.AddMapping(x => x.City, "Town"); 83 | Assert.That(() => (from x in excel.Worksheet("Sheet1") 84 | select x) 85 | .OrderBy(x => x.City) 86 | .ToList(), 87 | Throws.TypeOf(), "'Town' is not a valid column name. " + 88 | "Valid column names are: 'Name', 'CEO', 'EmployeeCount', 'StartDate'"); 89 | } 90 | 91 | [Test] 92 | public void bad_column_in_average_aggregate() 93 | { 94 | var excel = new ExcelQueryFactory(_excelFileName, new LogManagerFactory()); 95 | excel.AddMapping(x => x.EmployeeCount, "Employees"); 96 | Assert.That(() => (from x in excel.Worksheet("Sheet1") 97 | select x) 98 | .Average(x => x.EmployeeCount), 99 | Throws.TypeOf(), "'Employees' is not a valid column name. " + 100 | "Valid column names are: 'Name', 'CEO', 'EmployeeCount', 'StartDate'"); 101 | } 102 | 103 | [Test] 104 | public void bad_column_in_max_aggregate() 105 | { 106 | var excel = new ExcelQueryFactory(_excelFileName, new LogManagerFactory()); 107 | excel.AddMapping(x => x.EmployeeCount, "Employees"); 108 | Assert.That(() => (from x in excel.Worksheet("Sheet1") 109 | select x) 110 | .Max(x => x.EmployeeCount), 111 | Throws.TypeOf(), "'Employees' is not a valid column name. " + 112 | "Valid column names are: 'Name', 'CEO', 'EmployeeCount', 'StartDate'"); 113 | } 114 | 115 | [Test] 116 | public void bad_column_in_min_aggregate() 117 | { 118 | var excel = new ExcelQueryFactory(_excelFileName, new LogManagerFactory()); 119 | excel.AddMapping(x => x.EmployeeCount, "Employees"); 120 | Assert.That(() => (from x in excel.Worksheet("Sheet1") 121 | select x) 122 | .Min(x => x.EmployeeCount), 123 | Throws.TypeOf(), "'Employees' is not a valid column name. " + 124 | "Valid column names are: 'Name', 'CEO', 'EmployeeCount', 'StartDate'"); 125 | } 126 | 127 | [Test] 128 | public void bad_column_in_sum_aggregate() 129 | { 130 | var excel = new ExcelQueryFactory(_excelFileName, new LogManagerFactory()); 131 | excel.AddMapping(x => x.EmployeeCount, "Employees"); 132 | 133 | Assert.That(() => (from x in excel.Worksheet("Sheet1") 134 | select x) 135 | .Sum(x => x.EmployeeCount), 136 | Throws.TypeOf(), "'Employees' is not a valid column name. " + 137 | "Valid column names are: 'Name', 'CEO', 'EmployeeCount', 'StartDate'"); 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/LinqToExcel.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net35;net451;net46 5 | Full 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | x64 20 | false 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | Always 30 | 31 | 32 | Always 33 | 34 | 35 | Always 36 | 37 | 38 | Always 39 | 40 | 41 | Always 42 | 43 | 44 | Always 45 | 46 | 47 | Always 48 | 49 | 50 | Always 51 | 52 | 53 | Always 54 | 55 | 56 | 57 | Always 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/LogManagerFactory.cs: -------------------------------------------------------------------------------- 1 | // copyright(c) 2016 Stephen Workman (workman.stephen@gmail.com) 2 | 3 | using System; 4 | 5 | using log4net; 6 | using LinqToExcel.Logging; 7 | 8 | namespace LinqToExcel.Tests { 9 | public class LogManagerFactory : ILogManagerFactory { 10 | public ILogProvider GetLogger(String name) { 11 | return new LogProvider(LogManager.GetLogger(name)); 12 | } 13 | 14 | public ILogProvider GetLogger(Type type) { 15 | return new LogProvider(LogManager.GetLogger(type)); 16 | } 17 | } 18 | 19 | public class LogProvider : ILogProvider { 20 | private ILog _iLog; 21 | 22 | public LogProvider(ILog iLog) { 23 | _iLog = iLog; 24 | } 25 | 26 | public Boolean IsDebugEnabled { 27 | get { 28 | if (_iLog != null) 29 | return _iLog.IsDebugEnabled; 30 | return false; 31 | } 32 | } 33 | 34 | public void Debug(Object message) { 35 | if (_iLog != null) 36 | _iLog.Debug(message); 37 | } 38 | 39 | public void DebugFormat(String format, Object arg) { 40 | if (_iLog != null) 41 | _iLog.DebugFormat(format, arg); 42 | } 43 | 44 | public void Error(Object message, Exception exception) { 45 | if (_iLog != null) 46 | _iLog.Error(message, exception); 47 | } 48 | 49 | public void WarnFormat(String format, Object arg0, Object arg1, Object arg2) { 50 | if (_iLog != null) 51 | _iLog.WarnFormat(format, arg0, arg1, arg2); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/NamedRange_IntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.IO; 7 | 8 | namespace LinqToExcel.Tests 9 | { 10 | [Author("Paul Yoder", "paulyoder@gmail.com")] 11 | [Category("Integration")] 12 | [TestFixture] 13 | public class NamedRange_IntegrationTests 14 | { 15 | ExcelQueryFactory _factory; 16 | string _excelFileName; 17 | 18 | [OneTimeSetUp] 19 | public void fs() 20 | { 21 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 22 | var excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 23 | _excelFileName = Path.Combine(excelFilesDirectory, "Companies.xls"); 24 | } 25 | 26 | [SetUp] 27 | public void s() 28 | { 29 | _factory = new ExcelQueryFactory(_excelFileName, new LogManagerFactory()); 30 | } 31 | 32 | [Test] 33 | public void GetNamedRanges() 34 | { 35 | var namedRanges = from c in _factory.GetNamedRanges() 36 | select c; 37 | 38 | Assert.AreEqual("Companies, CompaniesRange, MoreCompanies", string.Join(", ", namedRanges.ToArray()), "Workbook-scope"); 39 | } 40 | 41 | [Test] 42 | public void GetCompaniesRangeNamedRanges() 43 | { 44 | var namedRanges = from c in _factory.GetNamedRanges("Range1") 45 | select c; 46 | 47 | Assert.AreEqual("CompaniesRange", string.Join(", ", namedRanges.ToArray()), "Worksheet-scope"); 48 | } 49 | 50 | [Test] 51 | public void use_sheetData_and_worksheetIndex() 52 | { 53 | var companies = from c in _factory.NamedRange(5, "CompaniesRange") 54 | select c; 55 | 56 | Assert.AreEqual(7, companies.Count(), "Count"); 57 | Assert.AreEqual("ACME", companies.First().Name, "First Company Name"); 58 | } 59 | 60 | [Test] 61 | public void use_row_and_worksheetIndex() 62 | { 63 | var companies = from c in _factory.NamedRange(5, "CompaniesRange") 64 | select c; 65 | 66 | Assert.AreEqual(7, companies.Count(), "Count"); 67 | Assert.AreEqual("Ontario Systems", companies.Last()["Name"].ToString(), "Last Company Name"); 68 | } 69 | 70 | 71 | [Test] 72 | public void use_sheetData_where_null() 73 | { 74 | var factory = new ExcelQueryFactory(_excelFileName + "x", new LogManagerFactory()); 75 | var companies = from c in factory.NamedRange("NullCellCompanies") 76 | where c.EmployeeCount == null 77 | select c; 78 | 79 | Assert.AreEqual(2, companies.Count(), "Count"); 80 | } 81 | 82 | [Test] 83 | public void use_row_where_null() 84 | { 85 | var factory = new ExcelQueryFactory(_excelFileName + "x", new LogManagerFactory()); 86 | var companies = from c in factory.NamedRange("NullCellCompanies") 87 | where c["EmployeeCount"] == null 88 | select c; 89 | 90 | Assert.AreEqual(2, companies.Count(), "Count"); 91 | } 92 | 93 | [Test] 94 | public void use_row_no_header_where_null() 95 | { 96 | var factory = new ExcelQueryFactory(_excelFileName + "x", new LogManagerFactory()); 97 | var companies = from c in factory.NamedRangeNoHeader("NullCellCompanies") 98 | where c[2] == null 99 | select c; 100 | 101 | Assert.AreEqual(2, companies.Count(), "Count"); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/NamedRange_SQLStatements_UnitTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Data.OleDb; 7 | 8 | namespace LinqToExcel.Tests 9 | { 10 | [Author("Paul Yoder", "paulyoder@gmail.com")] 11 | [Category("Unit")] 12 | [TestFixture] 13 | public class NamedRange_SQLStatements_UnitTests : SQLLogStatements_Helper 14 | { 15 | private IExcelQueryFactory _factory; 16 | 17 | [OneTimeSetUp] 18 | public void fs() 19 | { 20 | InstantiateLogger(); 21 | } 22 | 23 | [SetUp] 24 | public void s() 25 | { 26 | ClearLogEvents(); 27 | _factory = new ExcelQueryFactory("", new LogManagerFactory()); 28 | } 29 | 30 | [Test] 31 | public void Appends_named_range_info_to_table_name() 32 | { 33 | var companies = from c in _factory.NamedRange("Sheet1", "NamedRange") 34 | select c; 35 | 36 | try { companies.GetEnumerator(); } 37 | catch (OleDbException) { } 38 | Assert.AreEqual("SELECT * FROM [Sheet1$NamedRange]", GetSQLStatement()); 39 | } 40 | 41 | [Test] 42 | public void use_sheetData_method() 43 | { 44 | var companies = from c in _factory.NamedRange("Sheet1", "NamedRange") 45 | select c; 46 | 47 | try { companies.GetEnumerator(); } 48 | catch (OleDbException) { } 49 | Assert.AreEqual("SELECT * FROM [Sheet1$NamedRange]", GetSQLStatement()); 50 | } 51 | 52 | [Test] 53 | public void use_row_where_is_null() 54 | { 55 | var companies = from c in _factory.NamedRange("Sheet1", "NamedRange") 56 | where c["City"] == null 57 | select c; 58 | //System.Diagnostics.Debugger.Launch(); 59 | try { companies.GetEnumerator(); } 60 | catch (OleDbException) { } 61 | var expectedSql = string.Format("SELECT * FROM [Sheet1$NamedRange] WHERE ({0} IS NULL)", GetSQLFieldName("City")); 62 | Assert.AreEqual(expectedSql, GetSQLStatement()); 63 | } 64 | 65 | [Test] 66 | public void use_sheetData_where_is_null() 67 | { 68 | var companies = from c in _factory.NamedRange("worksheetName", "NamedRange") 69 | where c.Name == null 70 | select c; 71 | 72 | try { companies.GetEnumerator(); } 73 | catch (OleDbException) { } 74 | var expectedSql = string.Format("SELECT * FROM [worksheetName$NamedRange] WHERE ({0} IS NULL)", GetSQLFieldName("Name")); 75 | Assert.AreEqual(expectedSql, GetSQLStatement()); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/NoHeader_IntregrationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using NUnit.Framework; 7 | 8 | namespace LinqToExcel.Tests 9 | { 10 | [Author("Paul Yoder", "paulyoder@gmail.com")] 11 | [Category("Integration")] 12 | [TestFixture] 13 | public class NoHeader_IntregrationTests 14 | { 15 | private IExcelQueryFactory _factory; 16 | private string _excelFileName; 17 | 18 | [OneTimeSetUp] 19 | public void ts() 20 | { 21 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 22 | var excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 23 | _excelFileName = Path.Combine(excelFilesDirectory, "NoHeader.xls"); 24 | } 25 | 26 | [SetUp] 27 | public void s() 28 | { 29 | _factory = new ExcelQueryFactory(_excelFileName, new LogManagerFactory()); 30 | } 31 | 32 | [Test] 33 | public void NoHeader_no_args() 34 | { 35 | var companies = from c in _factory.WorksheetNoHeader() 36 | select c; 37 | 38 | Assert.AreEqual(7, companies.Count(), "Company Count"); 39 | Assert.AreEqual("ACME", companies.First()[0].ToString(), "First Company Name"); 40 | Assert.AreEqual(455, companies.Last()[2].Cast(), "Last Company Employee Count"); 41 | } 42 | 43 | [Test] 44 | public void csv_file() 45 | { 46 | var csvFile = Path.Combine( 47 | Path.GetDirectoryName(_excelFileName), 48 | "NoHeader.csv"); 49 | 50 | _factory = new ExcelQueryFactory(csvFile, new LogManagerFactory()); 51 | var companies = from c in _factory.WorksheetNoHeader() 52 | select c; 53 | 54 | Assert.AreEqual(7, companies.Count(), "Company Count"); 55 | Assert.AreEqual("ACME2", companies.First()[0].ToString(), "First Company Name"); 56 | Assert.AreEqual(4554, companies.Last()[2].Cast(), "Last Company Employee Count"); 57 | } 58 | 59 | [Test] 60 | public void where_clause() 61 | { 62 | var oldCompanies = from c in _factory.WorksheetNoHeader() 63 | where c[3].Cast() < new DateTime(1955, 1, 1) 64 | select c; 65 | 66 | Assert.AreEqual(3, oldCompanies.Count(), "Company Count"); 67 | Assert.AreEqual("McDonalds", oldCompanies.Last()[0].ToString(), "Last OldCompany Name"); 68 | } 69 | 70 | [Test] 71 | public void where_is_null() 72 | { 73 | var factory = new ExcelQueryFactory(_excelFileName.Replace("NoHeader.xls", "Companies.xlsx"), new LogManagerFactory()); 74 | var oldCompanies = from c in factory.WorksheetNoHeader("NullCells") 75 | where c[2] == null 76 | select c; 77 | 78 | Assert.AreEqual(2, oldCompanies.Count(), "Company Count"); 79 | } 80 | 81 | [Test] 82 | public void no_header_range_where_clause() 83 | { 84 | var ACompanies = from c in _factory.WorksheetRangeNoHeader("C5", "F11", "Range") 85 | where c[0].ToString().StartsWith("A") 86 | select c; 87 | 88 | Assert.AreEqual(2, ACompanies.Count(), "Company Count"); 89 | Assert.AreEqual(new DateTime(1917, 9, 1).ToShortDateString(), 90 | ACompanies.Last()[3].Cast().ToShortDateString(), 91 | "Last ACompany Date"); 92 | } 93 | 94 | [Test] 95 | public void WorksheetNoHeader_WorksheetName_arg() 96 | { 97 | var companies = from c in _factory.WorksheetNoHeader("Sheet1") 98 | select c; 99 | 100 | Assert.AreEqual(7, companies.Count(), "Company Count"); 101 | Assert.AreEqual("ACME", companies.First()[0].ToString(), "First Company Name"); 102 | Assert.AreEqual(455, companies.Last()[2].Cast(), "Last Company Employee Count"); 103 | } 104 | 105 | [Test] 106 | public void WorksheetNoHeader_WorksheetIndex_arg() 107 | { 108 | var companies = from c in _factory.WorksheetNoHeader(1) 109 | select c; 110 | 111 | Assert.AreEqual(7, companies.Count(), "Company Count"); 112 | Assert.AreEqual("ACME", companies.First()[0].ToString(), "First Company Name"); 113 | Assert.AreEqual(455, companies.Last()[2].Cast(), "Last Company Employee Count"); 114 | } 115 | 116 | [Test] 117 | public void WorksheetRangeNoHeader_no_arg() 118 | { 119 | var companies = from c in _factory.WorksheetRangeNoHeader("A1", "D7") 120 | select c; 121 | 122 | Assert.AreEqual(7, companies.Count(), "Company Count"); 123 | Assert.AreEqual("ACME", companies.First()[0].ToString(), "First Company Name"); 124 | Assert.AreEqual(455, companies.Last()[2].Cast(), "Last Company Employee Count"); 125 | } 126 | 127 | [Test] 128 | public void WorksheetRangeNoHeader_WorksheetName_arg() 129 | { 130 | var companies = from c in _factory.WorksheetRangeNoHeader("C5", "F11", "Range") 131 | select c; 132 | 133 | Assert.AreEqual(7, companies.Count(), "Company Count"); 134 | Assert.AreEqual("ACME", companies.First()[0].ToString(), "First Company Name"); 135 | Assert.AreEqual(455, companies.Last()[2].Cast(), "Last Company Employee Count"); 136 | } 137 | 138 | [Test] 139 | public void WorksheetRangeNoHeader_WorksheetIndex_arg() 140 | { 141 | var companies = from c in _factory.WorksheetRangeNoHeader("C5", "F11", 0) 142 | select c; 143 | 144 | Assert.AreEqual(7, companies.Count(), "Company Count"); 145 | Assert.AreEqual("ACME", companies.First()[0].ToString(), "First Company Name"); 146 | Assert.AreEqual(455, companies.Last()[2].Cast(), "Last Company Employee Count"); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/NoHeader_SQLStatements_UnitTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Data.OleDb; 7 | 8 | namespace LinqToExcel.Tests 9 | { 10 | [Author("Paul Yoder", "paulyoder@gmail.com")] 11 | [Category("Unit")] 12 | [TestFixture] 13 | public class NoHeader_SQLStatements_UnitTests : SQLLogStatements_Helper 14 | { 15 | private ExcelQueryFactory _factory; 16 | 17 | [OneTimeSetUp] 18 | public void fs() 19 | { 20 | InstantiateLogger(); 21 | } 22 | 23 | [SetUp] 24 | public void s() 25 | { 26 | _factory = new ExcelQueryFactory("", new LogManagerFactory()); 27 | ClearLogEvents(); 28 | } 29 | 30 | [Test] 31 | public void range_csv_file_throws_exception() 32 | { 33 | var csvFile = @"C:\ExcelFiles\NoHeaderRange.csv"; 34 | 35 | var excel = new ExcelQueryFactory(csvFile, new LogManagerFactory()); 36 | Assert.That(() => (from c in excel.WorksheetRangeNoHeader("B9", "E15") 37 | select c), 38 | Throws.TypeOf(), "Cannot use WorksheetRangeNoHeader on csv files"); 39 | 40 | } 41 | 42 | [Test] 43 | public void where_clause() 44 | { 45 | var warnerCompany = from c in _factory.WorksheetNoHeader() 46 | where c[1] == "Bugs Bunny" 47 | select c; 48 | 49 | try { warnerCompany.GetEnumerator(); } 50 | catch (OleDbException) { } 51 | 52 | var expectedSQL = "SELECT * FROM [Sheet1$] WHERE (F2 = ?)"; 53 | Assert.AreEqual(expectedSQL, GetSQLStatement()); 54 | } 55 | 56 | [Test] 57 | public void where_is_null() 58 | { 59 | var warnerCompany = from c in _factory.WorksheetNoHeader() 60 | where c[1] == null 61 | select c; 62 | 63 | try { warnerCompany.GetEnumerator(); } 64 | catch (OleDbException) { } 65 | 66 | var expectedSQL = "SELECT * FROM [Sheet1$] WHERE (F2 IS NULL)"; 67 | Assert.AreEqual(expectedSQL, GetSQLStatement()); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/PersistentConnection_IntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using NUnit.Framework; 5 | 6 | namespace LinqToExcel.Tests 7 | { 8 | [Author("Andrew Corkery", "andrew.corkery@gmail.com")] 9 | [Category("Integration")] 10 | [TestFixture] 11 | public class PersistentConnection_IntegrationTests 12 | { 13 | private IExcelQueryFactory _factory; 14 | 15 | [OneTimeSetUp] 16 | public void fs() 17 | { 18 | string testDirectory = AppDomain.CurrentDomain.BaseDirectory; 19 | string excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 20 | string excelFileName = Path.Combine(excelFilesDirectory, "Companies.xlsm"); 21 | 22 | _factory = new ExcelQueryFactory(excelFileName, new LogManagerFactory()); 23 | _factory.UsePersistentConnection = true; 24 | } 25 | 26 | [Test] 27 | public void WorksheetRangeNoHeader_returns_7_companies() 28 | { 29 | var companies = from c in _factory.WorksheetRangeNoHeader("A2", "D8", "Sheet1") 30 | select c; 31 | 32 | Assert.AreEqual(7, companies.Count()); 33 | } 34 | 35 | [Test] 36 | public void WorksheetRangeNoHeader_can_query_sheet_500_times_on_same_connection() 37 | { 38 | IQueryable rows = null; 39 | 40 | int totalRows = 0; 41 | 42 | for (int i = 0; i < 500; i++) 43 | { 44 | rows = from cm in _factory.WorksheetRangeNoHeader("A2", "D8", "Sheet1") 45 | select cm; 46 | 47 | totalRows += rows.Count(); 48 | } 49 | 50 | Assert.AreEqual((500*7), totalRows); 51 | } 52 | 53 | [OneTimeTearDown] 54 | public void td() 55 | { 56 | //dispose of the factory (and persistent connection) 57 | _factory.Dispose(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/Range_IntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.IO; 7 | 8 | namespace LinqToExcel.Tests 9 | { 10 | [Author("Paul Yoder", "paulyoder@gmail.com")] 11 | [Category("Integration")] 12 | [TestFixture] 13 | public class Range_IntegrationTests 14 | { 15 | ExcelQueryFactory _factory; 16 | string _excelFileName; 17 | 18 | [OneTimeSetUp] 19 | public void fs() 20 | { 21 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 22 | var excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 23 | _excelFileName = Path.Combine(excelFilesDirectory, "Companies.xls"); 24 | } 25 | 26 | [SetUp] 27 | public void s() 28 | { 29 | _factory = new ExcelQueryFactory(_excelFileName, new LogManagerFactory()); 30 | } 31 | 32 | [Test] 33 | public void use_sheetData_and_worksheetIndex() 34 | { 35 | var companies = from c in _factory.WorksheetRange("C6", "F13", 5) 36 | select c; 37 | 38 | Assert.AreEqual(7, companies.Count(), "Count"); 39 | Assert.AreEqual("ACME", companies.First().Name, "First Company Name"); 40 | } 41 | 42 | [Test] 43 | public void use_row_and_worksheetIndex() 44 | { 45 | var companies = from c in _factory.WorksheetRange("c6", "f13", 5) 46 | select c; 47 | 48 | Assert.AreEqual(7, companies.Count(), "Count"); 49 | Assert.AreEqual("Ontario Systems", companies.Last()["Name"].ToString(), "Last Company Name"); 50 | } 51 | 52 | 53 | [Test] 54 | public void use_sheetData_where_null() 55 | { 56 | var factory = new ExcelQueryFactory(_excelFileName + "x", new LogManagerFactory()); 57 | var companies = from c in factory.WorksheetRange("A1", "D4", "NullCells") 58 | where c.EmployeeCount == null 59 | select c; 60 | 61 | Assert.AreEqual(2, companies.Count(), "Count"); 62 | } 63 | 64 | [Test] 65 | public void use_row_where_null() 66 | { 67 | var factory = new ExcelQueryFactory(_excelFileName + "x", new LogManagerFactory()); 68 | var companies = from c in factory.WorksheetRange("A1", "D4", "NullCells") 69 | where c["EmployeeCount"] == null 70 | select c; 71 | 72 | Assert.AreEqual(2, companies.Count(), "Count"); 73 | } 74 | 75 | [Test] 76 | public void use_row_no_header_where_null() 77 | { 78 | var factory = new ExcelQueryFactory(_excelFileName + "x", new LogManagerFactory()); 79 | var companies = from c in factory.WorksheetRangeNoHeader("A1", "D4", "NullCells") 80 | where c[2] == null 81 | select c; 82 | 83 | Assert.AreEqual(2, companies.Count(), "Count"); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/Range_SQLStatements_UnitTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Data.OleDb; 7 | 8 | namespace LinqToExcel.Tests 9 | { 10 | [Author("Paul Yoder", "paulyoder@gmail.com")] 11 | [Category("Unit")] 12 | [TestFixture] 13 | public class Range_SQLStatements_UnitTests : SQLLogStatements_Helper 14 | { 15 | private IExcelQueryFactory _factory; 16 | 17 | [OneTimeSetUp] 18 | public void fs() 19 | { 20 | InstantiateLogger(); 21 | } 22 | 23 | [SetUp] 24 | public void s() 25 | { 26 | ClearLogEvents(); 27 | _factory = new ExcelQueryFactory("", new LogManagerFactory()); 28 | } 29 | 30 | [Test] 31 | public void Appends_range_info_to_table_name() 32 | { 33 | var companies = from c in _factory.WorksheetRange("B2", "D4") 34 | select c; 35 | 36 | try { companies.GetEnumerator(); } 37 | catch (OleDbException) { } 38 | Assert.AreEqual("SELECT * FROM [Sheet1$B2:D4]", GetSQLStatement()); 39 | } 40 | 41 | [Test] 42 | public void Throws_argument_exception_if_startRange_is_incorrect_format() 43 | { 44 | try 45 | { 46 | Assert.That(() => from c in _factory.WorksheetRange("22", "D4") 47 | select c, 48 | Throws.TypeOf(), "StartRange argument '22' is invalid format for cell name"); 49 | } 50 | catch (OleDbException) { } 51 | } 52 | 53 | [Test] 54 | public void Throws_argument_exception_if_endRange_is_incorrect_format() 55 | { 56 | try 57 | { 58 | Assert.That(() => from c in _factory.WorksheetRange("B2", "DD") 59 | select c, 60 | Throws.TypeOf(), "EndRange argument 'DD' is invalid format for cell name"); 61 | } 62 | catch (OleDbException) { } 63 | } 64 | 65 | [Test] 66 | public void use_sheetData_method() 67 | { 68 | var companies = from c in _factory.WorksheetRange("B2", "D4") 69 | select c; 70 | 71 | try { companies.GetEnumerator(); } 72 | catch (OleDbException) { } 73 | Assert.AreEqual("SELECT * FROM [Sheet1$B2:D4]", GetSQLStatement()); 74 | } 75 | 76 | [Test] 77 | public void use_sheetData_worksheetName_method() 78 | { 79 | var companies = from c in _factory.WorksheetRange("B2", "D4", "worksheetName") 80 | select c; 81 | 82 | try { companies.GetEnumerator(); } 83 | catch (OleDbException) { } 84 | Assert.AreEqual("SELECT * FROM [worksheetName$B2:D4]", GetSQLStatement()); 85 | } 86 | 87 | [Test] 88 | public void use_row_method() 89 | { 90 | var companies = from c in _factory.WorksheetRange("B2", "D4") 91 | select c; 92 | 93 | try { companies.GetEnumerator(); } 94 | catch (OleDbException) { } 95 | Assert.AreEqual("SELECT * FROM [Sheet1$B2:D4]", GetSQLStatement()); 96 | } 97 | 98 | [Test] 99 | public void use_row_worksheetName_method() 100 | { 101 | var companies = from c in _factory.WorksheetRange("B2", "D4", "worksheetName") 102 | select c; 103 | 104 | try { companies.GetEnumerator(); } 105 | catch (OleDbException) { } 106 | Assert.AreEqual("SELECT * FROM [worksheetName$B2:D4]", GetSQLStatement()); 107 | } 108 | 109 | [Test] 110 | public void use_row_where_is_null() 111 | { 112 | var companies = from c in _factory.WorksheetRange("B2", "D4", "worksheetName") 113 | where c["City"] == null 114 | select c; 115 | //System.Diagnostics.Debugger.Launch(); 116 | try { companies.GetEnumerator(); } 117 | catch (OleDbException) { } 118 | var expectedSql = string.Format("SELECT * FROM [worksheetName$B2:D4] WHERE ({0} IS NULL)", GetSQLFieldName("City")); 119 | Assert.AreEqual(expectedSql, GetSQLStatement()); 120 | } 121 | 122 | [Test] 123 | public void use_sheetData_where_is_null() 124 | { 125 | var companies = from c in _factory.WorksheetRange("B2", "D4") 126 | where c.Name == null 127 | select c; 128 | 129 | try { companies.GetEnumerator(); } 130 | catch (OleDbException) { } 131 | var expectedSql = string.Format("SELECT * FROM [Sheet1$B2:D4] WHERE ({0} IS NULL)", GetSQLFieldName("Name")); 132 | Assert.AreEqual(expectedSql, GetSQLStatement()); 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/RowTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using NUnit.Framework; 4 | 5 | namespace LinqToExcel.Tests 6 | { 7 | [Author("Paul Yoder", "paulyoder@gmail.com")] 8 | [Category("Unit")] 9 | [TestFixture] 10 | public class RowTest 11 | { 12 | IDictionary _columnMappings; 13 | IList _cells; 14 | 15 | [SetUp] 16 | public void s() 17 | { 18 | _columnMappings = new Dictionary(); 19 | _columnMappings["Name"] = 0; 20 | _columnMappings["Favorite Sport"] = 1; 21 | _columnMappings["Age"] = 2; 22 | 23 | _cells = new List(); 24 | _cells.Add(new Cell("Paul")); 25 | _cells.Add(new Cell("Ultimate Frisbee")); 26 | _cells.Add(new Cell(25)); 27 | } 28 | 29 | [Test] 30 | public void index_maps_cells_correctly() 31 | { 32 | var row = new Row(_cells, _columnMappings); 33 | Assert.AreEqual(_cells[0], row[0]); 34 | Assert.AreEqual(_cells[1], row[1]); 35 | Assert.AreEqual(_cells[2], row[2]); 36 | } 37 | 38 | [Test] 39 | public void column_name_index_maps_cells_correctly() 40 | { 41 | var row = new Row(_cells, _columnMappings); 42 | Assert.AreEqual(_cells[0], row["Name"]); 43 | Assert.AreEqual(_cells[1], row["Favorite Sport"]); 44 | Assert.AreEqual(_cells[2], row["Age"]); 45 | } 46 | 47 | [Test] 48 | public void invalid_column_name_index_throws_argument_exception() 49 | { 50 | var newRow = new Row(_cells, _columnMappings); 51 | Assert.That(() => newRow["First Name"], 52 | Throws.TypeOf(), "'First Name' column name does not exist. Valid column names are 'Name', 'Favorite Sport', 'Age'"); 53 | 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/Row_IntegrationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using System.IO; 5 | 6 | namespace LinqToExcel.Tests 7 | { 8 | [Author("Paul Yoder", "paulyoder@gmail.com")] 9 | [Category("Integration")] 10 | [TestFixture] 11 | public class Row_IntegrationTests 12 | { 13 | string _excelFileName; 14 | [OneTimeSetUp] 15 | public void fs() 16 | { 17 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 18 | var excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 19 | _excelFileName = Path.Combine(excelFilesDirectory, "Companies.xls"); 20 | } 21 | 22 | [Test] 23 | public void column_values() 24 | { 25 | var firstCompany = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 26 | select c).First(); 27 | 28 | Assert.AreEqual("ACME", firstCompany["Name"].ToString()); 29 | Assert.AreEqual("Bugs Bunny", firstCompany["CEO"].ToString()); 30 | Assert.AreEqual(25, firstCompany["EmployeeCount"].Cast()); 31 | Assert.AreEqual(new DateTime(1918, 11, 11).Date, firstCompany["StartDate"].Cast().Date); 32 | } 33 | 34 | [Test] 35 | public void columnNames_returns_list_of_column_names() 36 | { 37 | var firstCompany = (from c in ExcelQueryFactory.Worksheet(null, _excelFileName, null, new LogManagerFactory()) 38 | select c).First(); 39 | 40 | Assert.AreEqual(4, firstCompany.ColumnNames.Count()); 41 | Assert.IsTrue(firstCompany.ColumnNames.Contains("Name")); 42 | Assert.IsTrue(firstCompany.ColumnNames.Contains("CEO")); 43 | Assert.IsTrue(firstCompany.ColumnNames.Contains("EmployeeCount")); 44 | Assert.IsTrue(firstCompany.ColumnNames.Contains("StartDate")); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/Row_SQLStatement_UnitTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using System.Data.OleDb; 5 | 6 | namespace LinqToExcel.Tests 7 | { 8 | [Author("Paul Yoder", "paulyoder@gmail.com")] 9 | [Category("Unit")] 10 | [TestFixture] 11 | public class Row_SQLStatement_UnitTests : SQLLogStatements_Helper 12 | { 13 | [OneTimeSetUp] 14 | public void fs() 15 | { 16 | InstantiateLogger(); 17 | } 18 | 19 | [SetUp] 20 | public void s() 21 | { 22 | ClearLogEvents(); 23 | } 24 | 25 | [Test] 26 | public void no_where_clause() 27 | { 28 | var companies = from c in ExcelQueryFactory.Worksheet("", "", null, new LogManagerFactory()) 29 | select c; 30 | 31 | try { companies.GetEnumerator(); } 32 | catch (OleDbException) { } 33 | Assert.AreEqual("SELECT * FROM [Sheet1$]", GetSQLStatement()); 34 | } 35 | 36 | [Test] 37 | public void column_name_used_in_where_clause() 38 | { 39 | var companies = from c in ExcelQueryFactory.Worksheet("", "", null, new LogManagerFactory()) 40 | where c["City"] == "Omaha" 41 | select c; 42 | 43 | try { companies.GetEnumerator(); } 44 | catch (OleDbException) { } 45 | var expectedSql = string.Format("SELECT * FROM [Sheet1$] WHERE ({0} = ?)", GetSQLFieldName("City")); 46 | Assert.AreEqual(expectedSql, GetSQLStatement()); 47 | Assert.AreEqual("Omaha", GetSQLParameters()[0]); 48 | } 49 | 50 | [Test] 51 | public void column_name_used_in_orderby_clause() 52 | { 53 | var companies = (from c in ExcelQueryFactory.Worksheet("", "", null, new LogManagerFactory()) 54 | select c).OrderBy(x => x["City"]); 55 | 56 | try { companies.GetEnumerator(); } 57 | catch (OleDbException) { } 58 | var expectedSql = string.Format("SELECT * FROM [Sheet1$] ORDER BY {0} ASC", GetSQLFieldName("City")); 59 | Assert.AreEqual(expectedSql, GetSQLStatement()); 60 | } 61 | 62 | [Test] 63 | public void column_name_is_cast_in_where_clause() 64 | { 65 | var companies = from c in ExcelQueryFactory.Worksheet("", "", null, new LogManagerFactory()) 66 | where c["Modified"].Cast() < new DateTime(2009, 11, 2) 67 | select c; 68 | 69 | try { companies.GetEnumerator(); } 70 | catch (OleDbException) { } 71 | var expectedSql = string.Format("SELECT * FROM [Sheet1$] WHERE ({0} < ?)", GetSQLFieldName("Modified")); 72 | Assert.AreEqual(expectedSql, GetSQLStatement()); 73 | } 74 | 75 | [Test] 76 | public void where_is_null() 77 | { 78 | var companies = from c in ExcelQueryFactory.Worksheet("", "", null, new LogManagerFactory()) 79 | where c["City"] == null 80 | select c; 81 | 82 | try { companies.GetEnumerator(); } 83 | catch (OleDbException) { } 84 | var expectedSql = string.Format("SELECT * FROM [Sheet1$] WHERE ({0} IS NULL)", GetSQLFieldName("City")); 85 | Assert.AreEqual(expectedSql, GetSQLStatement()); 86 | } 87 | 88 | [Test] 89 | public void where_is_not_null() 90 | { 91 | var companies = from c in ExcelQueryFactory.Worksheet("", "", null, new LogManagerFactory()) 92 | where c["City"] != null 93 | select c; 94 | 95 | try { companies.GetEnumerator(); } 96 | catch (OleDbException) { } 97 | var expectedSql = string.Format("SELECT * FROM [Sheet1$] WHERE ({0} IS NOT NULL)", GetSQLFieldName("City")); 98 | Assert.AreEqual(expectedSql, GetSQLStatement()); 99 | } 100 | 101 | [Test] 102 | public void argument_exception_thrown_when_column_indexes_used_in_worksheet_where_clause() 103 | { 104 | var companies = from c in ExcelQueryFactory.Worksheet("", "", null, new LogManagerFactory()) 105 | where c[0] == "Omaha" 106 | select c; 107 | try 108 | { 109 | Assert.That(() => companies.GetEnumerator(), 110 | Throws.TypeOf(), "Can only use column indexes in WHERE clause when using WorksheetNoHeader"); 111 | } 112 | catch (OleDbException) { } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/SQLLogStatements_Helper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using log4net.Appender; 3 | using log4net.Core; 4 | using System.Linq; 5 | 6 | namespace LinqToExcel.Tests 7 | { 8 | public class SQLLogStatements_Helper 9 | { 10 | /// 11 | /// This memory appender catches all the logged messages 12 | /// which the unit tests can use for their assertions 13 | /// 14 | protected MemoryAppender _loggedEvents; 15 | 16 | protected void InstantiateLogger() 17 | { 18 | _loggedEvents = new MemoryAppender(); 19 | log4net.Config.BasicConfigurator.Configure(_loggedEvents); 20 | } 21 | 22 | protected void ClearLogEvents() 23 | { 24 | _loggedEvents.Clear(); 25 | } 26 | 27 | /// 28 | /// Retrieves the SQL statement from the log events 29 | /// 30 | /// 31 | /// The SQL statement log message is in the following format 32 | /// SQL: {sql statement} 33 | /// 34 | protected string GetSQLStatement() 35 | { 36 | var loggingEvents = _loggedEvents.GetEvents(); 37 | foreach (LoggingEvent logEvent in loggingEvents) 38 | { 39 | if (logEvent.LoggerName == "LinqToExcel.SQL") 40 | return logEvent.RenderedMessage.Split(";".ToCharArray())[0]; 41 | } 42 | return ""; 43 | } 44 | 45 | /// 46 | /// Returns the SQL Parameters 47 | /// 48 | /// 49 | /// The SQL Parameters log messages are in the following format 50 | /// Param[{param #}]: {parameter value} 51 | /// 52 | protected string[] GetSQLParameters() 53 | { 54 | var loggingEvents = _loggedEvents.GetEvents(); 55 | var parameters = new List(); 56 | foreach (LoggingEvent logEvent in loggingEvents) 57 | { 58 | if (logEvent.LoggerName == "LinqToExcel.SQL") 59 | { 60 | var splitMessage = logEvent.RenderedMessage.Split(";".ToCharArray()); 61 | for (var i = 1; i < splitMessage.Length - 1; i++) 62 | { 63 | parameters.Add( 64 | splitMessage[i] 65 | .Split("=".ToCharArray()) 66 | .Last() 67 | .Replace("'", "") 68 | .Substring(1)); 69 | } 70 | } 71 | } 72 | return parameters.ToArray(); 73 | } 74 | 75 | /// 76 | /// Returns the sql formatted column name 77 | /// 78 | /// Name of column 79 | protected string GetSQLFieldName(string columnName) 80 | { 81 | return string.Format("[{0}]", columnName); 82 | } 83 | 84 | /// 85 | /// Returns the connection string 86 | /// 87 | protected string GetConnectionString() 88 | { 89 | var loggingEvents = _loggedEvents.GetEvents(); 90 | foreach (LoggingEvent logEvent in loggingEvents) 91 | { 92 | string message = logEvent.RenderedMessage; 93 | if (message.Length > 5 && message.Substring(0, 18) == "Connection String:") 94 | return logEvent.RenderedMessage.Substring(19); 95 | } 96 | return ""; 97 | } 98 | 99 | protected string GetDataSource() 100 | { 101 | var conProps = GetConnectionString().Split(";".ToCharArray()); 102 | foreach (string conProp in conProps) 103 | { 104 | if (conProp.Substring(0, 11) == "Data Source") 105 | return conProp.Substring(12); 106 | } 107 | return ""; 108 | } 109 | 110 | protected string GetExtendedProperties() 111 | { 112 | var conString = GetConnectionString(); 113 | var location = conString.IndexOf("Extended Properties="); 114 | return conString.Substring(location + 20); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/SkipEmptyRows_UnitTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using NUnit.Framework; 5 | 6 | namespace LinqToExcel.Tests 7 | { 8 | [Category("Unit")] 9 | [TestFixture] 10 | public class SkipEmptyRows_UnitTests 11 | { 12 | ExcelQueryFactory _factory; 13 | string _fileName; 14 | 15 | [OneTimeSetUp] 16 | public void fs() 17 | { 18 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 19 | var excelFilesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 20 | _fileName = Path.Combine(excelFilesDirectory, "EmptyRows.xls"); 21 | } 22 | 23 | [SetUp] 24 | public void s() 25 | { 26 | _factory = new ExcelQueryFactory(_fileName, new LogManagerFactory()); 27 | } 28 | 29 | [Test] 30 | public void CanGetAllRows_GetTypeResults() 31 | { 32 | _factory.SkipEmptyRows = false; 33 | var skippedRows = from row in _factory.Worksheet("EmptyRows") 34 | select row; 35 | 36 | Assert.AreEqual(6, skippedRows.ToList().Count); 37 | } 38 | 39 | [Test] 40 | public void CanGetAllRows_GetRowResults() 41 | { 42 | _factory.SkipEmptyRows = false; 43 | var skippedRows = from row in _factory.Worksheet("EmptyRows") 44 | select row; 45 | 46 | Assert.AreEqual(6, skippedRows.ToList().Count); 47 | } 48 | 49 | [Test] 50 | public void CanGetAllRows_GetRowNoHeaderResults() 51 | { 52 | _factory.SkipEmptyRows = false; 53 | var skippedRows = from row in _factory.WorksheetNoHeader("EmptyRowsNoHeader") 54 | select row; 55 | 56 | Assert.AreEqual(6, skippedRows.ToList().Count); 57 | } 58 | 59 | [Test] 60 | public void CanSkipEmptyRows_GetTypeResults() 61 | { 62 | _factory.SkipEmptyRows = true; 63 | var skippedRows = from row in _factory.Worksheet("EmptyRows") 64 | select row; 65 | 66 | Assert.AreEqual(3, skippedRows.ToList().Count); 67 | } 68 | 69 | [Test] 70 | public void CanSkipEmptyRows_GetRowResults() 71 | { 72 | _factory.SkipEmptyRows = true; 73 | var skippedRows = from row in _factory.Worksheet("EmptyRows") 74 | select row; 75 | 76 | Assert.AreEqual(3, skippedRows.ToList().Count); 77 | } 78 | 79 | [Test] 80 | public void CanSkipEmptyRows_GetRowNoHeaderResults() 81 | { 82 | _factory.SkipEmptyRows = true; 83 | var skippedRows = from row in _factory.WorksheetNoHeader("EmptyRowsNoHeader") 84 | select row; 85 | 86 | Assert.AreEqual(3, skippedRows.ToList().Count); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/Transformations.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToExcel.Tests 2 | { 3 | public class Transformation1 4 | { 5 | public int Value { get; set; } 6 | } 7 | 8 | public class Transformation2 9 | { 10 | public string Value { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/UnSupportedMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using NUnit.Framework; 5 | using System.Data.OleDb; 6 | 7 | namespace LinqToExcel.Tests 8 | { 9 | [Author("Paul Yoder", "paulyoder@gmail.com")] 10 | [Category("Unit")] 11 | [TestFixture] 12 | public class UnSupportedMethods 13 | { 14 | [Test] 15 | public void contains() 16 | { 17 | Assert.That(() => (from c in ExcelQueryFactory.Worksheet(null, "", null, new LogManagerFactory()) 18 | select c).Contains(new Company()), 19 | Throws.TypeOf(), "LinqToExcel does not provide support for the Contains() method"); 20 | } 21 | 22 | [Test] 23 | public void default_if_empty() 24 | { 25 | var companies = (from c in ExcelQueryFactory.Worksheet(null, "", null, new LogManagerFactory()) 26 | select c).DefaultIfEmpty(); 27 | Assert.That(() => companies.ToList(), 28 | Throws.TypeOf(), "LinqToExcel does not provide support for the DefaultIfEmpty()"); 29 | } 30 | 31 | [Test] 32 | public void except() 33 | { 34 | Assert.That(() => (from c in ExcelQueryFactory.Worksheet(null, "", null, new LogManagerFactory()) 35 | select c).Except(new List()).ToList(), 36 | Throws.TypeOf(), "LinqToExcel does not provide support for the Group() method"); 37 | } 38 | 39 | [Test] 40 | public void group() 41 | { 42 | var companies = from c in ExcelQueryFactory.Worksheet(null, "", null, new LogManagerFactory()) 43 | group c by c.CEO into g 44 | select g; 45 | try 46 | { 47 | Assert.That(() => companies.ToList(), 48 | Throws.TypeOf(), "LinqToExcel does not provide support for the Group() method"); 49 | } 50 | catch (OleDbException) { } 51 | } 52 | 53 | [Test] 54 | public void intersect() 55 | { 56 | Assert.That(() => (from c in ExcelQueryFactory.Worksheet(null, "", null, new LogManagerFactory()) 57 | select c.CEO).Intersect( 58 | from d in ExcelQueryFactory.Worksheet(null, "", null, new LogManagerFactory()) 59 | select d.CEO) 60 | .ToList(), 61 | Throws.TypeOf(), "LinqToExcel does not provide support for the Intersect() method"); 62 | } 63 | 64 | [Test] 65 | public void of_type() 66 | { 67 | Assert.That(() => (from c in ExcelQueryFactory.Worksheet(null, "", null, new LogManagerFactory()) 68 | select c).OfType().ToList(), 69 | Throws.TypeOf(), "LinqToExcel does not provide support for the OfType() method"); 70 | } 71 | 72 | [Test] 73 | public void single() 74 | { 75 | Assert.That(() => (from c in ExcelQueryFactory.Worksheet(null, "", null, new LogManagerFactory()) 76 | select c).Single(), 77 | Throws.TypeOf(), "LinqToExcel does not provide support for the Single() method. Use the First() method instead"); 78 | } 79 | 80 | [Test] 81 | public void union() 82 | { 83 | Assert.That(() => (from c in ExcelQueryFactory.Worksheet(null, "", null, new LogManagerFactory()) 84 | select c).Union( 85 | from d in ExcelQueryFactory.Worksheet(null, "", null, new LogManagerFactory()) 86 | select d) 87 | .ToList(), 88 | Throws.TypeOf(), "LinqToExcel does not provide support for the Union() method"); 89 | } 90 | 91 | [Test] 92 | public void join() 93 | { 94 | Assert.That(() => (from c in ExcelQueryFactory.Worksheet(null, "", null, new LogManagerFactory()) 95 | join d in ExcelQueryFactory.Worksheet(null, "", null, new LogManagerFactory()) 96 | on c.CEO equals d.CEO 97 | select d) 98 | .ToList(), 99 | Throws.TypeOf(), "LinqToExcel does not provide support for the Join() method"); 100 | } 101 | 102 | [Test] 103 | public void distinct_on_whole_row() 104 | { 105 | Assert.That(() => (from c in ExcelQueryFactory.Worksheet(null, "", null, new LogManagerFactory()) 106 | select c).Distinct().ToList(), 107 | Throws.TypeOf(), "LinqToExcel only provides support for the Distinct() method when it's mapped to a class and a single property is selected. [e.g. (from row in excel.Worksheet() select row.FirstName).Distinct()]"); 108 | } 109 | 110 | [Test] 111 | public void distinct_on_no_header() 112 | { 113 | var excel = new ExcelQueryFactory("", new LogManagerFactory()); 114 | Assert.That(() => (from c in excel.WorksheetNoHeader() 115 | select c).Distinct().ToList(), 116 | Throws.TypeOf(), "LinqToExcel only provides support for the Distinct() method when it's mapped to a class and a single property is selected. [e.g. (from row in excel.Worksheet() select row.FirstName).Distinct()]"); 117 | } 118 | 119 | [Test] 120 | public void distinct_on_no_header_with_selected_column() 121 | { 122 | var excel = new ExcelQueryFactory("", new LogManagerFactory()); 123 | Assert.That(() => (from c in excel.WorksheetNoHeader() 124 | select c[0]).Distinct().ToList(), 125 | Throws.TypeOf(), "LinqToExcel only provides support for the Distinct() method when it's mapped to a class and a single property is selected. [e.g. (from row in excel.Worksheet() select row.FirstName).Distinct()]"); 126 | } 127 | 128 | [Test] 129 | public void distinct_on_row() 130 | { 131 | var excel = new ExcelQueryFactory("", new LogManagerFactory()); 132 | Assert.That(() => (from c in excel.Worksheet() 133 | select c).Distinct().ToList(), 134 | Throws.TypeOf(), "LinqToExcel only provides support for the Distinct() method when it's mapped to a class and a single property is selected. [e.g. (from row in excel.Worksheet() select row.FirstName).Distinct()]"); 135 | } 136 | 137 | [Test] 138 | public void distinct_on_row_with_selected_column() 139 | { 140 | var excel = new ExcelQueryFactory("", new LogManagerFactory()); 141 | Assert.That(() => (from c in excel.Worksheet() 142 | select c["Name"]).Distinct().ToList(), 143 | Throws.TypeOf(), "LinqToExcel only provides support for the Distinct() method when it's mapped to a class and a single property is selected. [e.g. (from row in excel.Worksheet() select row.FirstName).Distinct()]"); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/LinqToExcel.Tests/WorkSheetNameTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | using NUnit.Framework; 5 | 6 | namespace LinqToExcel.Tests { 7 | 8 | [Author("Paul Yoder", "paulyoder@gmail.com")] 9 | [Category("Integration")] 10 | [TestFixture] 11 | public class WorkSheetNameTests { 12 | private String _filesDirectory; 13 | 14 | [OneTimeSetUp] 15 | public void Setup() { 16 | var testDirectory = AppDomain.CurrentDomain.BaseDirectory; 17 | _filesDirectory = Path.Combine(testDirectory, "ExcelFiles"); 18 | } 19 | 20 | [Test] 21 | public void WorkSheetNamesAreDecodedCorrectly() { 22 | var fileName = Path.Combine(_filesDirectory, "WorksheetNames.xlsx"); 23 | 24 | var workbook = new ExcelQueryFactory(fileName, new LogManagerFactory()); 25 | var worksheetNames = workbook.GetWorksheetNames(); 26 | 27 | CollectionAssert.AreEqual( 28 | new [] { 29 | " ' ", 30 | "$woot$", 31 | "Emb$dded", 32 | "Ends with $'\"", 33 | "Ends with a $", 34 | "Has a $ in it" 35 | }, 36 | worksheetNames 37 | ); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/LinqToExcel.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27004.2005 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinqToExcel", "LinqToExcel\LinqToExcel.csproj", "{08F80D96-5387-4406-B88B-DCC0CB661702}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinqToExcel.Tests", "LinqToExcel.Tests\LinqToExcel.Tests.csproj", "{195B956A-8029-44FD-9518-C04F5280611F}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {08F80D96-5387-4406-B88B-DCC0CB661702}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {08F80D96-5387-4406-B88B-DCC0CB661702}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {08F80D96-5387-4406-B88B-DCC0CB661702}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {08F80D96-5387-4406-B88B-DCC0CB661702}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {195B956A-8029-44FD-9518-C04F5280611F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {195B956A-8029-44FD-9518-C04F5280611F}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {195B956A-8029-44FD-9518-C04F5280611F}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {195B956A-8029-44FD-9518-C04F5280611F}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {80264802-F218-4279-85F8-73E6A896B2A7} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/LinqToExcel/Attributes/ExcelColumnAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinqToExcel.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)] 6 | public sealed class ExcelColumnAttribute : Attribute 7 | { 8 | private readonly string _columnName; 9 | 10 | public ExcelColumnAttribute(string columnName) 11 | { 12 | _columnName = columnName; 13 | } 14 | 15 | public string ColumnName 16 | { 17 | get { return _columnName; } 18 | } 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/LinqToExcel/Domain/Cell.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinqToExcel 4 | { 5 | /// 6 | /// Represents a cell and its value in an excel spreadsheet 7 | /// 8 | public class Cell 9 | { 10 | /// 11 | /// Cell's value 12 | /// 13 | public object Value { get; private set; } 14 | 15 | /// Cell's value 16 | public Cell(object value) 17 | { 18 | Value = value; 19 | } 20 | 21 | /// 22 | /// Casts the cell's value to the generic argument type 23 | /// 24 | /// Object type to convert to 25 | public T Cast() 26 | { 27 | return (Value == null || Value is DBNull) ? 28 | default(T) : 29 | (T)Convert.ChangeType(Value, typeof(T)); 30 | } 31 | 32 | /// 33 | /// Cell's value as a string 34 | /// 35 | public override string ToString() 36 | { 37 | return Value.ToString(); 38 | } 39 | 40 | /// 41 | /// Allow cell to be implicitly cast to a string 42 | /// 43 | public static implicit operator string(Cell cell) 44 | { 45 | return cell.ToString(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/LinqToExcel/Domain/IAllowFieldTypeConversionExceptions.cs: -------------------------------------------------------------------------------- 1 | using LinqToExcel.Exceptions; 2 | using System.Collections.Generic; 3 | 4 | namespace LinqToExcel 5 | { 6 | /// 7 | /// Implement this interface to bypass the default thrown exception 8 | /// on a field parse error. All exceptions will instead be placed in 9 | /// this list. Be aware that you will still get a typed row back but 10 | /// failed column values should be untrusted. 11 | /// 12 | public interface IAllowFieldTypeConversionExceptions 13 | { 14 | IList FieldTypeConversionExceptions { get; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/LinqToExcel/Domain/IContainsUnmappedCells.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LinqToExcel 4 | { 5 | /// 6 | /// Implement this interface to receive values for cells that 7 | /// were not mapped. 8 | /// 9 | public interface IContainsUnmappedCells 10 | { 11 | IDictionary UnmappedCells { get; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/LinqToExcel/Domain/Row.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using LinqToExcel.Extensions; 4 | 5 | namespace LinqToExcel 6 | { 7 | public class Row : List 8 | { 9 | IDictionary _columnIndexMapping; 10 | 11 | public Row() : 12 | this(new List(),new Dictionary()) 13 | { } 14 | 15 | /// Cells contained within the row 16 | /// Column name to cell index mapping 17 | public Row(IList cells, IDictionary columnIndexMapping) 18 | { 19 | for (int i = 0; i < cells.Count; i++) 20 | this.Insert(i, cells[i]); 21 | _columnIndexMapping = columnIndexMapping; 22 | } 23 | 24 | /// Column Name 25 | public Cell this[string columnName] 26 | { 27 | get 28 | { 29 | if (!_columnIndexMapping.ContainsKey(columnName)) 30 | throw new ArgumentException(string.Format("'{0}' column name does not exist. Valid column names are '{1}'", 31 | columnName, string.Join("', '", _columnIndexMapping.Keys.ToArray()))); 32 | return base[_columnIndexMapping[columnName]]; 33 | } 34 | } 35 | 36 | /// 37 | /// List of column names in the row object 38 | /// 39 | public IEnumerable ColumnNames 40 | { 41 | get { return _columnIndexMapping.Keys; } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/LinqToExcel/Domain/RowNoHeader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace LinqToExcel 7 | { 8 | public class RowNoHeader : List 9 | { 10 | /// Cells contained within the row 11 | public RowNoHeader(IEnumerable cells) 12 | { 13 | base.AddRange(cells); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/LinqToExcel/Domain/StrictMappingException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace LinqToExcel.Domain 7 | { 8 | public class StrictMappingException : Exception 9 | { 10 | public StrictMappingException(string message) 11 | : base(message) 12 | { } 13 | 14 | public StrictMappingException(string formatMessage, params object[] args) 15 | : base(string.Format(formatMessage, args)) 16 | { } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/LinqToExcel/Exceptions/ExcelException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace LinqToExcel.Exceptions 7 | { 8 | public class ExcelException : Exception 9 | { 10 | /// 11 | /// Row index where exception occours 12 | /// 13 | public int Row { get; private set; } 14 | 15 | /// 16 | /// Column name where exception occours 17 | /// 18 | public string ColumnName { get; private set; } 19 | 20 | /// 21 | /// Column index where exception occours 22 | /// 23 | public int Column { get; private set; } 24 | 25 | public ExcelException(int row, string columnName, Exception innerException) 26 | : base(string.Format("Error on row {0} and column name '{1}'.", row, columnName), innerException) 27 | { 28 | Row = row; 29 | ColumnName = columnName; 30 | } 31 | 32 | public ExcelException(int row, int column, Exception innerException) 33 | : base(string.Format("Error on row {0} and column '{1}'.", row, Query.ExcelUtilities.ColumnIndexToExcelColumnName(column)), innerException) 34 | { 35 | Row = row; 36 | Column = column; 37 | ColumnName = Query.ExcelUtilities.ColumnIndexToExcelColumnName(column); 38 | } 39 | 40 | public ExcelException(int row, int column, string columnName, Exception innerException) 41 | : base(string.Format("Error on row {0} and column name '{1}'.", row, columnName), innerException) 42 | { 43 | Row = row; 44 | Column = column; 45 | ColumnName = columnName ?? Query.ExcelUtilities.ColumnIndexToExcelColumnName(column); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/LinqToExcel/Extensions/CommonExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Collections; 5 | using System.Text.RegularExpressions; 6 | using System.Linq.Expressions; 7 | 8 | namespace LinqToExcel.Extensions 9 | { 10 | public static class CommonExtensions 11 | { 12 | /// 13 | /// Sets the value of a property 14 | /// 15 | /// Name of the property 16 | /// Value to set the property to 17 | public static void SetProperty(this object @object, string propertyName, object value) 18 | { 19 | @object.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, @object, new object[] { value }); 20 | } 21 | 22 | /// 23 | /// Calls a method 24 | /// 25 | /// Name of the method 26 | /// Method arguments 27 | /// Return value of the method 28 | public static object CallMethod(this object @object, string methodName, params object[] args) 29 | { 30 | return @object.GetType().InvokeMember(methodName, BindingFlags.InvokeMethod, null, @object, args); 31 | } 32 | 33 | public static T Cast(this object @object) 34 | { 35 | return (T)@object.Cast(typeof(T)); 36 | } 37 | 38 | public static object Cast(this object @object, Type castType) 39 | { 40 | //return null for DBNull values 41 | if (@object == null || @object.GetType() == typeof(DBNull) || @object.ToString() == "null") 42 | return null; 43 | 44 | //checking for nullable types 45 | if (castType.IsGenericType && 46 | castType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 47 | { 48 | castType = Nullable.GetUnderlyingType(castType); 49 | } 50 | return Convert.ChangeType(@object, castType); 51 | } 52 | 53 | public static IEnumerable Cast(this IEnumerable list, Func caster) 54 | { 55 | var results = new List(); 56 | foreach (var item in list) 57 | results.Add(caster(item)); 58 | return results; 59 | } 60 | 61 | public static IEnumerable Cast(this IEnumerable list) 62 | { 63 | var func = new Func((item) => 64 | (TResult)Convert.ChangeType(item, typeof(TResult))); 65 | return list.Cast(func); 66 | } 67 | 68 | public static string[] ToArray(this ICollection collection) 69 | { 70 | var list = new List(); 71 | foreach (var item in collection) 72 | list.Add(item); 73 | return list.ToArray(); 74 | } 75 | 76 | public static bool IsNumber(this string value) 77 | { 78 | return Regex.Match(value, @"^\d+$").Success; 79 | } 80 | 81 | public static bool IsNullValue(this Expression exp) 82 | { 83 | var constantExpression = exp as ConstantExpression; 84 | return constantExpression != null && constantExpression.Value == null; 85 | } 86 | 87 | public static string RegexReplace(this string source, string regex, string replacement) 88 | { 89 | return Regex.Replace(source, regex, replacement); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/LinqToExcel/IExcelQueryFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.OleDb; 3 | using System.Linq.Expressions; 4 | using LinqToExcel.Query; 5 | using System.Collections.Generic; 6 | using LinqToExcel.Domain; 7 | 8 | namespace LinqToExcel 9 | { 10 | public interface IExcelQueryFactory : IDisposable 11 | { 12 | /// 13 | /// Full path to the Excel spreadsheet 14 | /// 15 | string FileName { get; set; } 16 | 17 | /// 18 | /// Confirms all the worksheet columns are mapped to a property, and if not, throws a StrictMappingException 19 | /// 20 | StrictMappingType? StrictMapping { get; set; } 21 | 22 | /// 23 | /// Indicates how to treat leading and trailing spaces in string values. 24 | /// 25 | TrimSpacesType TrimSpaces { get; set; } 26 | 27 | /// 28 | /// If true, uses a single, persistent connection for the lifetime of the factory. 29 | /// If false, a new connection is created for each query 30 | /// Default is false 31 | /// 32 | bool UsePersistentConnection { get; set; } 33 | 34 | /// 35 | /// Add a column to property mapping 36 | /// 37 | /// Class type to return row data as 38 | /// Class property to map to 39 | /// Worksheet column name to map from 40 | void AddMapping(Expression> property, string column); 41 | 42 | /// 43 | /// Add a column to property mapping 44 | /// 45 | /// Class property to map to 46 | /// Worksheet column name to map from 47 | void AddMapping(string propertyName, string column); 48 | 49 | /// 50 | /// Add a column to property mapping with a transformation operation 51 | /// 52 | /// Class type to return row data as 53 | /// Class property to map to 54 | /// Worksheet column name to map from 55 | /// Lambda expression that transforms a cell value in the spreadsheet to the desired property value 56 | void AddMapping(Expression> property, string column, Func transformation); 57 | 58 | /// 59 | /// Transforms a cell value in the spreadsheet to the desired property value 60 | /// 61 | /// Class type to return row data as 62 | /// Class property value to transform 63 | /// Lambda expression that transforms a cell value in the spreadsheet to the desired property value 64 | /// 65 | /// AddTransformation{Person}(p => p.IsActive, x => x == "Y"); 66 | /// AddTransformation{Person}(p => p.IsYoung, x => DateTime.Parse(x) > new DateTime(2000, 1, 1)); 67 | /// 68 | void AddTransformation(Expression> property, Func transformation); 69 | 70 | /// 71 | /// Enables Linq queries against an Excel worksheet 72 | /// 73 | /// Class type to return row data as 74 | ExcelQueryable Worksheet(); 75 | 76 | /// 77 | /// Enables Linq queries against an Excel worksheet 78 | /// 79 | /// Class type to return row data as 80 | /// Name of the worksheet 81 | ExcelQueryable Worksheet(string worksheetName); 82 | 83 | /// 84 | /// Enables Linq queries against an Excel worksheet 85 | /// 86 | /// Class type to return row data as 87 | /// Worksheet index ordered by name, not position in the workbook 88 | ExcelQueryable Worksheet(int worksheetIndex); 89 | 90 | /// 91 | /// Enables Linq queries against an Excel worksheet 92 | /// 93 | ExcelQueryable Worksheet(); 94 | 95 | /// 96 | /// Enables Linq queries against an Excel worksheet 97 | /// 98 | /// Name of the worksheet 99 | ExcelQueryable Worksheet(string worksheetName); 100 | 101 | /// 102 | /// Enables Linq queries against an Excel worksheet 103 | /// 104 | /// Worksheet index ordered by name, not position in the workbook 105 | ExcelQueryable Worksheet(int worksheetIndex); 106 | 107 | /// 108 | /// Enables Linq queries against an Excel worksheet 109 | /// 110 | /// Class type to return row data as 111 | /// Upper left cell name of the range (eg 'B2') 112 | /// Bottom right cell name of the range (eg 'D4') 113 | ExcelQueryable WorksheetRange(string startRange, string endRange); 114 | 115 | /// 116 | /// Enables Linq queries against an Excel worksheet 117 | /// 118 | /// Class type to return row data as 119 | /// Upper left cell name of the range (eg 'B2') 120 | /// Bottom right cell name of the range (eg 'D4') 121 | /// Name of the worksheet 122 | ExcelQueryable WorksheetRange(string startRange, string endRange, string worksheetName); 123 | 124 | /// 125 | /// Enables Linq queries against an Excel worksheet 126 | /// 127 | /// Class type to return row data as 128 | /// Upper left cell name of the range (eg 'B2') 129 | /// Bottom right cell name of the range (eg 'D4') 130 | /// Worksheet index ordered by name, not position in the workbook 131 | ExcelQueryable WorksheetRange(string startRange, string endRange, int worksheetIndex); 132 | 133 | /// 134 | /// Enables Linq queries against an Excel worksheet 135 | /// 136 | /// Upper left cell name of the range (eg 'B2') 137 | /// Bottom right cell name of the range (eg 'D4') 138 | ExcelQueryable WorksheetRange(string startRange, string endRange); 139 | 140 | /// 141 | /// Enables Linq queries against an Excel worksheet 142 | /// 143 | /// Upper left cell name of the range (eg 'B2') 144 | /// Bottom right cell name of the range (eg 'D4') 145 | /// Name of the worksheet 146 | ExcelQueryable WorksheetRange(string startRange, string endRange, string worksheetName); 147 | 148 | /// 149 | /// Enables Linq queries against an Excel worksheet 150 | /// 151 | /// Upper left cell name of the range (eg 'B2') 152 | /// Bottom right cell name of the range (eg 'D4') 153 | /// Worksheet index ordered by name, not position in the workbook 154 | ExcelQueryable WorksheetRange(string startRange, string endRange, int worksheetIndex); 155 | 156 | /// 157 | /// Enables Linq queries against an Excel worksheet that does not have a header row 158 | /// 159 | ExcelQueryable WorksheetNoHeader(); 160 | 161 | /// 162 | /// Enables Linq queries against an Excel worksheet that does not have a header row 163 | /// 164 | /// Name of the worksheet 165 | ExcelQueryable WorksheetNoHeader(string worksheetName); 166 | 167 | /// 168 | /// Enables Linq queries against an Excel worksheet that does not have a header row 169 | /// 170 | /// Worksheet index ordered by name, not position in the workbook 171 | ExcelQueryable WorksheetNoHeader(int worksheetIndex); 172 | 173 | /// 174 | /// Enables Linq queries against an Excel worksheet that does not have a header row 175 | /// 176 | /// Upper left cell name of the range (eg 'B2') 177 | /// Bottom right cell name of the range (eg 'D4') 178 | ExcelQueryable WorksheetRangeNoHeader(string startRange, string endRange); 179 | 180 | /// 181 | /// Enables Linq queries against an Excel worksheet that does not have a header row 182 | /// 183 | /// Upper left cell name of the range (eg 'B2') 184 | /// Bottom right cell name of the range (eg 'D4') 185 | /// Name of the worksheet 186 | ExcelQueryable WorksheetRangeNoHeader(string startRange, string endRange, string worksheetName); 187 | 188 | /// 189 | /// Enables Linq queries against an Excel worksheet that does not have a header row 190 | /// 191 | /// Upper left cell name of the range (eg 'B2') 192 | /// Bottom right cell name of the range (eg 'D4') 193 | /// Worksheet index ordered by name, not position in the workbook 194 | ExcelQueryable WorksheetRangeNoHeader(string startRange, string endRange, int worksheetIndex); 195 | 196 | /// 197 | /// Enables Linq queries against a workbook-scope named range 198 | /// 199 | /// Class type to return row data as 200 | /// Name of the workbook-scope named range 201 | ExcelQueryable NamedRange(string namedRangeName); 202 | 203 | /// 204 | /// Enables Linq queries against a named range 205 | /// 206 | /// Class type to return row data as 207 | /// Name of the worksheet 208 | /// Name of the named range 209 | ExcelQueryable NamedRange(string worksheetName, string namedRangeName); 210 | 211 | /// 212 | /// Enables Linq queries against a named range 213 | /// 214 | /// Class type to return row data as 215 | /// Worksheet index ordered by name, not position in the workbook 216 | /// Name of the named range 217 | ExcelQueryable NamedRange(int worksheetIndex, string namedRangeName); 218 | 219 | /// 220 | /// Enables Linq queries against a workbook-scope named range 221 | /// 222 | /// Name of the workbook-scope named range 223 | ExcelQueryable NamedRange(string namedRangeName); 224 | 225 | /// 226 | /// Enables Linq queries against an Excel worksheet 227 | /// 228 | /// Name of the worksheet 229 | /// Name of the named range 230 | ExcelQueryable NamedRange(string worksheetName, string namedRangeName); 231 | 232 | /// 233 | /// Enables Linq queries against an Excel worksheet 234 | /// 235 | /// Worksheet index ordered by name, not position in the workbook 236 | /// Name of the named range 237 | ExcelQueryable NamedRange(int worksheetIndex, string namedRangeName); 238 | 239 | /// 240 | /// Enables Linq queries against a workbook-scope named range that does not have a header row 241 | /// 242 | /// Name of the workbook-scope named range 243 | ExcelQueryable NamedRangeNoHeader(string namedRangeName); 244 | 245 | /// 246 | /// Enables Linq queries against a named range that does not have a header row 247 | /// 248 | /// Name of the worksheet 249 | /// Name of the named range 250 | ExcelQueryable NamedRangeNoHeader(string worksheetName, string namedRangeName); 251 | 252 | /// 253 | /// Enables Linq queries against a named range that does not have a header row 254 | /// 255 | /// Worksheet index ordered by name, not position in the workbook 256 | /// Name of the named range 257 | ExcelQueryable NamedRangeNoHeader(int worksheetIndex, string namedRangeName); 258 | 259 | /// 260 | /// Returns a list of worksheet names that the spreadsheet contains 261 | /// 262 | IEnumerable GetWorksheetNames(); 263 | 264 | /// 265 | /// Returns a list of workbook-scope named ranges that the spreadsheet contains 266 | /// 267 | IEnumerable GetNamedRanges(); 268 | 269 | /// 270 | /// Returns a list of worksheet-scope named ranges that the worksheet contains 271 | /// 272 | /// Name of the worksheet 273 | IEnumerable GetNamedRanges(string worksheetName); 274 | 275 | /// 276 | /// Returns a list of columns names that a named range contains 277 | /// 278 | /// Worksheet name to get the list of column names from 279 | /// Named Range name to get the list of column names from 280 | IEnumerable GetColumnNames(string worksheetName, string namedRangeName); 281 | 282 | /// 283 | /// Returns a list of columns names that a worksheet contains 284 | /// 285 | /// Worksheet name to get the list of column names from 286 | IEnumerable GetColumnNames(string worksheetName); 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /src/LinqToExcel/License.txt: -------------------------------------------------------------------------------- 1 | copyright (c) 2008-2010 Paul Yoder 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/LinqToExcel/LinqToExcel.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net35;net451;net46 5 | 2.0.0.2 6 | 2.0.0.0 7 | 2.0.0-PRERELEASE-2 8 | Yoder Web Solutions, LLC 9 | Paul Yoder, Stephen Workman 10 | Easily retrieve data from spreadsheets and csv files by using LINQ 11 | Copyright © Paul Yoder 2019 12 | https://github.com/paulyoder/LinqToExcel/blob/master/License.txt 13 | https://github.com/paulyoder/LinqToExcel 14 | Linq Excel spreadsheet csv 15 | en-US 16 | true 17 | true 18 | false 19 | LinqToExcel.snk 20 | https://github.com/paulyoder/LinqToExcel 21 | 22 | true 23 | 24 | 25 | true 26 | 27 | 28 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Always 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/LinqToExcel/LinqToExcel.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulyoder/LinqToExcel/8759172638ce31c6a98eaf516427069379683947/src/LinqToExcel/LinqToExcel.snk -------------------------------------------------------------------------------- /src/LinqToExcel/Logging/ILogManagerFactory.cs: -------------------------------------------------------------------------------- 1 | // copyright(c) 2016 Stephen Workman (workman.stephen@gmail.com) 2 | 3 | using System; 4 | 5 | namespace LinqToExcel.Logging { 6 | public interface ILogManagerFactory { 7 | ILogProvider GetLogger(Type name); 8 | ILogProvider GetLogger(String name); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/LinqToExcel/Logging/ILogProvider.cs: -------------------------------------------------------------------------------- 1 | // copyright(c) 2016 Stephen Workman (workman.stephen@gmail.com) 2 | 3 | using System; 4 | 5 | namespace LinqToExcel.Logging { 6 | public interface ILogProvider { 7 | bool IsDebugEnabled { get; } 8 | void Debug(Object message); 9 | void DebugFormat(String format, Object arg); 10 | void Error(Object message, Exception exception); 11 | void WarnFormat(String format, Object arg0, Object arg1, Object arg2); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/LinqToExcel/Query/ExcelQueryArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.OleDb; 4 | using System.Linq; 5 | using System.Text; 6 | using LinqToExcel.Domain; 7 | 8 | namespace LinqToExcel.Query 9 | { 10 | internal class ExcelQueryArgs 11 | { 12 | internal string FileName { get; set; } 13 | internal string WorksheetName { get; set; } 14 | internal int? WorksheetIndex { get; set; } 15 | internal Dictionary ColumnMappings { get; set; } 16 | internal Dictionary> Transformations { get; private set; } 17 | internal string NamedRangeName { get; set; } 18 | internal string StartRange { get; set; } 19 | internal string EndRange { get; set; } 20 | internal bool NoHeader { get; set; } 21 | internal StrictMappingType? StrictMapping { get; set; } 22 | internal bool ReadOnly { get; set; } 23 | internal bool UsePersistentConnection { get; set; } 24 | internal OleDbConnection PersistentConnection { get; set; } 25 | internal TrimSpacesType TrimSpaces { get; set; } 26 | internal bool Lazy { get; set; } 27 | internal OleDbServices OleDbServices { get; set; } 28 | internal int CodePageIdentifier { get; set; } 29 | internal bool SkipEmptyRows { get; set; } 30 | 31 | internal ExcelQueryArgs() 32 | : this(new ExcelQueryConstructorArgs()) 33 | { 34 | OleDbServices = OleDbServices.AllServices; 35 | } 36 | 37 | /// 38 | /// Copy constructor 39 | /// 40 | internal ExcelQueryArgs(ExcelQueryArgs orig) : this() 41 | { 42 | if (orig != null) 43 | { 44 | FileName = orig.FileName; 45 | WorksheetName = orig.WorksheetName; 46 | WorksheetIndex = orig.WorksheetIndex; 47 | ColumnMappings = orig.ColumnMappings; 48 | Transformations = orig.Transformations; 49 | NamedRangeName = orig.NamedRangeName; 50 | StartRange = orig.StartRange; 51 | EndRange = orig.EndRange; 52 | NoHeader = orig.NoHeader; 53 | StrictMapping = orig.StrictMapping; 54 | ReadOnly = orig.ReadOnly; 55 | UsePersistentConnection = orig.UsePersistentConnection; 56 | PersistentConnection = orig.PersistentConnection; 57 | TrimSpaces = orig.TrimSpaces; 58 | OleDbServices = orig.OleDbServices; 59 | CodePageIdentifier = orig.CodePageIdentifier; 60 | SkipEmptyRows = orig.SkipEmptyRows; 61 | } 62 | } 63 | 64 | internal ExcelQueryArgs(ExcelQueryConstructorArgs args) 65 | { 66 | FileName = args.FileName; 67 | ColumnMappings = args.ColumnMappings ?? new Dictionary(); 68 | Transformations = args.Transformations ?? new Dictionary>(); 69 | StrictMapping = args.StrictMapping ?? StrictMappingType.None; 70 | UsePersistentConnection = args.UsePersistentConnection; 71 | TrimSpaces = args.TrimSpaces; 72 | ReadOnly = args.ReadOnly; 73 | Lazy = args.Lazy; 74 | OleDbServices = args.OleDbServices; 75 | CodePageIdentifier = args.CodePageIdentifier; 76 | SkipEmptyRows = args.SkipEmptyRows; 77 | } 78 | 79 | public override string ToString() 80 | { 81 | var columnMappingsString = new StringBuilder(); 82 | foreach (var kvp in ColumnMappings) 83 | columnMappingsString.AppendFormat("[{0} = '{1}'] ", kvp.Key, kvp.Value); 84 | var transformationsString = string.Join(", ", Transformations.Keys.ToArray()); 85 | 86 | return string.Format("FileName: '{0}'; WorksheetName: '{1}'; WorksheetIndex: {2}; StartRange: {3}; EndRange: {4}; Named Range: {11}; NoHeader: {5}; ColumnMappings: {6}; Transformations: {7}, StrictMapping: {8}, UsePersistentConnection: {9}, TrimSpaces: {10}", 87 | FileName, WorksheetName, WorksheetIndex, StartRange, EndRange, NoHeader, columnMappingsString, transformationsString, StrictMapping, UsePersistentConnection, TrimSpaces, NamedRangeName); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/LinqToExcel/Query/ExcelQueryConstructorArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.OleDb; 4 | using System.Linq; 5 | using System.Text; 6 | using LinqToExcel.Domain; 7 | 8 | namespace LinqToExcel.Query 9 | { 10 | internal class ExcelQueryConstructorArgs 11 | { 12 | internal bool Lazy { get; set; } 13 | 14 | public ExcelQueryConstructorArgs() 15 | { 16 | OleDbServices = OleDbServices.AllServices; 17 | } 18 | 19 | internal string FileName { get; set; } 20 | internal Dictionary ColumnMappings { get; set; } 21 | internal Dictionary> Transformations { get; set; } 22 | internal StrictMappingType? StrictMapping { get; set; } 23 | internal bool UsePersistentConnection { get; set; } 24 | internal TrimSpacesType TrimSpaces { get; set; } 25 | internal bool ReadOnly { get; set; } 26 | internal OleDbServices OleDbServices { get; set; } 27 | internal int CodePageIdentifier { get; set; } 28 | internal bool SkipEmptyRows { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/LinqToExcel/Query/ExcelQueryable.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Remotion.Linq; 4 | using System.Linq.Expressions; 5 | using LinqToExcel.Attributes; 6 | using System; 7 | 8 | using LinqToExcel.Logging; 9 | 10 | using Remotion.Linq.Parsing.Structure; 11 | 12 | namespace LinqToExcel.Query 13 | { 14 | public class ExcelQueryable : QueryableBase 15 | { 16 | private static IQueryExecutor CreateExecutor(ExcelQueryArgs args, ILogManagerFactory logManagerFactory) 17 | { 18 | return new ExcelQueryExecutor(args, logManagerFactory); 19 | } 20 | 21 | // This constructor is called by users, create a new IQueryExecutor. 22 | internal ExcelQueryable(ExcelQueryArgs args, ILogManagerFactory logManagerFactory) 23 | : base( QueryParser.CreateDefault(), CreateExecutor(args, logManagerFactory) ) 24 | { 25 | foreach (var property in typeof(T).GetProperties()) 26 | { 27 | ExcelColumnAttribute att = (ExcelColumnAttribute)Attribute.GetCustomAttribute(property, typeof(ExcelColumnAttribute)); 28 | if (att != null && !args.ColumnMappings.ContainsKey(property.Name)) 29 | { 30 | args.ColumnMappings.Add(property.Name, att.ColumnName); 31 | } 32 | } 33 | } 34 | 35 | // This constructor is called indirectly by LINQ's query methods, just pass to base. 36 | public ExcelQueryable(IQueryProvider provider, Expression expression) 37 | : base(provider, expression) 38 | { } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/LinqToExcel/Query/ExcelUtilities.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Data.OleDb; 5 | using System.Data; 6 | using System.IO; 7 | 8 | using LinqToExcel.Extensions; 9 | 10 | namespace LinqToExcel.Query 11 | { 12 | public static class ExcelUtilities 13 | { 14 | internal static string GetConnectionString(ExcelQueryArgs args) 15 | { 16 | var connString = ""; 17 | var fileNameLower = args.FileName.ToLower(); 18 | 19 | if (fileNameLower.EndsWith("xlsx") || 20 | fileNameLower.EndsWith("xlsm")) 21 | { 22 | connString = string.Format( 23 | @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};OLE DB Services={1:d};Extended Properties=""Excel 12.0 Xml;HDR=YES;IMEX=1""", 24 | args.FileName, 25 | args.OleDbServices); 26 | } 27 | else if (fileNameLower.EndsWith("xlsb")) 28 | { 29 | connString = string.Format( 30 | @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};OLE DB Services={1:d};Extended Properties=""Excel 12.0;HDR=YES;IMEX=1""", 31 | args.FileName, 32 | args.OleDbServices); 33 | } 34 | else if (fileNameLower.EndsWith("csv")) 35 | { 36 | connString = string.Format( 37 | @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};OLE DB Services={1:d};Extended Properties=""text;Excel 12.0;HDR=YES;IMEX=1""", 38 | Path.GetDirectoryName(args.FileName), 39 | args.OleDbServices); 40 | } 41 | else 42 | { 43 | connString = string.Format( 44 | @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};OLE DB Services={1:d};Extended Properties=""Excel 12.0;HDR=YES;IMEX=1""", 45 | args.FileName, 46 | args.OleDbServices); 47 | } 48 | 49 | if (args.NoHeader) 50 | connString = connString.Replace("HDR=YES", "HDR=NO"); 51 | 52 | if (args.ReadOnly) 53 | connString = connString.Replace("IMEX=1", "IMEX=1;READONLY=TRUE"); 54 | 55 | if(args.CodePageIdentifier > 0) 56 | connString = connString.Replace("IMEX=1",string.Format ("IMEX=1;CharacterSet={0:000}",args.CodePageIdentifier)); 57 | 58 | return connString; 59 | } 60 | 61 | internal static IEnumerable GetWorksheetNames(string fileName) 62 | { 63 | return GetWorksheetNames(fileName, new ExcelQueryArgs()); 64 | } 65 | 66 | internal static IEnumerable GetWorksheetNames(string fileName, ExcelQueryArgs origArgs) 67 | { 68 | var args = new ExcelQueryArgs(origArgs); 69 | args.FileName = fileName; 70 | args.ReadOnly = true; 71 | return GetWorksheetNames(args); 72 | } 73 | 74 | internal static OleDbConnection GetConnection(ExcelQueryArgs args) 75 | { 76 | if (args.UsePersistentConnection) 77 | { 78 | if (args.PersistentConnection == null) 79 | args.PersistentConnection = new OleDbConnection(GetConnectionString(args)); 80 | 81 | return args.PersistentConnection; 82 | } 83 | 84 | return new OleDbConnection(GetConnectionString(args)); 85 | } 86 | 87 | internal static IEnumerable GetWorksheetNames(ExcelQueryArgs args) 88 | { 89 | var worksheetNames = new List(); 90 | 91 | var conn = GetConnection(args); 92 | try 93 | { 94 | if (conn.State == ConnectionState.Closed) 95 | conn.Open(); 96 | 97 | var excelTables = conn.GetOleDbSchemaTable( 98 | OleDbSchemaGuid.Tables, 99 | new Object[] { null, null, null, "TABLE" }); 100 | 101 | worksheetNames.AddRange( 102 | from DataRow row in excelTables.Rows 103 | where IsTable(row) 104 | let tableName = row["TABLE_NAME"].ToString() 105 | .RegexReplace("(^'|'$)", "") 106 | .RegexReplace(@"\$$", "") 107 | .Replace("''", "'") 108 | where IsNotBuiltinTable(tableName) 109 | select tableName); 110 | 111 | excelTables.Dispose(); 112 | } 113 | finally 114 | { 115 | if (!args.UsePersistentConnection) 116 | conn.Dispose(); 117 | } 118 | 119 | return worksheetNames; 120 | } 121 | 122 | internal static bool IsTable(DataRow row) 123 | { 124 | var tableName = row["TABLE_NAME"].ToString(); 125 | 126 | return tableName.EndsWith("$") || (tableName.StartsWith("'") && tableName.EndsWith("$'")); 127 | } 128 | 129 | internal static bool IsNamedRange(DataRow row) 130 | { 131 | var tableName = row["TABLE_NAME"].ToString(); 132 | 133 | return (tableName.Contains("$") && !tableName.EndsWith("$") && !tableName.EndsWith("$'")) || !tableName.Contains("$"); 134 | } 135 | 136 | internal static bool IsWorkseetScopedNamedRange(DataRow row) 137 | { 138 | var tableName = row["TABLE_NAME"].ToString(); 139 | 140 | return IsNamedRange(row) && tableName.Contains("$"); 141 | } 142 | 143 | internal static bool IsNotBuiltinTable(string tableName) 144 | { 145 | return !tableName.Contains("FilterDatabase") && !tableName.Contains("Print_Area"); 146 | } 147 | 148 | internal static IEnumerable GetColumnNames(string worksheetName, string fileName) 149 | { 150 | return GetColumnNames(worksheetName, fileName, new ExcelQueryArgs()); 151 | } 152 | 153 | internal static IEnumerable GetColumnNames(string worksheetName, string fileName, ExcelQueryArgs origArgs) 154 | { 155 | var args = new ExcelQueryArgs(origArgs); 156 | args.WorksheetName = worksheetName; 157 | args.FileName = fileName; 158 | return GetColumnNames(args); 159 | } 160 | 161 | internal static IEnumerable GetColumnNames(string worksheetName, string namedRange, string fileName) 162 | { 163 | return GetColumnNames(worksheetName, namedRange, fileName, new ExcelQueryArgs()); 164 | } 165 | 166 | internal static IEnumerable GetColumnNames(string worksheetName, string namedRange, string fileName, ExcelQueryArgs origArgs) 167 | { 168 | var args = new ExcelQueryArgs(origArgs); 169 | args.WorksheetName = worksheetName; 170 | args.NamedRangeName = namedRange; 171 | args.FileName = fileName; 172 | return GetColumnNames(args); 173 | } 174 | 175 | internal static IEnumerable GetColumnNames(ExcelQueryArgs args) 176 | { 177 | var columns = new List(); 178 | var conn = GetConnection(args); 179 | try 180 | { 181 | if (conn.State == ConnectionState.Closed) 182 | conn.Open(); 183 | 184 | using (var command = conn.CreateCommand()) 185 | { 186 | command.CommandText = string.Format("SELECT TOP 1 * FROM [{0}{1}]", string.Format("{0}{1}", args.WorksheetName, "$"), args.NamedRangeName); 187 | var data = command.ExecuteReader(); 188 | columns.AddRange(GetColumnNames(data)); 189 | } 190 | } 191 | finally 192 | { 193 | if (!args.UsePersistentConnection) 194 | conn.Dispose(); 195 | } 196 | 197 | return columns; 198 | } 199 | 200 | internal static IEnumerable GetColumnNames(IDataReader data) 201 | { 202 | var columns = new List(); 203 | var sheetSchema = data.GetSchemaTable(); 204 | foreach (DataRow row in sheetSchema.Rows) 205 | columns.Add(row["ColumnName"].ToString()); 206 | 207 | return columns; 208 | } 209 | 210 | internal static IEnumerable GetNamedRanges(string fileName, string worksheetName) 211 | { 212 | return GetNamedRanges(fileName, worksheetName, new ExcelQueryArgs()); 213 | } 214 | 215 | internal static IEnumerable GetNamedRanges(string fileName) 216 | { 217 | return GetNamedRanges(fileName, new ExcelQueryArgs()); 218 | } 219 | 220 | internal static IEnumerable GetNamedRanges(string fileName, ExcelQueryArgs origArgs) 221 | { 222 | var args = new ExcelQueryArgs(origArgs); 223 | args.FileName = fileName; 224 | args.ReadOnly = true; 225 | return GetNamedRanges(args); 226 | } 227 | 228 | internal static IEnumerable GetNamedRanges(string fileName, string worksheetName, ExcelQueryArgs origArgs) 229 | { 230 | var args = new ExcelQueryArgs(origArgs); 231 | args.FileName = fileName; 232 | args.WorksheetName = worksheetName; 233 | args.ReadOnly = true; 234 | return GetNamedRanges(args); 235 | } 236 | 237 | internal static IEnumerable GetNamedRanges(ExcelQueryArgs args) 238 | { 239 | var namedRanges = new List(); 240 | 241 | var conn = GetConnection(args); 242 | try 243 | { 244 | if (conn.State == ConnectionState.Closed) 245 | conn.Open(); 246 | 247 | var excelTables = conn.GetOleDbSchemaTable( 248 | OleDbSchemaGuid.Tables, 249 | new Object[] { null, null, null, "TABLE" }); 250 | 251 | namedRanges.AddRange( 252 | from DataRow row in excelTables.Rows 253 | where IsNamedRange(row) 254 | && (!string.IsNullOrEmpty(args.WorksheetName) ? row["TABLE_NAME"].ToString().StartsWith(args.WorksheetName) : !IsWorkseetScopedNamedRange(row)) 255 | let tableName = row["TABLE_NAME"].ToString() 256 | .Replace("''", "'") 257 | where IsNotBuiltinTable(tableName) 258 | select tableName.Split('$').Last()); 259 | 260 | excelTables.Dispose(); 261 | } 262 | finally 263 | { 264 | if (!args.UsePersistentConnection) 265 | conn.Dispose(); 266 | } 267 | 268 | return namedRanges; 269 | } 270 | 271 | public static string ColumnIndexToExcelColumnName(int index) 272 | { 273 | if (index < 1) throw new ArgumentException("Index should be a positive integer"); 274 | var quotient = (--index) / 26; 275 | 276 | if (quotient > 0) 277 | { 278 | return ColumnIndexToExcelColumnName(quotient) + (char)((index % 26) + 65); 279 | } 280 | else 281 | 282 | { 283 | return ((char)((index % 26) + 65)).ToString(); 284 | } 285 | } 286 | 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /src/LinqToExcel/Query/OleDbServices.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToExcel.Query 2 | { 3 | /// 4 | /// Describes which services the OLE DB connection will use. 5 | /// 6 | /// 7 | /// This allows you to change the OLE DB Services value in the connection string, which among other 8 | /// features, will allow you to opt out of implicit transactions (e.g. those created using 9 | /// TransactionScope). 10 | /// 11 | /// 12 | /// Services enabled | Value in connection string 13 | /// ============================================================================ 14 | /// All services (the default) | "OLE DB Services = -1;" 15 | /// All services except pooling | "OLE DB Services = -2;" 16 | /// All services except pooling and auto-enlistment | "OLE DB Services = -4;" 17 | /// All services except client cursor | "OLE DB Services = -5;" 18 | /// All services except client cursor and pooling | "OLE DB Services = -6;" 19 | /// No services | "OLE DB Services = 0;" 20 | /// 21 | /// 22 | /// See https://msdn.microsoft.com/en-us/library/ms810829.aspx for more information. 23 | /// 24 | public enum OleDbServices 25 | { 26 | /// 27 | /// This is the default value for OLE DB Services in connection strings where it 28 | /// is not explicitly specified. Sets OLE DB Services to -1 in the connection string. 29 | /// 30 | AllServices = -1, 31 | 32 | /// 33 | /// Sets OLE DB Services to -2 in the connection string. 34 | /// 35 | AllServicesExceptPooling = -2, 36 | 37 | /// 38 | /// This will disable auto-enlistment in TransactionScope. 39 | /// Sets OLE DB Services to -4 in the connection string. 40 | /// 41 | AllServicesExceptPoolingAndAutoEnlistment = -4, 42 | 43 | /// 44 | /// Sets OLE DB Services to -5 in the connection string. 45 | /// 46 | AllServicesExceptClientCursor = -5, 47 | 48 | /// 49 | /// Sets OLE DB Services to -6 in the connection string. 50 | /// 51 | AllServicesExceptClientCursorAndPooling = -6, 52 | 53 | /// 54 | /// Sets OLE DB Services to 0 in the connection string. 55 | /// 56 | NoServices = 0, 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/LinqToExcel/Query/ProjectorBuildingExpressionTreeVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Linq.Expressions; 4 | using Remotion.Linq.Clauses.Expressions; 5 | using Remotion.Linq.Parsing; 6 | 7 | namespace LinqToExcel.Query 8 | { 9 | public class ProjectorBuildingExpressionTreeVisitor : RelinqExpressionVisitor 10 | { 11 | // This is the generic ResultObjectMapping.GetObject() method we'll use to obtain a queried object for an IQuerySource. 12 | private static readonly MethodInfo s_getObjectGenericMethodDefinition = typeof(ResultObjectMapping).GetMethod("GetObject"); 13 | 14 | // Call this method to get the projector. T is the type of the result (after the projection). 15 | public static Func BuildProjector(Expression selectExpression) 16 | { 17 | // This is the parameter of the delegat we're building. It's the ResultObjectMapping, which holds all the input data needed for the projection. 18 | var resultItemParameter = Expression.Parameter(typeof(ResultObjectMapping), "resultItem"); 19 | 20 | // The visitor gives us the projector's body. It simply replaces all QuerySourceReferenceExpressions with calls to ResultObjectMapping.GetObject(). 21 | var visitor = new ProjectorBuildingExpressionTreeVisitor(resultItemParameter); 22 | var body = visitor.Visit(selectExpression); 23 | 24 | // Construct a LambdaExpression from parameter and body and compile it into a delegate. 25 | var projector = Expression.Lambda>(body, resultItemParameter); 26 | return projector.Compile(); 27 | } 28 | 29 | private readonly ParameterExpression _resultItemParameter; 30 | 31 | private ProjectorBuildingExpressionTreeVisitor(ParameterExpression resultItemParameter) 32 | { 33 | _resultItemParameter = resultItemParameter; 34 | } 35 | 36 | protected override Expression VisitQuerySourceReference(QuerySourceReferenceExpression expression) 37 | { 38 | // Substitute generic parameter "T" of ResultObjectMapping.GetObject() with type of query source item, then return a call to that method 39 | // with the query source referenced by the expression. 40 | var getObjectMethod = s_getObjectGenericMethodDefinition.MakeGenericMethod(expression.Type); 41 | return Expression.Call(_resultItemParameter, getObjectMethod, Expression.Constant(expression.ReferencedQuerySource)); 42 | } 43 | 44 | protected override Expression VisitSubQuery(SubQueryExpression expression) 45 | { 46 | throw new NotSupportedException("This provider does not support subqueries in the select projection."); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/LinqToExcel/Query/ResultObjectMapping.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Remotion.Linq.Clauses; 3 | 4 | namespace LinqToExcel.Query 5 | { 6 | public class ResultObjectMapping 7 | { 8 | private readonly Dictionary _resultObjectsBySource = new Dictionary(); 9 | 10 | public ResultObjectMapping(IQuerySource querySource, object resultObject) 11 | { 12 | Add(querySource, resultObject); 13 | } 14 | 15 | public void Add(IQuerySource querySource, object resultObject) 16 | { 17 | _resultObjectsBySource.Add(querySource, resultObject); 18 | } 19 | 20 | public T GetObject(IQuerySource source) 21 | { 22 | return (T)_resultObjectsBySource[source]; 23 | } 24 | 25 | public IEnumerator> GetEnumerator() 26 | { 27 | return _resultObjectsBySource.GetEnumerator(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/LinqToExcel/Query/SqlGeneratorQueryModelVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using Remotion.Linq; 6 | using Remotion.Linq.Clauses; 7 | using Remotion.Linq.Clauses.ResultOperators; 8 | using System.Linq.Expressions; 9 | using Remotion.Linq.Collections; 10 | 11 | namespace LinqToExcel.Query 12 | { 13 | internal class SqlGeneratorQueryModelVisitor : QueryModelVisitorBase 14 | { 15 | public SqlParts SqlStatement { get; protected set; } 16 | private readonly ExcelQueryArgs _args; 17 | 18 | internal SqlGeneratorQueryModelVisitor(ExcelQueryArgs args) 19 | { 20 | _args = args; 21 | SqlStatement = new SqlParts(); 22 | SqlStatement.Table = (String.IsNullOrEmpty(_args.StartRange)) ? 23 | !String.IsNullOrEmpty(_args.NamedRangeName) && String.IsNullOrEmpty(_args.WorksheetName) ? 24 | string.Format("[{0}]", 25 | _args.NamedRangeName) : 26 | string.Format("[{0}${1}]", 27 | _args.WorksheetName, _args.NamedRangeName) : 28 | string.Format("[{0}${1}:{2}]", 29 | _args.WorksheetName, _args.StartRange, _args.EndRange); 30 | 31 | if (!string.IsNullOrEmpty(_args.WorksheetName) && _args.WorksheetName.ToLower().EndsWith(".csv")) 32 | SqlStatement.Table = SqlStatement.Table.Replace("$]", "]"); 33 | } 34 | 35 | public override void VisitGroupJoinClause(GroupJoinClause groupJoinClause, QueryModel queryModel, int index) 36 | { 37 | throw new NotSupportedException("LinqToExcel does not provide support for group join"); 38 | } 39 | 40 | public override void VisitJoinClause(JoinClause joinClause, QueryModel queryModel, int index) 41 | { 42 | throw new NotSupportedException("LinqToExcel does not provide support for the Join() method"); 43 | } 44 | 45 | public override void VisitQueryModel(QueryModel queryModel) 46 | { 47 | queryModel.SelectClause.Accept(this, queryModel); 48 | queryModel.MainFromClause.Accept(this, queryModel); 49 | VisitBodyClauses(queryModel.BodyClauses, queryModel); 50 | VisitResultOperators(queryModel.ResultOperators, queryModel); 51 | 52 | if (queryModel.MainFromClause.ItemType.Name == "IGrouping`2") 53 | throw new NotSupportedException("LinqToExcel does not provide support for the Group() method"); 54 | } 55 | 56 | public override void VisitWhereClause(WhereClause whereClause, QueryModel queryModel, int index) 57 | { 58 | var where = new WhereClauseExpressionTreeVisitor(queryModel.MainFromClause.ItemType, _args.ColumnMappings); 59 | where.Visit(whereClause.Predicate); 60 | SqlStatement.Where = where.WhereClause; 61 | SqlStatement.Parameters = where.Params; 62 | SqlStatement.ColumnNamesUsed.AddRange(where.ColumnNamesUsed); 63 | 64 | base.VisitWhereClause(whereClause, queryModel, index); 65 | } 66 | 67 | public override void VisitResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, int index) 68 | { 69 | //Affects SQL result operators 70 | if (resultOperator is TakeResultOperator) 71 | { 72 | var take = resultOperator as TakeResultOperator; 73 | SqlStatement.Aggregate = string.Format("TOP {0} *", take.Count); 74 | } 75 | else if (resultOperator is AverageResultOperator) 76 | UpdateAggregate(queryModel, "AVG"); 77 | else if (resultOperator is CountResultOperator) 78 | SqlStatement.Aggregate = "COUNT(*)"; 79 | else if (resultOperator is LongCountResultOperator) 80 | SqlStatement.Aggregate = "COUNT(*)"; 81 | else if (resultOperator is FirstResultOperator) 82 | SqlStatement.Aggregate = "TOP 1 *"; 83 | else if (resultOperator is MaxResultOperator) 84 | UpdateAggregate(queryModel, "MAX"); 85 | else if (resultOperator is MinResultOperator) 86 | UpdateAggregate(queryModel, "MIN"); 87 | else if (resultOperator is SumResultOperator) 88 | UpdateAggregate(queryModel, "SUM"); 89 | else if (resultOperator is DistinctResultOperator) 90 | ProcessDistinctAggregate(queryModel); 91 | 92 | //Not supported result operators 93 | else if (resultOperator is ContainsResultOperator) 94 | throw new NotSupportedException("LinqToExcel does not provide support for the Contains() method"); 95 | else if (resultOperator is DefaultIfEmptyResultOperator) 96 | throw new NotSupportedException("LinqToExcel does not provide support for the DefaultIfEmpty() method"); 97 | else if (resultOperator is ExceptResultOperator) 98 | throw new NotSupportedException("LinqToExcel does not provide support for the Except() method"); 99 | else if (resultOperator is GroupResultOperator) 100 | throw new NotSupportedException("LinqToExcel does not provide support for the Group() method"); 101 | else if (resultOperator is IntersectResultOperator) 102 | throw new NotSupportedException("LinqToExcel does not provide support for the Intersect() method"); 103 | else if (resultOperator is OfTypeResultOperator) 104 | throw new NotSupportedException("LinqToExcel does not provide support for the OfType() method"); 105 | else if (resultOperator is SingleResultOperator) 106 | throw new NotSupportedException("LinqToExcel does not provide support for the Single() method. Use the First() method instead"); 107 | else if (resultOperator is UnionResultOperator) 108 | throw new NotSupportedException("LinqToExcel does not provide support for the Union() method"); 109 | 110 | base.VisitResultOperator(resultOperator, queryModel, index); 111 | } 112 | 113 | protected override void VisitBodyClauses(ObservableCollection bodyClauses, QueryModel queryModel) 114 | { 115 | var orderClause = bodyClauses 116 | .FirstOrDefault(x => x.GetType() == typeof(OrderByClause)) 117 | as OrderByClause; 118 | 119 | if (orderClause != null) 120 | { 121 | var columnName = ""; 122 | var exp = orderClause.Orderings.First().Expression; 123 | if (exp is MemberExpression) 124 | { 125 | var mExp = exp as MemberExpression; 126 | columnName = (_args.ColumnMappings.ContainsKey(mExp.Member.Name)) ? 127 | _args.ColumnMappings[mExp.Member.Name] : 128 | mExp.Member.Name; 129 | } 130 | else if (exp is MethodCallExpression) 131 | { 132 | //row["ColumnName"] is being used in order by statement 133 | columnName = ((MethodCallExpression)exp).Arguments.First() 134 | .ToString().Replace("\"", ""); 135 | } 136 | 137 | SqlStatement.OrderBy = columnName; 138 | SqlStatement.ColumnNamesUsed.Add(columnName); 139 | var orderDirection = orderClause.Orderings.First().OrderingDirection; 140 | SqlStatement.OrderByAsc = (orderDirection == OrderingDirection.Asc) ? true : false; 141 | } 142 | base.VisitBodyClauses(bodyClauses, queryModel); 143 | } 144 | 145 | protected void UpdateAggregate(QueryModel queryModel, string aggregateName) 146 | { 147 | var columnName = GetResultColumnName(queryModel); 148 | SqlStatement.Aggregate = string.Format("{0}({1})", 149 | aggregateName, 150 | columnName); 151 | SqlStatement.ColumnNamesUsed.Add(columnName); 152 | } 153 | 154 | protected void ProcessDistinctAggregate(QueryModel queryModel) 155 | { 156 | if (queryModel.SelectClause.Selector is MemberExpression) 157 | UpdateAggregate(queryModel, "DISTINCT"); 158 | else 159 | throw new NotSupportedException("LinqToExcel only provides support for the Distinct() method when it's mapped to a class and a single property is selected. [e.g. (from row in excel.Worksheet() select row.FirstName).Distinct()]"); 160 | } 161 | 162 | private string GetResultColumnName(QueryModel queryModel) 163 | { 164 | MemberExpression mExp; 165 | 166 | if (queryModel.SelectClause.Selector is UnaryExpression uExp) { 167 | mExp = (MemberExpression) uExp.Operand; 168 | } else { 169 | mExp = (MemberExpression) queryModel.SelectClause.Selector; 170 | } 171 | 172 | return (_args.ColumnMappings != null && _args.ColumnMappings.ContainsKey(mExp.Member.Name)) ? 173 | _args.ColumnMappings[mExp.Member.Name] : 174 | mExp.Member.Name; 175 | } 176 | 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/LinqToExcel/Query/SqlParts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Data.OleDb; 5 | 6 | namespace LinqToExcel.Query 7 | { 8 | public class SqlParts 9 | { 10 | public string Aggregate { get; set; } 11 | public string Table { get; set; } 12 | public string Where { get; set; } 13 | public IEnumerable Parameters { get; set; } 14 | public string OrderBy { get; set; } 15 | public bool OrderByAsc { get; set; } 16 | public List ColumnNamesUsed { get; set; } 17 | 18 | public SqlParts() 19 | { 20 | Aggregate = "*"; 21 | Parameters = new List(); 22 | OrderByAsc = true; 23 | ColumnNamesUsed = new List(); 24 | } 25 | 26 | public static implicit operator string(SqlParts sql) 27 | { 28 | return sql.ToString(); 29 | } 30 | 31 | public override string ToString() 32 | { 33 | var sql = new StringBuilder(); 34 | sql.AppendFormat("SELECT {0} FROM {1}", 35 | Aggregate, 36 | Table); 37 | if (!String.IsNullOrEmpty(Where)) 38 | sql.AppendFormat(" WHERE {0}", Where); 39 | if (!String.IsNullOrEmpty(OrderBy)) 40 | { 41 | var asc = (OrderByAsc) ? "ASC" : "DESC"; 42 | sql.AppendFormat(" ORDER BY [{0}] {1}", 43 | OrderBy, 44 | asc); 45 | } 46 | return sql.ToString(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/LinqToExcel/Query/StrictMappingType.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToExcel.Query 2 | { 3 | /// 4 | /// Class property and worksheet mapping enforcemment type. 5 | /// 6 | public enum StrictMappingType 7 | { 8 | /// 9 | /// All worksheet columns must map to a class property; all class properties must map to a worksheet columm. 10 | /// 11 | Both, 12 | 13 | /// 14 | /// All class properties must map to a worksheet column; other worksheet columns are ignored. 15 | /// 16 | ClassStrict, 17 | 18 | /// 19 | /// No checks are made to enforce worksheet column or class property mappings. 20 | /// 21 | None, 22 | 23 | /// 24 | /// All worksheet columns must map to a class property; other class properties are ignored. 25 | /// 26 | WorksheetStrict 27 | } 28 | } -------------------------------------------------------------------------------- /src/LinqToExcel/Query/TrimSpacesType.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToExcel.Query 2 | { 3 | /// 4 | /// Indicates how to treat leading and trailing spaces in string values. 5 | /// 6 | public enum TrimSpacesType 7 | { 8 | /// 9 | /// Do not perform any trimming. 10 | /// 11 | None, 12 | 13 | /// 14 | /// Trim leading spaces from strings. 15 | /// 16 | Start, 17 | 18 | /// 19 | /// Trim trailing spaces from strings. 20 | /// 21 | End, 22 | 23 | /// 24 | /// Trim leading and trailing spaces from strings. 25 | /// 26 | Both 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/LinqToExcel/Query/WhereClauseExpressionTreeVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Remotion.Linq.Parsing; 6 | using System.Data.OleDb; 7 | using System.Linq.Expressions; 8 | using LinqToExcel.Extensions; 9 | using Remotion.Linq.Clauses.Expressions; 10 | 11 | namespace LinqToExcel.Query 12 | { 13 | public class WhereClauseExpressionTreeVisitor : ThrowingExpressionVisitor 14 | { 15 | private readonly StringBuilder _whereClause = new StringBuilder(); 16 | private readonly List _params = new List(); 17 | private readonly Dictionary _columnMapping; 18 | private readonly List _columnNamesUsed = new List(); 19 | private readonly Type _sheetType; 20 | private readonly List _validStringMethods; 21 | 22 | public WhereClauseExpressionTreeVisitor(Type sheetType, Dictionary columnMapping) 23 | { 24 | _sheetType = sheetType; 25 | _columnMapping = columnMapping; 26 | _validStringMethods = new List() { 27 | "Equals", 28 | "Contains", 29 | "StartsWith", 30 | "IsNullOrEmpty", 31 | "EndsWith" }; 32 | } 33 | 34 | public string WhereClause 35 | { 36 | get { return _whereClause.ToString(); } 37 | } 38 | 39 | public IEnumerable Params 40 | { 41 | get { return _params; } 42 | } 43 | 44 | public IEnumerable ColumnNamesUsed 45 | { 46 | get { return _columnNamesUsed.Select(x => x.Replace("[", "").Replace("]", "")); } 47 | } 48 | 49 | protected override Exception CreateUnhandledItemException(T unhandledItem, string visitMethod) 50 | { 51 | throw new NotImplementedException(visitMethod + " method is not implemented"); 52 | } 53 | 54 | protected override Expression VisitBinary(BinaryExpression bExp) 55 | { 56 | _whereClause.Append("("); 57 | 58 | // Patch for vb.net expression that are always considered a MethodCallExpression even if they are not. 59 | // see http://www.re-motion.org/blogs/mix/archive/2009/10/16/vb.net-specific-text-comparison-in-linq-queries.aspx 60 | bExp = ConvertVbStringCompare(bExp); 61 | 62 | //We always want the MemberAccess (ColumnName) to be on the left side of the statement 63 | var bLeft = bExp.Left; 64 | var bRight = bExp.Right; 65 | if ((bExp.Right.NodeType == ExpressionType.MemberAccess) && 66 | (((MemberExpression)bExp.Right).Member.DeclaringType == _sheetType)) 67 | { 68 | bLeft = bExp.Right; 69 | bRight = bExp.Left; 70 | } 71 | 72 | Visit(bLeft); 73 | switch (bExp.NodeType) 74 | { 75 | case ExpressionType.AndAlso: 76 | _whereClause.Append(" AND "); 77 | break; 78 | case ExpressionType.Equal: 79 | if (bRight.IsNullValue()) 80 | _whereClause.Append(" IS NULL"); 81 | else 82 | _whereClause.Append(" = "); 83 | break; 84 | case ExpressionType.GreaterThan: 85 | _whereClause.Append(" > "); 86 | break; 87 | case ExpressionType.GreaterThanOrEqual: 88 | _whereClause.Append(" >= "); 89 | break; 90 | case ExpressionType.LessThan: 91 | _whereClause.Append(" < "); 92 | break; 93 | case ExpressionType.LessThanOrEqual: 94 | _whereClause.Append(" <= "); 95 | break; 96 | case ExpressionType.NotEqual: 97 | if (bRight.IsNullValue()) 98 | _whereClause.Append(" IS NOT NULL"); 99 | else 100 | _whereClause.Append(" <> "); 101 | break; 102 | case ExpressionType.OrElse: 103 | _whereClause.Append(" OR "); 104 | break; 105 | default: 106 | throw new NotSupportedException(string.Format("{0} statement is not supported", bExp.NodeType.ToString())); 107 | } 108 | if (!bRight.IsNullValue()) 109 | Visit(bRight); 110 | _whereClause.Append(")"); 111 | return bExp; 112 | } 113 | 114 | protected BinaryExpression ConvertVbStringCompare(BinaryExpression exp) 115 | { 116 | if (exp.Left.NodeType == ExpressionType.Call) 117 | { 118 | var compareStringCall = (MethodCallExpression)exp.Left; 119 | if (compareStringCall.Method.DeclaringType.FullName == "Microsoft.VisualBasic.CompilerServices.Operators" && compareStringCall.Method.Name == "CompareString") 120 | { 121 | var arg1 = compareStringCall.Arguments[0]; 122 | var arg2 = compareStringCall.Arguments[1]; 123 | 124 | switch (exp.NodeType) 125 | { 126 | case ExpressionType.LessThan: 127 | return Expression.LessThan(arg1, arg2); 128 | case ExpressionType.LessThanOrEqual: 129 | return Expression.LessThanOrEqual(arg1, arg2); 130 | case ExpressionType.GreaterThan: 131 | return Expression.GreaterThan(arg1, arg2); 132 | case ExpressionType.GreaterThanOrEqual: 133 | return Expression.GreaterThanOrEqual(arg1, arg2); 134 | case ExpressionType.NotEqual: 135 | return Expression.NotEqual(arg1, arg2); 136 | default: 137 | return Expression.Equal(arg1, arg2); 138 | } 139 | } 140 | } 141 | return exp; 142 | } 143 | 144 | protected override Expression VisitMember(MemberExpression mExp) 145 | { 146 | //Set the column name to the property mapping if there is one, 147 | //else use the property name for the column name 148 | var columnName = (_columnMapping.ContainsKey(mExp.Member.Name)) ? 149 | _columnMapping[mExp.Member.Name] : 150 | mExp.Member.Name; 151 | _whereClause.AppendFormat("[{0}]", columnName); 152 | _columnNamesUsed.Add(columnName); 153 | return mExp; 154 | } 155 | 156 | protected override Expression VisitConstant(ConstantExpression cExp) 157 | { 158 | _params.Add(new OleDbParameter("?", cExp.Value)); 159 | _whereClause.Append("?"); 160 | return cExp; 161 | } 162 | 163 | /// 164 | /// This method is visited when the LinqToExcel.Row type is used in the query 165 | /// 166 | protected override Expression VisitUnary(UnaryExpression uExp) 167 | { 168 | if (IsNotStringIsNullOrEmpty(uExp)) 169 | AddStringIsNullOrEmptyToWhereClause((MethodCallExpression)uExp.Operand, true); 170 | else 171 | _whereClause.Append(GetColumnName(uExp.Operand)); 172 | return uExp; 173 | } 174 | 175 | private bool IsNotStringIsNullOrEmpty(UnaryExpression uExp) 176 | { 177 | return uExp.NodeType == ExpressionType.Not && ((MethodCallExpression)uExp.Operand).Method.Name == "IsNullOrEmpty"; 178 | } 179 | 180 | /// 181 | /// Only As<>() method calls on the LinqToExcel.Row type are support 182 | /// 183 | protected override Expression VisitMethodCall(MethodCallExpression mExp) 184 | { 185 | if (_validStringMethods.Contains(mExp.Method.Name)) 186 | ProcessStringMethod(mExp); 187 | else 188 | { 189 | var columnName = GetColumnName(mExp); 190 | _whereClause.Append(columnName); 191 | _columnNamesUsed.Add(columnName); 192 | } 193 | return mExp; 194 | } 195 | 196 | private void ProcessStringMethod(MethodCallExpression mExp) 197 | { 198 | switch (mExp.Method.Name) 199 | { 200 | case "Contains": 201 | AddStringMethodToWhereClause(mExp, "LIKE", "%{0}%"); 202 | break; 203 | case "StartsWith": 204 | AddStringMethodToWhereClause(mExp, "LIKE", "{0}%"); 205 | break; 206 | case "EndsWith": 207 | AddStringMethodToWhereClause(mExp, "LIKE", "%{0}"); 208 | break; 209 | case "Equals": 210 | AddStringMethodToWhereClause(mExp, "=", "{0}"); 211 | break; 212 | case "IsNullOrEmpty": 213 | AddStringIsNullOrEmptyToWhereClause(mExp); 214 | break; 215 | } 216 | } 217 | 218 | private void AddStringMethodToWhereClause(MethodCallExpression mExp, string operatorString, string argumentFormat) 219 | { 220 | _whereClause.Append("("); 221 | Visit(mExp.Object); 222 | _whereClause.AppendFormat(" {0} ?)", operatorString); 223 | 224 | var value = mExp.Arguments.First().ToString().Replace("\"", ""); 225 | var parameter = string.Format(argumentFormat, value); 226 | _params.Add(new OleDbParameter("?", parameter)); 227 | } 228 | 229 | private void AddStringIsNullOrEmptyToWhereClause(MethodCallExpression mExp) 230 | { 231 | AddStringIsNullOrEmptyToWhereClause(mExp, false); 232 | } 233 | 234 | private void AddStringIsNullOrEmptyToWhereClause(MethodCallExpression mExp, bool notEqual) 235 | { 236 | var columnName = GetColumnName((MemberExpression)mExp.Arguments[0]); 237 | if (notEqual) 238 | _whereClause.AppendFormat("(({0} <> '') OR ({0} IS NOT NULL))", columnName); 239 | else 240 | _whereClause.AppendFormat("(({0} = '') OR ({0} IS NULL))", columnName); 241 | } 242 | 243 | /// 244 | /// Retrieves the column name from a member expression or method call expression 245 | /// 246 | /// Expression 247 | private string GetColumnName(Expression exp) 248 | { 249 | if (exp is MemberExpression) 250 | return GetColumnName((MemberExpression)exp); 251 | else 252 | return GetColumnName((MethodCallExpression)exp); 253 | } 254 | 255 | /// 256 | /// Retrieves the column name from a member expression 257 | /// 258 | /// Member Expression 259 | private string GetColumnName(MemberExpression mExp) 260 | { 261 | return "[" + mExp.Member.Name + "]"; 262 | } 263 | 264 | /// 265 | /// Retrieves the column name from a method call expression 266 | /// 267 | /// Method Call Expression 268 | private string GetColumnName(MethodCallExpression mExp) 269 | { 270 | MethodCallExpression method = mExp; 271 | if (mExp.Object is MethodCallExpression) 272 | method = (MethodCallExpression)mExp.Object; 273 | 274 | var arg = method.Arguments.First(); 275 | if (arg.Type == typeof(int)) 276 | { 277 | if (_sheetType == typeof(RowNoHeader)) 278 | return string.Format("F{0}", Int32.Parse(arg.ToString()) + 1); 279 | else 280 | throw new ArgumentException("Can only use column indexes in WHERE clause when using WorksheetNoHeader"); 281 | } 282 | 283 | var columnName = arg.ToString().ToCharArray(); 284 | columnName[0] = "[".ToCharArray().First(); 285 | columnName[columnName.Length - 1] = "]".ToCharArray().First(); 286 | return new string(columnName); 287 | } 288 | } 289 | } 290 | --------------------------------------------------------------------------------