diff --git a/Database/MySql/tracker.sql b/Database/MySql/tracker.sql new file mode 100644 index 0000000..e49c4a0 --- /dev/null +++ b/Database/MySql/tracker.sql @@ -0,0 +1,473 @@ +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `tracker` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `audit` +-- + +DROP TABLE IF EXISTS `audit`; +CREATE TABLE `audit` ( + `Id` int(11) NOT NULL, + `Date` datetime NOT NULL, + `UserId` int(11) DEFAULT NULL, + `TaskId` int(11) DEFAULT NULL, + `Content` longtext NOT NULL, + `Username` varchar(50) NOT NULL, + `CreatedDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `RowVersion` binary(8) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `item` +-- + +DROP TABLE IF EXISTS `item`; +CREATE TABLE `item` ( + `ItemId` varchar(10) NOT NULL, + `ProductId` varchar(10) NOT NULL, + `ListPrice` decimal(10,2) DEFAULT NULL, + `UnitCost` decimal(10,2) DEFAULT NULL, + `Supplier` int(11) DEFAULT NULL, + `Status` varchar(2) DEFAULT NULL, + `Attr1` varchar(80) DEFAULT NULL, + `Attr2` varchar(80) DEFAULT NULL, + `Attr3` varchar(80) DEFAULT NULL, + `Attr4` varchar(80) DEFAULT NULL, + `Attr5` varchar(80) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `item` +-- + +INSERT INTO `item` (`ItemId`, `ProductId`, `ListPrice`, `UnitCost`, `Supplier`, `Status`, `Attr1`, `Attr2`, `Attr3`, `Attr4`, `Attr5`) VALUES +('EST-1', 'FI-SW-01', '16.50', '10.00', 1, 'P', 'Large', NULL, NULL, NULL, NULL), +('EST-10', 'K9-DL-01', '18.50', '12.00', 1, 'P', 'Spotted Adult Female', NULL, NULL, NULL, NULL), +('EST-11', 'RP-SN-01', '18.50', '12.00', 1, 'P', 'Venomless', NULL, NULL, NULL, NULL), +('EST-12', 'RP-SN-01', '18.50', '12.00', 1, 'P', 'Rattleless', NULL, NULL, NULL, NULL), +('EST-13', 'RP-LI-02', '18.50', '12.00', 1, 'P', 'Green Adult', NULL, NULL, NULL, NULL), +('EST-14', 'FL-DSH-01', '58.50', '12.00', 1, 'P', 'Tailless', NULL, NULL, NULL, NULL), +('EST-15', 'FL-DSH-01', '23.50', '12.00', 1, 'P', 'Tailed', NULL, NULL, NULL, NULL), +('EST-16', 'FL-DLH-02', '93.50', '12.00', 1, 'P', 'Adult Female', NULL, NULL, NULL, NULL), +('EST-17', 'FL-DLH-02', '93.50', '12.00', 1, 'P', 'Adult Male', NULL, NULL, NULL, NULL), +('EST-18', 'AV-CB-01', '193.50', '92.00', 1, 'P', 'Adult Male', NULL, NULL, NULL, NULL), +('EST-19', 'AV-SB-02', '15.50', '2.00', 1, 'P', 'Adult Male', NULL, NULL, NULL, NULL), +('EST-2', 'FI-SW-01', '16.50', '10.00', 1, 'P', 'Small', NULL, NULL, NULL, NULL), +('EST-20', 'FI-FW-02', '5.50', '2.00', 1, 'P', 'Adult Male', NULL, NULL, NULL, NULL), +('EST-21', 'FI-FW-02', '5.29', '1.00', 1, 'P', 'Adult Female', NULL, NULL, NULL, NULL), +('EST-22', 'K9-RT-02', '135.50', '100.00', 1, 'P', 'Adult Male', NULL, NULL, NULL, NULL), +('EST-23', 'K9-RT-02', '145.49', '100.00', 1, 'P', 'Adult Female', NULL, NULL, NULL, NULL), +('EST-24', 'K9-RT-02', '255.50', '92.00', 1, 'P', 'Adult Male', NULL, NULL, NULL, NULL), +('EST-25', 'K9-RT-02', '325.29', '90.00', 1, 'P', 'Adult Female', NULL, NULL, NULL, NULL), +('EST-26', 'K9-CW-01', '125.50', '92.00', 1, 'P', 'Adult Male', NULL, NULL, NULL, NULL), +('EST-27', 'K9-CW-01', '155.29', '90.00', 1, 'P', 'Adult Female', NULL, NULL, NULL, NULL), +('EST-28', 'K9-RT-01', '155.29', '90.00', 1, 'P', 'Adult Female', NULL, NULL, NULL, NULL), +('EST-3', 'FI-SW-02', '18.50', '12.00', 1, 'P', 'Toothless', NULL, NULL, NULL, NULL), +('EST-4', 'FI-FW-01', '18.50', '12.00', 1, 'P', 'Spotted', NULL, NULL, NULL, NULL), +('EST-5', 'FI-FW-01', '18.50', '12.00', 1, 'P', 'Spotless', NULL, NULL, NULL, NULL), +('EST-6', 'K9-BD-01', '18.50', '12.00', 1, 'P', 'Male Adult', NULL, NULL, NULL, NULL), +('EST-7', 'K9-BD-01', '18.50', '12.00', 1, 'P', 'Female Puppy', NULL, NULL, NULL, NULL), +('EST-8', 'K9-PO-02', '18.50', '12.00', 1, 'P', 'Male Puppy', NULL, NULL, NULL, NULL), +('EST-9', 'K9-DL-01', '18.50', '12.00', 1, 'P', 'Spotless Male Puppy', NULL, NULL, NULL, NULL); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `item 2` +-- + +DROP TABLE IF EXISTS `item 2`; +CREATE TABLE `item 2` ( + `ItemId` varchar(10) NOT NULL, + `ProductId` varchar(10) NOT NULL, + `ListPrice` decimal(10,2) DEFAULT NULL, + `UnitCost` decimal(10,2) DEFAULT NULL, + `Supplier` int(11) DEFAULT NULL, + `Status` varchar(2) DEFAULT NULL, + `Attr1` varchar(80) DEFAULT NULL, + `Attr2` varchar(80) DEFAULT NULL, + `Attr3` varchar(80) DEFAULT NULL, + `Attr4` varchar(80) DEFAULT NULL, + `Attr5` varchar(80) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `priority` +-- + +DROP TABLE IF EXISTS `priority`; +CREATE TABLE `priority` ( + `Id` int(11) NOT NULL, + `Name` varchar(50) NOT NULL, + `Order` int(11) NOT NULL, + `Description` varchar(200) DEFAULT NULL, + `CreatedDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `ModifiedDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `RowVersion` binary(8) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `priority` +-- + +INSERT INTO `priority` (`Id`, `Name`, `Order`, `Description`, `CreatedDate`, `ModifiedDate`, `RowVersion`) VALUES +(1, 'High', 1, 'A High Priority', '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007d1), +(2, 'Normal', 2, 'A Normal Priority', '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007d2), +(3, 'Low', 3, 'A Low Priority', '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007d3); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `product` +-- + +DROP TABLE IF EXISTS `product`; +CREATE TABLE `product` ( + `ProductId` varchar(10) NOT NULL, + `Category` varchar(10) NOT NULL, + `Name` varchar(80) DEFAULT NULL, + `Descn` varchar(255) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `product` +-- + +INSERT INTO `product` (`ProductId`, `Category`, `Name`, `Descn`) VALUES +('AV-CB-01', 'BIRDS', 'Amazon Parrot', 'Great companion for up to 75 years'), +('AV-SB-02', 'BIRDS', 'Finch', 'Great stress reliever'), +('FI-FW-01', 'FISH', 'Koi', 'Freshwater fish from Japan'), +('FI-FW-02', 'FISH', 'Goldfish', 'Freshwater fish from China'), +('FI-SW-01', 'FISH', 'Angelfish', 'Saltwater fish from Australia'), +('FI-SW-02', 'FISH', 'Tiger Shark', 'Saltwater fish from Australia'), +('FL-DLH-02', 'CATS', 'Persian', 'Friendly house cat, doubles as a princess'), +('FL-DSH-01', 'CATS', 'Manx', 'Great for reducing mouse populations'), +('K9-BD-01', 'DOGS', 'Bulldog', 'Friendly dog from England'), +('K9-CW-01', 'DOGS', 'Chihuahua', 'Great companion dog'), +('K9-DL-01', 'DOGS', 'Dalmation', 'Great dog for a fire station'), +('K9-PO-02', 'DOGS', 'Poodle', 'Cute dog from France'), +('K9-RT-01', 'DOGS', 'Golden Retriever', 'Great family dog'), +('K9-RT-02', 'DOGS', 'Labrador Retriever', 'Great hunting dog'), +('RP-LI-02', 'REPTILES', 'Iguana', 'Friendly green friend'), +('RP-SN-01', 'REPTILES', 'Rattlesnake', 'Doubles as a watch dog'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `productsummary` +-- + +DROP TABLE IF EXISTS `productsummary`; +CREATE TABLE `productsummary` ( + `ProductId` varchar(10) NOT NULL, + `Name` varchar(80) DEFAULT NULL, + `AvgPrice` decimal(10,2) NOT NULL, + `Verified` tinyint(1) NOT NULL DEFAULT '1' +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `role` +-- + +DROP TABLE IF EXISTS `role`; +CREATE TABLE `role` ( + `Id` int(11) NOT NULL, + `Name` varchar(50) NOT NULL, + `Description` varchar(150) DEFAULT NULL, + `CreatedDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `ModifiedDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `RowVersion` binary(8) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `role` +-- + +INSERT INTO `role` (`Id`, `Name`, `Description`, `CreatedDate`, `ModifiedDate`, `RowVersion`) VALUES +(1, 'Admin', NULL, '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007d4), +(2, 'Manager', NULL, '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007d5), +(3, 'Newb', NULL, '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007d6), +(4, 'Nobody', NULL, '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007d7), +(5, 'Power User', NULL, '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007d8); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `status` +-- + +DROP TABLE IF EXISTS `status`; +CREATE TABLE `status` ( + `Id` int(11) NOT NULL, + `Name` varchar(50) NOT NULL, + `Description` varchar(150) DEFAULT NULL, + `Order` int(11) NOT NULL, + `CreatedDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `ModifiedDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `RowVersion` binary(8) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `status` +-- + +INSERT INTO `status` (`Id`, `Name`, `Description`, `Order`, `CreatedDate`, `ModifiedDate`, `RowVersion`) VALUES +(1, 'Not Started', NULL, 1, '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007d9), +(2, 'In Progress', NULL, 2, '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007da), +(3, 'Completed', NULL, 3, '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007db), +(4, 'Waiting on someone else', NULL, 4, '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007dc), +(5, 'Deferred', NULL, 5, '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007dd), +(6, 'Done', NULL, 6, '2011-09-08 06:57:02', '2011-09-08 06:57:02', 0x00000000000007de); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `task` +-- + +DROP TABLE IF EXISTS `task`; +CREATE TABLE `task` ( + `Id` int(11) NOT NULL, + `StatusId` int(11) NOT NULL, + `PriorityId` int(11) DEFAULT NULL, + `CreatedId` int(11) NOT NULL, + `Summary` varchar(255) NOT NULL, + `Details` varchar(2000) DEFAULT NULL, + `StartDate` datetime DEFAULT NULL, + `DueDate` datetime DEFAULT NULL, + `CompleteDate` datetime DEFAULT NULL, + `AssignedId` int(11) DEFAULT NULL, + `CreatedDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `ModifiedDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `RowVersion` binary(8) NOT NULL, + `LastModifiedBy` varchar(50) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `task` +-- + +INSERT INTO `task` (`Id`, `StatusId`, `PriorityId`, `CreatedId`, `Summary`, `Details`, `StartDate`, `DueDate`, `CompleteDate`, `AssignedId`, `CreatedDate`, `ModifiedDate`, `RowVersion`, `LastModifiedBy`) VALUES +(1, 1, 1, 2, 'Make it to Earth', 'Find and make it to earth while avoiding the cylons.', NULL, NULL, NULL, 1, '2009-12-18 04:01:58', '2009-12-18 04:01:58', 0x00000000000007df, 'laura.roslin@battlestar.com'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `taskextended` +-- + +DROP TABLE IF EXISTS `taskextended`; +CREATE TABLE `taskextended` ( + `TaskId` int(11) NOT NULL, + `Browser` varchar(200) DEFAULT NULL, + `OS` varchar(150) DEFAULT NULL, + `CreatedDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `ModifiedDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `RowVersion` binary(8) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `user` +-- + +DROP TABLE IF EXISTS `user`; +CREATE TABLE `user` ( + `Id` int(11) NOT NULL, + `EmailAddress` varchar(250) NOT NULL, + `FirstName` varchar(200) DEFAULT NULL, + `LastName` varchar(200) DEFAULT NULL, + `Avatar` longblob, + `CreatedDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `ModifiedDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `RowVersion` binary(8) NOT NULL, + `PasswordHash` char(86) NOT NULL DEFAULT '', + `PasswordSalt` char(5) NOT NULL DEFAULT '', + `Comment` longtext, + `IsApproved` tinyint(1) NOT NULL DEFAULT '1', + `LastLoginDate` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `LastActivityDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `LastPasswordChangeDate` datetime DEFAULT NULL, + `AvatarType` varchar(150) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `user` +-- + +INSERT INTO `user` (`Id`, `EmailAddress`, `FirstName`, `LastName`, `Avatar`, `CreatedDate`, `ModifiedDate`, `RowVersion`, `PasswordHash`, `PasswordSalt`, `Comment`, `IsApproved`, `LastLoginDate`, `LastActivityDate`, `LastPasswordChangeDate`, `AvatarType`) VALUES +(1, 'william.adama@battlestar.com', 'William', 'Adama', NULL, '2009-05-06 10:46:20', '2009-05-06 10:46:20', 0x00000000000007e0, '1+v5rvSXnyX7tvwTKfM+aq+s0hDmNXsduGZfq8sQv1ggPnGlQdDdBdbUP0bUmbMbiU40PvRQWKRAy5QUd1xrAA', '?#nkY', NULL, 1, NULL, '2009-05-06 10:46:20', NULL, NULL), +(2, 'laura.roslin@battlestar.com', 'Laura', 'Roslin', NULL, '2009-05-06 10:47:00', '2009-05-06 10:47:00', 0x00000000000007e1, 'Sx/jwRHFW/CQpO0E6G8d+jo344AmAKfX+C48a0iAZyMrb4sE8VoDuyZorbhbLZAX9f4UZk67O7eCjk854OrYSg', 'Ph)6;', NULL, 1, NULL, '2009-05-06 10:47:00', NULL, NULL), +(3, 'kara.thrace@battlestar.com', 'Kara', 'Thrace', NULL, '2009-05-06 10:47:43', '2009-05-06 10:47:43', 0x00000000000007e2, '5KhtS4ax7G1aGkq97w02ooVZMmJp8bcySEKMSxruXu/Z/wRKoNAxMlkjRVY1yLavrC3GRYQZjy5b6JW8cR5EWg', '!]@2/', NULL, 1, NULL, '2009-05-06 10:47:43', NULL, NULL), +(4, 'lee.adama@battlestar.com', 'Lee', 'Adama', NULL, '2009-05-06 10:48:02', '2009-05-06 10:48:02', 0x00000000000007e3, 'IrK8OhI2n4Ev3YA4y5kP7vy+n2CffX2MgcONbAh6/kZpNZYBYoYyrMhqdYztehL0NAIdvcInQ6zOjMplq+zWQA', 'e@_a{', NULL, 1, NULL, '2009-05-06 10:48:02', NULL, NULL), +(5, 'gaius.baltar@battlestar.com', 'Gaius', 'Baltar', NULL, '2009-05-06 10:48:26', '2009-05-06 10:48:26', 0x00000000000007e4, '7tfajMaEerDNVgi6Oi6UJ6JxsUXZ0u4zQeUrZQxnaXJQ2f2vd9AzBR4sVOaH7LZtCjQopMzlQ38QqNEnpK0B/g', '_qpA2', NULL, 1, NULL, '2009-05-06 10:48:26', NULL, NULL), +(6, 'saul.tigh@battlestar.com', 'Saul', 'Tigh', NULL, '2009-05-06 10:49:26', '2009-05-06 10:49:26', 0x00000000000007e5, 'wzkR89zRXe7hND1jqAP9xgupYJBvEZcjsfUe3TaU45kxRajjjS9u0fOTLK+uglzk67EGochJdeoikWs7hxMNRA', 'h]-zG', NULL, 1, NULL, '2009-05-06 10:49:26', NULL, NULL); + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `audit` +-- +ALTER TABLE `audit` + ADD PRIMARY KEY (`Id`), + ADD KEY `FK_Audit_Task` (`TaskId`), + ADD KEY `FK_Audit_User` (`UserId`); + +-- +-- Indexes for table `item` +-- +ALTER TABLE `item` + ADD PRIMARY KEY (`ItemId`), + ADD KEY `FK__Item__ProductId__04E4BC85` (`ProductId`); + +-- +-- Indexes for table `item 2` +-- +ALTER TABLE `item 2` + ADD PRIMARY KEY (`ItemId`), + ADD KEY `FK__Item 2__ProductI__0A9D95DB` (`ProductId`); + +-- +-- Indexes for table `priority` +-- +ALTER TABLE `priority` + ADD PRIMARY KEY (`Id`); + +-- +-- Indexes for table `product` +-- +ALTER TABLE `product` + ADD PRIMARY KEY (`ProductId`); + +-- +-- Indexes for table `productsummary` +-- +ALTER TABLE `productsummary` + ADD PRIMARY KEY (`ProductId`); + +-- +-- Indexes for table `role` +-- +ALTER TABLE `role` + ADD PRIMARY KEY (`Id`); + +-- +-- Indexes for table `status` +-- +ALTER TABLE `status` + ADD PRIMARY KEY (`Id`); + +-- +-- Indexes for table `task` +-- +ALTER TABLE `task` + ADD PRIMARY KEY (`Id`), + ADD KEY `IX_Task` (`AssignedId`,`StatusId`), + ADD KEY `FK_Task_Priority` (`PriorityId`), + ADD KEY `FK_Task_Status` (`StatusId`), + ADD KEY `FK_Task_User_Created` (`CreatedId`); + +-- +-- Indexes for table `taskextended` +-- +ALTER TABLE `taskextended` + ADD PRIMARY KEY (`TaskId`); + +-- +-- Indexes for table `user` +-- +ALTER TABLE `user` + ADD PRIMARY KEY (`Id`), + ADD UNIQUE KEY `IX_User` (`EmailAddress`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `audit` +-- +ALTER TABLE `audit` + MODIFY `Id` int(11) NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT for table `role` +-- +ALTER TABLE `role` + MODIFY `Id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6; +-- +-- AUTO_INCREMENT for table `status` +-- +ALTER TABLE `status` + MODIFY `Id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7; +-- +-- AUTO_INCREMENT for table `task` +-- +ALTER TABLE `task` + MODIFY `Id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; +-- +-- AUTO_INCREMENT for table `user` +-- +ALTER TABLE `user` + MODIFY `Id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7; +-- +-- Constraints for dumped tables +-- + +-- +-- Constraints for table `audit` +-- +ALTER TABLE `audit` + ADD CONSTRAINT `FK_Audit_Task` FOREIGN KEY (`TaskId`) REFERENCES `task` (`Id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + ADD CONSTRAINT `FK_Audit_User` FOREIGN KEY (`UserId`) REFERENCES `user` (`Id`) ON DELETE NO ACTION ON UPDATE NO ACTION; + +-- +-- Constraints for table `item` +-- +ALTER TABLE `item` + ADD CONSTRAINT `FK__Item__ProductId__04E4BC85` FOREIGN KEY (`ProductId`) REFERENCES `product` (`ProductId`) ON DELETE NO ACTION ON UPDATE NO ACTION; + +-- +-- Constraints for table `item 2` +-- +ALTER TABLE `item 2` + ADD CONSTRAINT `FK__Item 2__ProductI__0A9D95DB` FOREIGN KEY (`ProductId`) REFERENCES `product` (`ProductId`) ON DELETE NO ACTION ON UPDATE NO ACTION; + +-- +-- Constraints for table `task` +-- +ALTER TABLE `task` + ADD CONSTRAINT `FK_Task_Priority` FOREIGN KEY (`PriorityId`) REFERENCES `priority` (`Id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + ADD CONSTRAINT `FK_Task_Status` FOREIGN KEY (`StatusId`) REFERENCES `status` (`Id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + ADD CONSTRAINT `FK_Task_User_Assigned` FOREIGN KEY (`AssignedId`) REFERENCES `user` (`Id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + ADD CONSTRAINT `FK_Task_User_Created` FOREIGN KEY (`CreatedId`) REFERENCES `user` (`Id`) ON DELETE NO ACTION ON UPDATE NO ACTION; + +-- +-- Constraints for table `taskextended` +-- +ALTER TABLE `taskextended` + ADD CONSTRAINT `FK_TaskExtended_Task` FOREIGN KEY (`TaskId`) REFERENCES `task` (`Id`) ON DELETE NO ACTION ON UPDATE NO ACTION; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/Database/SqlServer/Tracker.sql b/Database/SqlServer/Tracker.sql index 6dc6c92..ac6ff9c 100644 Binary files a/Database/SqlServer/Tracker.sql and b/Database/SqlServer/Tracker.sql differ diff --git a/Database/SqlServer/Tracker/DacMetadata.xml b/Database/SqlServer/Tracker/DacMetadata.xml new file mode 100644 index 0000000..392353a --- /dev/null +++ b/Database/SqlServer/Tracker/DacMetadata.xml @@ -0,0 +1,5 @@ + + + Tracker + 1.0.0.0 + \ No newline at end of file diff --git a/Database/SqlServer/Tracker/Origin.xml b/Database/SqlServer/Tracker/Origin.xml new file mode 100644 index 0000000..8cd1b07 --- /dev/null +++ b/Database/SqlServer/Tracker/Origin.xml @@ -0,0 +1,22 @@ + + + + 3.0.0.0 + false + + 2.0.0.0 + 1.0.0.0 + + + + b115af09-6ff8-4ee2-aa71-27c1b9dcda60 + 2014-09-04T15:26:48.1499192-05:00 + 2014-09-04T15:26:48.2608526-05:00 + Microsoft.Data.Tools.Schema.Tasks.Sql, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + 12.0.40706.0 + http://schemas.microsoft.com/sqlserver/dac/Serialization/2012/02 + + + 4A52E1138674B39C68C0111BF1D1A0CA20D3D4633B60409E97BF619E229EF901 + + \ No newline at end of file diff --git a/Database/SqlServer/Tracker/model.sql b/Database/SqlServer/Tracker/model.sql new file mode 100644 index 0000000..3a3dac9 --- /dev/null +++ b/Database/SqlServer/Tracker/model.sql @@ -0,0 +1,123 @@ +CREATE TABLE [dbo].[Audit] ( + [Id] INT IDENTITY (1, 1) NOT NULL, + [Date] DATETIME NOT NULL, + [UserId] INT NULL, + [TaskId] INT NULL, + [Content] VARCHAR (MAX) NOT NULL, + [Username] NVARCHAR (50) NOT NULL, + [CreatedDate] DATETIME CONSTRAINT [DF_Audit_CreatedDate] DEFAULT (getdate()) NOT NULL, + [RowVersion] ROWVERSION NOT NULL, + CONSTRAINT [PK_Audit] PRIMARY KEY CLUSTERED ([Id] ASC), + CONSTRAINT [FK_Audit_Task] FOREIGN KEY ([TaskId]) REFERENCES [dbo].[Task] ([Id]), + CONSTRAINT [FK_Audit_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id]) +); + +GO +CREATE TABLE [dbo].[Priority] ( + [Id] INT NOT NULL, + [Name] NVARCHAR (50) NOT NULL, + [Order] INT NOT NULL, + [Description] NVARCHAR (200) NULL, + [CreatedDate] DATETIME CONSTRAINT [DF__Priority__CreatedDate] DEFAULT (getdate()) NOT NULL, + [ModifiedDate] DATETIME CONSTRAINT [DF__Priority__ModifiedDate] DEFAULT (getdate()) NOT NULL, + [RowVersion] ROWVERSION NOT NULL, + CONSTRAINT [PK_Priority] PRIMARY KEY CLUSTERED ([Id] ASC) +); + +GO +CREATE TABLE [dbo].[Role] ( + [Id] INT IDENTITY (1, 1) NOT NULL, + [Name] NVARCHAR (50) NOT NULL, + [Description] NVARCHAR (150) NULL, + [CreatedDate] DATETIME CONSTRAINT [DF__Role__CreatedDate] DEFAULT (getdate()) NOT NULL, + [ModifiedDate] DATETIME CONSTRAINT [DF__Role__ModifiedDate] DEFAULT (getdate()) NOT NULL, + [RowVersion] ROWVERSION NOT NULL, + CONSTRAINT [PK_Role] PRIMARY KEY CLUSTERED ([Id] ASC) +); + +GO +CREATE TABLE [dbo].[Status] ( + [Id] INT IDENTITY (1, 1) NOT NULL, + [Name] NVARCHAR (50) NOT NULL, + [Description] NVARCHAR (150) NULL, + [Order] INT NOT NULL, + [CreatedDate] DATETIME CONSTRAINT [DF__Status__CreatedDate] DEFAULT (getdate()) NOT NULL, + [ModifiedDate] DATETIME CONSTRAINT [DF__Status__ModifiedDate] DEFAULT (getdate()) NOT NULL, + [RowVersion] ROWVERSION NOT NULL, + CONSTRAINT [PK_Status] PRIMARY KEY CLUSTERED ([Id] ASC) +); + +GO +CREATE TABLE [dbo].[Task] ( + [Id] INT IDENTITY (1, 1) NOT NULL, + [StatusId] INT NOT NULL, + [PriorityId] INT NULL, + [CreatedId] INT NOT NULL, + [Summary] NVARCHAR (255) NOT NULL, + [Details] NVARCHAR (2000) NULL, + [StartDate] DATETIME NULL, + [DueDate] DATETIME NULL, + [CompleteDate] DATETIME NULL, + [AssignedId] INT NULL, + [CreatedDate] DATETIME CONSTRAINT [DF__Task__CreatedDate] DEFAULT (getdate()) NOT NULL, + [ModifiedDate] DATETIME CONSTRAINT [DF__Task__ModifiedDate] DEFAULT (getdate()) NOT NULL, + [RowVersion] ROWVERSION NOT NULL, + [LastModifiedBy] NVARCHAR (50) NULL, + CONSTRAINT [PK_Task] PRIMARY KEY CLUSTERED ([Id] ASC), + CONSTRAINT [FK_Task_Priority] FOREIGN KEY ([PriorityId]) REFERENCES [dbo].[Priority] ([Id]), + CONSTRAINT [FK_Task_Status] FOREIGN KEY ([StatusId]) REFERENCES [dbo].[Status] ([Id]), + CONSTRAINT [FK_Task_User_Assigned] FOREIGN KEY ([AssignedId]) REFERENCES [dbo].[User] ([Id]), + CONSTRAINT [FK_Task_User_Created] FOREIGN KEY ([CreatedId]) REFERENCES [dbo].[User] ([Id]) +); + +GO +CREATE TABLE [dbo].[TaskExtended] ( + [TaskId] INT NOT NULL, + [Browser] NVARCHAR (200) NULL, + [OS] NVARCHAR (150) NULL, + [CreatedDate] DATETIME DEFAULT (getdate()) NOT NULL, + [ModifiedDate] DATETIME DEFAULT (getdate()) NOT NULL, + [RowVersion] ROWVERSION NOT NULL, + CONSTRAINT [PK_TaskExtended] PRIMARY KEY CLUSTERED ([TaskId] ASC), + CONSTRAINT [FK_TaskExtended_Task] FOREIGN KEY ([TaskId]) REFERENCES [dbo].[Task] ([Id]) +); + +GO +CREATE TABLE [dbo].[User] ( + [Id] INT IDENTITY (1, 1) NOT NULL, + [EmailAddress] NVARCHAR (250) NOT NULL, + [FirstName] NVARCHAR (200) NULL, + [LastName] NVARCHAR (200) NULL, + [Avatar] VARBINARY (MAX) NULL, + [CreatedDate] DATETIME CONSTRAINT [DF__User__CreatedDate] DEFAULT (getdate()) NOT NULL, + [ModifiedDate] DATETIME CONSTRAINT [DF__User__ModifiedDate] DEFAULT (getdate()) NOT NULL, + [RowVersion] ROWVERSION NOT NULL, + [PasswordHash] CHAR (86) CONSTRAINT [DF__User__PasswordHash] DEFAULT ('') NOT NULL, + [PasswordSalt] CHAR (5) CONSTRAINT [DF__User__PasswordSalt] DEFAULT ('') NOT NULL, + [Comment] TEXT NULL, + [IsApproved] BIT CONSTRAINT [DF__User__IsApproved] DEFAULT ((1)) NOT NULL, + [LastLoginDate] DATETIME CONSTRAINT [DF__User__LastLoginDate] DEFAULT (getdate()) NULL, + [LastActivityDate] DATETIME CONSTRAINT [DF__User__LastActivityDate] DEFAULT (getdate()) NOT NULL, + [LastPasswordChangeDate] DATETIME NULL, + [AvatarType] NVARCHAR (150) NULL, + CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC) +); + +GO +CREATE TABLE [dbo].[UserRole] ( + [UserId] INT NOT NULL, + [RoleId] INT NOT NULL, + CONSTRAINT [PK_UserRole] PRIMARY KEY CLUSTERED ([UserId] ASC, [RoleId] ASC), + CONSTRAINT [FK_UserRole_Role] FOREIGN KEY ([RoleId]) REFERENCES [dbo].[Role] ([Id]), + CONSTRAINT [FK_UserRole_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id]) +); + +GO +CREATE NONCLUSTERED INDEX [IX_Task] + ON [dbo].[Task]([AssignedId] ASC, [StatusId] ASC); + +GO +CREATE UNIQUE NONCLUSTERED INDEX [IX_User] + ON [dbo].[User]([EmailAddress] ASC); + +GO diff --git a/Database/SqlServer/Tracker/model.xml b/Database/SqlServer/Tracker/model.xml new file mode 100644 index 0000000..f07b170 --- /dev/null +++ b/Database/SqlServer/Tracker/model.xml @@ -0,0 +1,1925 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/Database/SqlServer/Tracker/postdeploy.sql b/Database/SqlServer/Tracker/postdeploy.sql new file mode 100644 index 0000000..b72b0b1 --- /dev/null +++ b/Database/SqlServer/Tracker/postdeploy.sql @@ -0,0 +1,471 @@ +/* +Post-Deployment Script Template +-------------------------------------------------------------------------------------- + This file contains SQL statements that will be appended to the build script. + Use SQLCMD syntax to include a file in the post-deployment script. + Example: :r .\myfile.sql + Use SQLCMD syntax to reference a variable in the post-deployment script. + Example: :setvar TableName MyTable + SELECT * FROM [$(TableName)] +-------------------------------------------------------------------------------------- +*/ + +-- Table [dbo].[Priority] data +MERGE INTO [dbo].[Priority] AS t +USING +( + VALUES + ( + 1, + 'High', + 1, + 'A High Priority' + ), + ( + 2, + 'Normal', + 2, + 'A Normal Priority' + ), + ( + 3, + 'Low', + 3, + 'A Low Priority' + ) +) +AS s +( + [Id], + [Name], + [Order], + [Description] +) +ON +( + t.[Id] = s.[Id] +) +WHEN NOT MATCHED BY TARGET THEN + INSERT + ( + [Id], + [Name], + [Order], + [Description] + ) + VALUES + ( + s.[Id], + s.[Name], + s.[Order], + s.[Description] + ) +WHEN MATCHED THEN + UPDATE SET + t.[Name] = s.[Name], + t.[Order] = s.[Order], + t.[Description] = s.[Description] +OUTPUT $action as [Action]; + + +SET IDENTITY_INSERT [dbo].[Role] ON + +-- Table [dbo].[Role] data +MERGE INTO [dbo].[Role] AS t +USING +( + VALUES + ( + 1, + 'Admin', + 'Admin Role' + ), + ( + 2, + 'Manager', + NULL + ), + ( + 3, + 'Newb', + NULL + ), + ( + 4, + 'Nobody', + NULL + ), + ( + 5, + 'Power User', + NULL + ) +) +AS s +( + [Id], + [Name], + [Description] +) +ON +( + t.[Id] = s.[Id] +) +WHEN NOT MATCHED BY TARGET THEN + INSERT + ( + [Id], + [Name], + [Description] + ) + VALUES + ( + s.[Id], + s.[Name], + s.[Description] + ) +WHEN MATCHED THEN + UPDATE SET + t.[Name] = s.[Name], + t.[Description] = s.[Description] +OUTPUT $action as [Action]; + +SET IDENTITY_INSERT [dbo].[Role] OFF + + +SET IDENTITY_INSERT [dbo].[Status] ON + +-- Table [dbo].[Status] data +MERGE INTO [dbo].[Status] AS t +USING +( + VALUES + ( + 1, + 'Not Started', + NULL, + 1 + ), + ( + 2, + 'In Progress', + NULL, + 2 + ), + ( + 3, + 'Completed', + NULL, + 3 + ), + ( + 4, + 'Waiting on someone else', + NULL, + 4 + ), + ( + 5, + 'Deferred', + NULL, + 5 + ), + ( + 6, + 'Done', + NULL, + 6 + ) +) +AS s +( + [Id], + [Name], + [Description], + [Order] +) +ON +( + t.[Id] = s.[Id] +) +WHEN NOT MATCHED BY TARGET THEN + INSERT + ( + [Id], + [Name], + [Description], + [Order] + ) + VALUES + ( + s.[Id], + s.[Name], + s.[Description], + s.[Order] + ) +WHEN MATCHED THEN + UPDATE SET + t.[Name] = s.[Name], + t.[Description] = s.[Description], + t.[Order] = s.[Order] +OUTPUT $action as [Action]; + +SET IDENTITY_INSERT [dbo].[Status] OFF + + +SET IDENTITY_INSERT [dbo].[User] ON + +-- Table [dbo].[User] data +MERGE INTO [dbo].[User] AS t +USING +( + VALUES + ( + 1, + 'william.adama@battlestar.com', + 'William', + 'Adama', + NULL, + '1+v5rvSXnyX7tvwTKfM+aq+s0hDmNXsduGZfq8sQv1ggPnGlQdDdBdbUP0bUmbMbiU40PvRQWKRAy5QUd1xrAA', + '?#nkY', + 'Data Merge 635324524904242477', + 1, + '2014-04-07 07:26:54', + '2009-05-06 17:46:20', + NULL, + NULL + ), + ( + 2, + 'laura.roslin@battlestar.com', + 'Laura', + 'Roslin', + NULL, + 'Sx/jwRHFW/CQpO0E6G8d+jo344AmAKfX+C48a0iAZyMrb4sE8VoDuyZorbhbLZAX9f4UZk67O7eCjk854OrYSg', + 'Ph)6;', + 'Data Merge 635324524904242477', + 1, + '2014-04-07 07:26:54', + '2009-05-06 17:47:00', + NULL, + NULL + ), + ( + 3, + 'kara.thrace@battlestar.com', + 'Kara', + 'Thrace', + NULL, + '5KhtS4ax7G1aGkq97w02ooVZMmJp8bcySEKMSxruXu/Z/wRKoNAxMlkjRVY1yLavrC3GRYQZjy5b6JW8cR5EWg', + '!]@2/', + 'Data Merge 635324524147981355', + 1, + '2014-04-07 07:26:54', + '2009-05-06 17:47:43', + NULL, + NULL + ), + ( + 4, + 'lee.adama@battlestar.com', + 'Lee', + 'Adama', + NULL, + 'IrK8OhI2n4Ev3YA4y5kP7vy+n2CffX2MgcONbAh6/kZpNZYBYoYyrMhqdYztehL0NAIdvcInQ6zOjMplq+zWQA', + 'e@_a{', + 'Data Merge 635324524147981355', + 1, + '2014-04-07 07:26:54', + '2009-05-06 17:48:02', + NULL, + NULL + ), + ( + 5, + 'gaius.baltar@battlestar.com', + 'Gaius', + 'Baltar', + NULL, + '7tfajMaEerDNVgi6Oi6UJ6JxsUXZ0u4zQeUrZQxnaXJQ2f2vd9AzBR4sVOaH7LZtCjQopMzlQ38QqNEnpK0B/g', + '_qpA2', + 'Data Merge 635324524147981355', + 1, + '2014-04-07 07:26:54', + '2009-05-06 17:48:26', + NULL, + NULL + ), + ( + 6, + 'saul.tigh@battlestar.com', + 'Saul', + 'Tigh', + NULL, + 'wzkR89zRXe7hND1jqAP9xgupYJBvEZcjsfUe3TaU45kxRajjjS9u0fOTLK+uglzk67EGochJdeoikWs7hxMNRA', + 'h]-zG', + 'Data Merge 635324524147981355', + 1, + '2014-04-07 07:26:54', + '2009-05-06 17:49:26', + NULL, + NULL + ) +) +AS s +( + [Id], + [EmailAddress], + [FirstName], + [LastName], + [Avatar], + [PasswordHash], + [PasswordSalt], + [Comment], + [IsApproved], + [LastLoginDate], + [LastActivityDate], + [LastPasswordChangeDate], + [AvatarType] +) +ON +( + t.[Id] = s.[Id] +) +WHEN NOT MATCHED BY TARGET THEN + INSERT + ( + [Id], + [EmailAddress], + [FirstName], + [LastName], + [Avatar], + [PasswordHash], + [PasswordSalt], + [Comment], + [IsApproved], + [LastLoginDate], + [LastActivityDate], + [LastPasswordChangeDate], + [AvatarType] + ) + VALUES + ( + s.[Id], + s.[EmailAddress], + s.[FirstName], + s.[LastName], + s.[Avatar], + s.[PasswordHash], + s.[PasswordSalt], + s.[Comment], + s.[IsApproved], + s.[LastLoginDate], + s.[LastActivityDate], + s.[LastPasswordChangeDate], + s.[AvatarType] + ) +WHEN MATCHED THEN + UPDATE SET + t.[EmailAddress] = s.[EmailAddress], + t.[FirstName] = s.[FirstName], + t.[LastName] = s.[LastName], + t.[Avatar] = s.[Avatar], + t.[PasswordHash] = s.[PasswordHash], + t.[PasswordSalt] = s.[PasswordSalt], + t.[Comment] = s.[Comment], + t.[IsApproved] = s.[IsApproved], + t.[LastLoginDate] = s.[LastLoginDate], + t.[LastActivityDate] = s.[LastActivityDate], + t.[LastPasswordChangeDate] = s.[LastPasswordChangeDate], + t.[AvatarType] = s.[AvatarType] +OUTPUT $action as [Action]; + +SET IDENTITY_INSERT [dbo].[User] OFF + + +SET IDENTITY_INSERT [dbo].[Task] ON + +-- Table [dbo].[Task] data +MERGE INTO [dbo].[Task] AS t +USING +( + VALUES + ( + 1, + 1, + 1, + 2, + 'Make it to Earth', + 'Find and make it to earth while avoiding the cylons.', + NULL, + NULL, + NULL, + 1, + 'laura.roslin@battlestar.com' + ) +) +AS s +( + [Id], + [StatusId], + [PriorityId], + [CreatedId], + [Summary], + [Details], + [StartDate], + [DueDate], + [CompleteDate], + [AssignedId], + [LastModifiedBy] +) +ON +( + t.[Id] = s.[Id] +) +WHEN NOT MATCHED BY TARGET THEN + INSERT + ( + [Id], + [StatusId], + [PriorityId], + [CreatedId], + [Summary], + [Details], + [StartDate], + [DueDate], + [CompleteDate], + [AssignedId], + [LastModifiedBy] + ) + VALUES + ( + s.[Id], + s.[StatusId], + s.[PriorityId], + s.[CreatedId], + s.[Summary], + s.[Details], + s.[StartDate], + s.[DueDate], + s.[CompleteDate], + s.[AssignedId], + s.[LastModifiedBy] + ) +WHEN MATCHED THEN + UPDATE SET + t.[StatusId] = s.[StatusId], + t.[PriorityId] = s.[PriorityId], + t.[CreatedId] = s.[CreatedId], + t.[Summary] = s.[Summary], + t.[Details] = s.[Details], + t.[StartDate] = s.[StartDate], + t.[DueDate] = s.[DueDate], + t.[CompleteDate] = s.[CompleteDate], + t.[AssignedId] = s.[AssignedId], + t.[LastModifiedBy] = s.[LastModifiedBy] +OUTPUT $action as [Action]; + +SET IDENTITY_INSERT [dbo].[Task] OFF + + +GO diff --git a/License.txt b/License.txt index cf68ccd..6704ab5 100644 --- a/License.txt +++ b/License.txt @@ -1,4 +1,5 @@ Copyright (c) 2012, LoreSoft +Modified by AT Mulyana in 2016-2018 All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/Source/EntityFramework.Extended.Test/EntityFramework.Extended.Test.net40.csproj b/Source/EntityFramework.Extended.Test/EntityFramework.Extended.Test.net40.csproj index 78c0411..9ffc6b2 100644 --- a/Source/EntityFramework.Extended.Test/EntityFramework.Extended.Test.net40.csproj +++ b/Source/EntityFramework.Extended.Test/EntityFramework.Extended.Test.net40.csproj @@ -112,6 +112,9 @@ + + + - + \ No newline at end of file diff --git a/Source/EntityFramework.Extended/EntityFramework.Extended.net45.csproj b/Source/EntityFramework.Extended/EntityFramework.Extended.net45.csproj index ddf8af6..aee8ce8 100644 --- a/Source/EntityFramework.Extended/EntityFramework.Extended.net45.csproj +++ b/Source/EntityFramework.Extended/EntityFramework.Extended.net45.csproj @@ -1,7 +1,7 @@  - Debug + Release AnyCPU 8.0.30703 2.0 @@ -77,6 +77,8 @@ + + diff --git a/Source/EntityFramework.Extended/EntityFramework.Extended.nuspec b/Source/EntityFramework.Extended/EntityFramework.Extended.nuspec index 4fa97e0..7cc3d69 100644 --- a/Source/EntityFramework.Extended/EntityFramework.Extended.nuspec +++ b/Source/EntityFramework.Extended/EntityFramework.Extended.nuspec @@ -1,20 +1,20 @@ - EntityFramework.Extended - 6.1.0.0 - LoreSoft - LoreSoft - https://github.com/loresoft/EntityFramework.Extended - https://github.com/loresoft/EntityFramework.Extended + EntityFrameworkExtended + 6.2.0.4 + LoreSoft, AT Mulyana + LoreSoft, AT Mulyana + https://github.com/atmulyana/EntityFramework.Extended + https://github.com/atmulyana/EntityFramework.Extended false A library that extends the functionality of Entity Framework by adding batch update, future queries and audit logs. Entity Framework extensions library. - Copyright (c) 2014, LoreSoft + Copyright (c) 2014, LoreSoft, Modified by AT Mulyana in 2016-2018 en-US EntityFramework - + diff --git a/Source/EntityFramework.Extended/Extensions/BatchExtensions.cs b/Source/EntityFramework.Extended/Extensions/BatchExtensions.cs index 8cb019f..7700d80 100644 --- a/Source/EntityFramework.Extended/Extensions/BatchExtensions.cs +++ b/Source/EntityFramework.Extended/Extensions/BatchExtensions.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using EntityFramework.Batch; using EntityFramework.Mapping; +using System.Collections.Generic; namespace EntityFramework.Extensions { @@ -394,10 +395,220 @@ public static Task UpdateAsync( var runner = ResolveRunner(); return runner.UpdateAsync(objectContext, entityMap, sourceQuery, updateExpression); } +#endif + + private static Tuple GetQueryObjects(IDbSet dbSet) where TEntity : class + { + if (dbSet == null) + throw new ArgumentNullException("dbSet"); + + ObjectQuery destQuery = dbSet.ToObjectQuery(); + if (destQuery == null) + throw new ArgumentException("The DbSet must be of type ObjectQuery or DbQuery.", "dbSet"); + + ObjectContext destContext = destQuery.Context; + if (destContext == null) + throw new ArgumentException("The ObjectContext for the DbSet can not be null.", "dbSet"); + + EntityMap entityMap = destQuery.GetEntityMap(); + if (entityMap == null) + throw new ArgumentException("Could not load the entity mapping information for the destination.", "dbSet"); + return Tuple.Create(destContext, entityMap); + } + + private static Tuple, EntityMap> CheckDbQueryParams(IDbSet destination, + IQueryable source) + where TEntity : class + where TModel : class + { + EntityMap entityMap = GetQueryObjects(destination).Item2; + + ObjectQuery sourceQuery = source.ToObjectQuery(); + if (sourceQuery == null) + throw new ArgumentException("The query must be of type ObjectQuery or DbQuery.", "source"); + + ObjectContext sourceContext = sourceQuery.Context; + if (sourceContext == null) + throw new ArgumentException("The ObjectContext for the query can not be null.", "source"); + + return Tuple.Create(sourceQuery, entityMap); + } + + /// + /// Executes a statement `INSERT INTO [Table] (...) SELECT ...`. + /// + /// The type of the entity representing a record in database table. + /// The type of the query item. + /// The target table where the new data will be inserted into. + /// The query which retrieves the new data that will be inserted into the target table. + /// The number of row inserted. + /// Copy all items whose product id "K9-RT-02" from table item into item_2. + /// + /// + /// + /// When executing this method, the statement is immediately executed on the database provider + /// and is not part of the change tracking system. Also, changes will not be reflected on + /// any entities that have already been materialized in the current context. + /// + public static int Update( + this IDbSet destination, + IQueryable source) + where TEntity : class + where TModel : class + { + var p = CheckDbQueryParams(destination, source); + return ResolveRunner().Update(source, p.Item1, p.Item2); + } + +#if NET45 + /// + /// Executes a statement `INSERT INTO [Table] (...) SELECT ...` asynchronously. + /// + /// The type of the entity representing a record in database table. + /// The type of the query item. + /// The target table where the new data will be inserted into. + /// The query which retrieves the new data that will be inserted into the target table. + /// The number of row inserted. + /// Copy all items whose product id "K9-RT-02" from table item into item_2. + /// + /// + /// + /// When executing this method, the statement is immediately executed on the database provider + /// and is not part of the change tracking system. Also, changes will not be reflected on + /// any entities that have already been materialized in the current context. + /// + public static Task UpdateAsync( + this IDbSet destination, + IQueryable source) + where TEntity : class + where TModel : class + { + var p = CheckDbQueryParams(destination, source); + return ResolveRunner().UpdateAsync(source, p.Item1, p.Item2); + } +#endif + + /// + /// Executes a statement `INSERT INTO [Table] (...) SELECT ...`. + /// + /// The type of the entity representing a record in database table. + /// The type of the query item. + /// The target table where the new data will be inserted into. + /// The query which retrieves the new data that will be inserted into the target table. + /// The number of row inserted. + /// Copy all items whose product id "K9-RT-02" from table item into item_2. + /// + /// + /// + /// When executing this method, the statement is immediately executed on the database provider + /// and is not part of the change tracking system. Also, changes will not be reflected on + /// any entities that have already been materialized in the current context. + /// + public static int Insert( + this IDbSet destination, + IQueryable source) + where TEntity : class + where TModel : class + { + var p = CheckDbQueryParams(destination, source); + return ResolveRunner().Insert(source, p.Item1, p.Item2); + } +#if NET45 + /// + /// Executes a statement `INSERT INTO [Table] (...) SELECT ...` asynchronously. + /// + /// The type of the entity representing a record in database table. + /// The type of the query item. + /// The target table where the new data will be inserted into. + /// The query which retrieves the new data that will be inserted into the target table. + /// The number of row inserted. + /// Copy all items whose product id "K9-RT-02" from table item into item_2. + /// + /// + /// + /// When executing this method, the statement is immediately executed on the database provider + /// and is not part of the change tracking system. Also, changes will not be reflected on + /// any entities that have already been materialized in the current context. + /// + public static Task InsertAsync( + this IDbSet destination, + IQueryable source) + where TEntity : class + where TModel : class + { + var p = CheckDbQueryParams(destination, source); + return ResolveRunner().InsertAsync(source, p.Item1, p.Item2); + } +#endif + + /// + /// Inserts a lof of rows into a database table. It must be much faster than executing `DbSet.AddRange` or + /// repetitive `DbSet.Add` method and then executing 'DbContext.SaveChanges' method. + /// + /// The type of objects representing rows to be inserted into db table. + /// The IDbSet object representing the table to which the rows will be inserted. + /// The entity objects reprsenting the rows that will be inserted. + /// Number of rows in each batch. At the end of each batch, the rows in the batch are sent to the server. Zero means there + /// will be a single batch + /// Number of seconds for the operation to complete before it times out. Zero means no limit. + /// + /// The number of rows inserted. + /// + public static int Insert(this IDbSet dbSet, IEnumerable entities, int batchSize = 1000, int timeout = 0) + where TEntity : class + { + var objects = GetQueryObjects(dbSet); + return ResolveRunner().Insert(objects.Item1, entities, objects.Item2, batchSize, timeout); + } + +#if NET45 + /// + /// Inserts a lof of rows into a database table asynchronously. It must be much faster than executing `DbSet.AddRange` or + /// repetitive `DbSet.Add` method and then executing 'DbContext.SaveChanges' method. + /// + /// The type of objects representing rows to be inserted into db table. + /// The IDbSet object representing the table to which the rows will be inserted. + /// The entity objects reprsenting the rows that will be inserted. + /// Number of rows in each batch. At the end of each batch, the rows in the batch are sent to the server. Zero means there + /// will be a single batch + /// Number of seconds for the operation to complete before it times out. Zero means no limit. + /// + /// The number of rows inserted. + /// + public static async Task InsertAsync(this IDbSet dbSet, IEnumerable entities, int batchSize = 1000, int timeout = 0) + where TEntity : class + { + var objects = GetQueryObjects(dbSet); + return await ResolveRunner().InsertAsync(objects.Item1, entities, objects.Item2, batchSize, timeout); + } #endif - private static IBatchRunner ResolveRunner() + internal static IBatchRunner ResolveRunner() { var provider = Locator.Current.Resolve(); if (provider == null) diff --git a/Source/EntityFramework.Extended/Locator.cs b/Source/EntityFramework.Extended/Locator.cs index 284dd0c..e669053 100644 --- a/Source/EntityFramework.Extended/Locator.cs +++ b/Source/EntityFramework.Extended/Locator.cs @@ -89,6 +89,7 @@ public static void RegisterDefaults(IContainer container) { container.Register(() => new MetadataMappingProvider()); container.Register(() => new SqlServerBatchRunner()); + //container.Register(() => new MySqlBatchRunner()); container.Register(() => new FutureRunner()); container.Register(() => new MemoryCacheProvider()); diff --git a/Source/EntityFramework.Extended/Mapping/MetadataMappingProvider.cs b/Source/EntityFramework.Extended/Mapping/MetadataMappingProvider.cs index 6c9235a..4d8b5b7 100644 --- a/Source/EntityFramework.Extended/Mapping/MetadataMappingProvider.cs +++ b/Source/EntityFramework.Extended/Mapping/MetadataMappingProvider.cs @@ -176,6 +176,7 @@ private static void SetProperties(EntityMap entityMap, EntitySetMapping mapping, if (scalarPropertyMapping != null) { map.ColumnName = scalarPropertyMapping.Column.Name; + map.AutoGeneratedColumn = scalarPropertyMapping.Column.StoreGeneratedPattern != StoreGeneratedPattern.None; continue; } @@ -239,7 +240,7 @@ private static void SetTableName(EntityMap entityMap) private static string QuoteIdentifier(string name) { - return ("[" + name.Replace("]", "]]") + "]"); + return Extensions.BatchExtensions.ResolveRunner().Quote(name); } } } \ No newline at end of file diff --git a/Source/EntityFramework.Extended/Mapping/PropertyMap.cs b/Source/EntityFramework.Extended/Mapping/PropertyMap.cs index abe0d78..d34d8c2 100644 --- a/Source/EntityFramework.Extended/Mapping/PropertyMap.cs +++ b/Source/EntityFramework.Extended/Mapping/PropertyMap.cs @@ -16,5 +16,9 @@ public class PropertyMap /// Gets or sets the name of the column. /// public string ColumnName { get; set; } + /// + /// Is it auto generated column, such as SQL Server Identity column? + /// + public bool AutoGeneratedColumn { get; set; } } } \ No newline at end of file diff --git a/Source/GlobalAssemblyInfo.net40.cs b/Source/GlobalAssemblyInfo.net40.cs index d5ec530..62fcfe6 100644 --- a/Source/GlobalAssemblyInfo.net40.cs +++ b/Source/GlobalAssemblyInfo.net40.cs @@ -11,10 +11,10 @@ [assembly: System.Reflection.AssemblyProduct("EntityFramework.Extended (.NET 4.0)")] [assembly: System.Reflection.AssemblyDescription("Entity Framework extensions library. Built for .NET 4.0")] [assembly: System.Reflection.AssemblyCompany("LoreSoft")] -[assembly: System.Reflection.AssemblyCopyright("Copyright © 2015 LoreSoft")] +[assembly: System.Reflection.AssemblyCopyright("Copyright © 2015 LoreSoft, Modified by AT Mulyana in 2016-2018")] [assembly: System.Reflection.AssemblyVersion("6.0.0.0")] -[assembly: System.Reflection.AssemblyFileVersion("6.1.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersion("6.1.0.0")] +[assembly: System.Reflection.AssemblyFileVersion("6.2.0.4")] +[assembly: System.Reflection.AssemblyInformationalVersion("6.2.0.4")] @@ -26,13 +26,13 @@ internal sealed partial class ThisAssembly { internal const string AssemblyCompany = "LoreSoft"; - internal const string AssemblyCopyright = "Copyright © 2015 LoreSoft"; + internal const string AssemblyCopyright = "Copyright © 2015 LoreSoft, Modified by AT Mulyana in 2016-2018"; internal const string AssemblyVersion = "6.0.0.0"; - internal const string AssemblyFileVersion = "6.1.0.0"; + internal const string AssemblyFileVersion = "6.2.0.4"; - internal const string AssemblyInformationalVersion = "6.1.0.0"; + internal const string AssemblyInformationalVersion = "6.2.0.4"; private ThisAssembly() { } diff --git a/Source/GlobalAssemblyInfo.net45.cs b/Source/GlobalAssemblyInfo.net45.cs index 91700d4..1cbe846 100644 --- a/Source/GlobalAssemblyInfo.net45.cs +++ b/Source/GlobalAssemblyInfo.net45.cs @@ -11,10 +11,10 @@ [assembly: System.Reflection.AssemblyProduct("EntityFramework.Extended (.NET 4.5)")] [assembly: System.Reflection.AssemblyDescription("Entity Framework extensions library. Built for .NET 4.5")] [assembly: System.Reflection.AssemblyCompany("LoreSoft")] -[assembly: System.Reflection.AssemblyCopyright("Copyright © 2015 LoreSoft")] +[assembly: System.Reflection.AssemblyCopyright("Copyright © 2015 LoreSoft, Modified by AT Mulyana in 2016-2018")] [assembly: System.Reflection.AssemblyVersion("6.0.0.0")] -[assembly: System.Reflection.AssemblyFileVersion("6.1.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersion("6.1.0.0")] +[assembly: System.Reflection.AssemblyFileVersion("6.2.0.4")] +[assembly: System.Reflection.AssemblyInformationalVersion("6.2.0.4")] @@ -26,13 +26,13 @@ internal sealed partial class ThisAssembly { internal const string AssemblyCompany = "LoreSoft"; - internal const string AssemblyCopyright = "Copyright © 2015 LoreSoft"; + internal const string AssemblyCopyright = "Copyright © 2015 LoreSoft, Modified by AT Mulyana in 2016-2018"; internal const string AssemblyVersion = "6.0.0.0"; - internal const string AssemblyFileVersion = "6.1.0.0"; + internal const string AssemblyFileVersion = "6.2.0.4"; - internal const string AssemblyInformationalVersion = "6.1.0.0"; + internal const string AssemblyInformationalVersion = "6.2.0.4"; private ThisAssembly() { } diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Audit.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/Audit.cs index 4c21db4..1652bfe 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/Audit.cs +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Audit.cs @@ -1,3 +1,4 @@ + //------------------------------------------------------------------------------ // // This code was generated from a template. @@ -7,23 +8,38 @@ // //------------------------------------------------------------------------------ + namespace Tracker.SqlServer.Entities { - using System; + +using System; using System.Collections.Generic; - public partial class Audit - { - public int Id { get; set; } - public System.DateTime Date { get; set; } - public Nullable UserId { get; set; } - public Nullable TaskId { get; set; } - public string Content { get; set; } - public string Username { get; set; } - public System.DateTime CreatedDate { get; set; } - public byte[] RowVersion { get; set; } - - public virtual Task Task { get; set; } - public virtual User User { get; set; } - } +public partial class Audit +{ + + public int Id { get; set; } + + public System.DateTime Date { get; set; } + + public Nullable UserId { get; set; } + + public Nullable TaskId { get; set; } + + public string Content { get; set; } + + public string Username { get; set; } + + public System.DateTime CreatedDate { get; set; } + + public byte[] RowVersion { get; set; } + + + + public virtual Task Task { get; set; } + + public virtual User User { get; set; } + +} + } diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Item.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/Item.cs new file mode 100644 index 0000000..2256104 --- /dev/null +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Item.cs @@ -0,0 +1,49 @@ + +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + + +namespace Tracker.SqlServer.Entities +{ + +using System; + using System.Collections.Generic; + +public partial class Item +{ + + public string ItemId { get; set; } + + public string ProductId { get; set; } + + public Nullable ListPrice { get; set; } + + public Nullable UnitCost { get; set; } + + public Nullable Supplier { get; set; } + + public string Status { get; set; } + + public string Attr1 { get; set; } + + public string Attr2 { get; set; } + + public string Attr3 { get; set; } + + public string Attr4 { get; set; } + + public string Attr5 { get; set; } + + + + public virtual Product Product { get; set; } + +} + +} diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Item_2.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/Item_2.cs new file mode 100644 index 0000000..52feeaa --- /dev/null +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Item_2.cs @@ -0,0 +1,49 @@ + +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + + +namespace Tracker.SqlServer.Entities +{ + +using System; + using System.Collections.Generic; + +public partial class Item_2 +{ + + public string ItemId { get; set; } + + public string ProductId { get; set; } + + public Nullable ListPrice { get; set; } + + public Nullable UnitCost { get; set; } + + public Nullable Supplier { get; set; } + + public string Status { get; set; } + + public string Attr1 { get; set; } + + public string Attr2 { get; set; } + + public string Attr3 { get; set; } + + public string Attr4 { get; set; } + + public string Attr5 { get; set; } + + + + public virtual Product Product { get; set; } + +} + +} diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Priority.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/Priority.cs index fad1458..8e20972 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/Priority.cs +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Priority.cs @@ -1,3 +1,4 @@ + //------------------------------------------------------------------------------ // // This code was generated from a template. @@ -7,26 +8,42 @@ // //------------------------------------------------------------------------------ + namespace Tracker.SqlServer.Entities { - using System; + +using System; using System.Collections.Generic; - public partial class Priority +public partial class Priority +{ + + public Priority() { - public Priority() - { - this.Tasks = new HashSet(); - } - - public int Id { get; set; } - public string Name { get; set; } - public int Order { get; set; } - public string Description { get; set; } - public System.DateTime CreatedDate { get; set; } - public System.DateTime ModifiedDate { get; set; } - public byte[] RowVersion { get; set; } - - public virtual ICollection Tasks { get; set; } + + this.Tasks = new HashSet(); + } + + + public int Id { get; set; } + + public string Name { get; set; } + + public int Order { get; set; } + + public string Description { get; set; } + + public System.DateTime CreatedDate { get; set; } + + public System.DateTime ModifiedDate { get; set; } + + public byte[] RowVersion { get; set; } + + + + public virtual ICollection Tasks { get; set; } + +} + } diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Product.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/Product.cs new file mode 100644 index 0000000..2366ea0 --- /dev/null +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Product.cs @@ -0,0 +1,47 @@ + +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + + +namespace Tracker.SqlServer.Entities +{ + +using System; + using System.Collections.Generic; + +public partial class Product +{ + + public Product() + { + + this.Items = new HashSet(); + + this.Item_2 = new HashSet(); + + } + + + public string ProductId { get; set; } + + public string Category { get; set; } + + public string Name { get; set; } + + public string Descn { get; set; } + + + + public virtual ICollection Items { get; set; } + + public virtual ICollection Item_2 { get; set; } + +} + +} diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/ProductSummary.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/ProductSummary.cs new file mode 100644 index 0000000..9b8f007 --- /dev/null +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/ProductSummary.cs @@ -0,0 +1,31 @@ + +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + + +namespace Tracker.SqlServer.Entities +{ + +using System; + using System.Collections.Generic; + +public partial class ProductSummary +{ + + public string ProductId { get; set; } + + public string Name { get; set; } + + public decimal AvgPrice { get; set; } + + public bool Verified { get; set; } + +} + +} diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Role.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/Role.cs index 6b2b08f..1619326 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/Role.cs +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Role.cs @@ -1,3 +1,4 @@ + //------------------------------------------------------------------------------ // // This code was generated from a template. @@ -7,25 +8,40 @@ // //------------------------------------------------------------------------------ + namespace Tracker.SqlServer.Entities { - using System; + +using System; using System.Collections.Generic; - public partial class Role +public partial class Role +{ + + public Role() { - public Role() - { - this.Users = new HashSet(); - } - - public int Id { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public System.DateTime CreatedDate { get; set; } - public System.DateTime ModifiedDate { get; set; } - public byte[] RowVersion { get; set; } - - public virtual ICollection Users { get; set; } + + this.Users = new HashSet(); + } + + + public int Id { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + public System.DateTime CreatedDate { get; set; } + + public System.DateTime ModifiedDate { get; set; } + + public byte[] RowVersion { get; set; } + + + + public virtual ICollection Users { get; set; } + +} + } diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Status.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/Status.cs index 2468b9d..e1b566f 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/Status.cs +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Status.cs @@ -1,3 +1,4 @@ + //------------------------------------------------------------------------------ // // This code was generated from a template. @@ -7,26 +8,42 @@ // //------------------------------------------------------------------------------ + namespace Tracker.SqlServer.Entities { - using System; + +using System; using System.Collections.Generic; - public partial class Status +public partial class Status +{ + + public Status() { - public Status() - { - this.Tasks = new HashSet(); - } - - public int Id { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public int Order { get; set; } - public System.DateTime CreatedDate { get; set; } - public System.DateTime ModifiedDate { get; set; } - public byte[] RowVersion { get; set; } - - public virtual ICollection Tasks { get; set; } + + this.Tasks = new HashSet(); + } + + + public int Id { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + public int Order { get; set; } + + public System.DateTime CreatedDate { get; set; } + + public System.DateTime ModifiedDate { get; set; } + + public byte[] RowVersion { get; set; } + + + + public virtual ICollection Tasks { get; set; } + +} + } diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Task.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/Task.cs index cea704c..461c102 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/Task.cs +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Task.cs @@ -1,3 +1,4 @@ + //------------------------------------------------------------------------------ // // This code was generated from a template. @@ -7,38 +8,66 @@ // //------------------------------------------------------------------------------ + namespace Tracker.SqlServer.Entities { - using System; + +using System; using System.Collections.Generic; - public partial class Task +public partial class Task +{ + + public Task() { - public Task() - { - this.Audits = new HashSet(); - } - - public int Id { get; set; } - public int StatusId { get; set; } - public Nullable PriorityId { get; set; } - public int CreatedId { get; set; } - public string Summary { get; set; } - public string Details { get; set; } - public Nullable StartDate { get; set; } - public Nullable DueDate { get; set; } - public Nullable CompleteDate { get; set; } - public Nullable AssignedId { get; set; } - public System.DateTime CreatedDate { get; set; } - public System.DateTime ModifiedDate { get; set; } - public byte[] RowVersion { get; set; } - public string LastModifiedBy { get; set; } - - public virtual ICollection Audits { get; set; } - public virtual Priority Priority { get; set; } - public virtual Status Status { get; set; } - public virtual User User { get; set; } - public virtual User User1 { get; set; } - public virtual TaskExtended TaskExtended { get; set; } + + this.Audits = new HashSet(); + } + + + public int Id { get; set; } + + public int StatusId { get; set; } + + public Nullable PriorityId { get; set; } + + public int CreatedId { get; set; } + + public string Summary { get; set; } + + public string Details { get; set; } + + public Nullable StartDate { get; set; } + + public Nullable DueDate { get; set; } + + public Nullable CompleteDate { get; set; } + + public Nullable AssignedId { get; set; } + + public System.DateTime CreatedDate { get; set; } + + public System.DateTime ModifiedDate { get; set; } + + public byte[] RowVersion { get; set; } + + public string LastModifiedBy { get; set; } + + + + public virtual ICollection Audits { get; set; } + + public virtual Priority Priority { get; set; } + + public virtual Status Status { get; set; } + + public virtual User User { get; set; } + + public virtual User User1 { get; set; } + + public virtual TaskExtended TaskExtended { get; set; } + +} + } diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/TaskExtended.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/TaskExtended.cs index 5f59f9d..4533b5f 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/TaskExtended.cs +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/TaskExtended.cs @@ -1,3 +1,4 @@ + //------------------------------------------------------------------------------ // // This code was generated from a template. @@ -7,20 +8,32 @@ // //------------------------------------------------------------------------------ + namespace Tracker.SqlServer.Entities { - using System; + +using System; using System.Collections.Generic; - public partial class TaskExtended - { - public int TaskId { get; set; } - public string Browser { get; set; } - public string OS { get; set; } - public System.DateTime CreatedDate { get; set; } - public System.DateTime ModifiedDate { get; set; } - public byte[] RowVersion { get; set; } - - public virtual Task Task { get; set; } - } +public partial class TaskExtended +{ + + public int TaskId { get; set; } + + public string Browser { get; set; } + + public string OS { get; set; } + + public System.DateTime CreatedDate { get; set; } + + public System.DateTime ModifiedDate { get; set; } + + public byte[] RowVersion { get; set; } + + + + public virtual Task Task { get; set; } + +} + } diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.Context.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.Context.cs index ccf31f8..b196ef4 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.Context.cs +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.Context.cs @@ -1,4 +1,6 @@ -//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ // // This code was generated from a template. // @@ -7,30 +9,52 @@ // //------------------------------------------------------------------------------ + namespace Tracker.SqlServer.Entities { - using System; - using System.Data.Entity; - using System.Data.Entity.Infrastructure; - - public partial class TrackerEntities : DbContext + +using System; +using System.Data.Entity; +using System.Data.Entity.Infrastructure; + + +public partial class TrackerEntities : DbContext +{ + public TrackerEntities() + : base("name=TrackerEntities") { - public TrackerEntities() - : base("name=TrackerEntities") - { - } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - throw new UnintentionalCodeFirstException(); - } - - public virtual DbSet Audits { get; set; } - public virtual DbSet Priorities { get; set; } - public virtual DbSet Roles { get; set; } - public virtual DbSet Status { get; set; } - public virtual DbSet Tasks { get; set; } - public virtual DbSet TaskExtendeds { get; set; } - public virtual DbSet Users { get; set; } + + } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + throw new UnintentionalCodeFirstException(); } + + + public virtual DbSet Audits { get; set; } + + public virtual DbSet Priorities { get; set; } + + public virtual DbSet Roles { get; set; } + + public virtual DbSet Status { get; set; } + + public virtual DbSet Tasks { get; set; } + + public virtual DbSet TaskExtendeds { get; set; } + + public virtual DbSet Users { get; set; } + + public virtual DbSet Items { get; set; } + + public virtual DbSet Item_2 { get; set; } + + public virtual DbSet Products { get; set; } + + public virtual DbSet ProductSummaries { get; set; } + } + +} + diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.Designer.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.Designer.cs index 48f2f0b..71f238c 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.Designer.cs +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.Designer.cs @@ -1,4 +1,4 @@ -// T4 code generation is enabled for model 'C:\Projects\github\EntityFramework.Extended\Source\Samples\net40\Tracker.SqlServer.Entities\Tracker.edmx'. +// T4 code generation is enabled for model 'E:\Projects\EntityFramework.Extended\modif\Source\Samples\net40\Tracker.SqlServer.Entities\Tracker.edmx'. // To enable legacy code generation, change the value of the 'Code Generation Strategy' designer // property to 'Legacy ObjectContext'. This property is available in the Properties Window when the model // is open in the designer. diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.SqlServer.Entities.net40.csproj b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.SqlServer.Entities.net40.csproj index b1734e5..e23ec36 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.SqlServer.Entities.net40.csproj +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.SqlServer.Entities.net40.csproj @@ -59,9 +59,21 @@ Tracker.tt + + Tracker.tt + + + Tracker.tt + Tracker.tt + + Tracker.tt + + + Tracker.tt + Tracker.tt diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.cs index 7cc0662..c36263e 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.cs +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.cs @@ -1,4 +1,6 @@ -//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ // // This code was generated from a template. // @@ -7,3 +9,4 @@ // //------------------------------------------------------------------------------ + diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.edmx b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.edmx index b55f266..1e8559c 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.edmx +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.edmx @@ -4,7 +4,7 @@ - + @@ -18,6 +18,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -30,6 +62,24 @@ + + + + + + + + + + + + + + + + + + @@ -112,6 +162,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -222,13 +296,25 @@ + + + + + + + + + + + + @@ -266,8 +352,7 @@ - - + @@ -514,7 +599,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -635,6 +810,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.edmx.diagram b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.edmx.diagram index 80b310d..d2bcfda 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.edmx.diagram +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.edmx.diagram @@ -4,7 +4,7 @@ - + @@ -20,6 +20,12 @@ + + + + + + diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/User.cs b/Source/Samples/net40/Tracker.SqlServer.Entities/User.cs index 725ec8d..71b871c 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/User.cs +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/User.cs @@ -1,3 +1,4 @@ + //------------------------------------------------------------------------------ // // This code was generated from a template. @@ -7,41 +8,72 @@ // //------------------------------------------------------------------------------ + namespace Tracker.SqlServer.Entities { - using System; + +using System; using System.Collections.Generic; - public partial class User +public partial class User +{ + + public User() { - public User() - { - this.Audits = new HashSet(); - this.Tasks = new HashSet(); - this.Tasks1 = new HashSet(); - this.Roles = new HashSet(); - } - - public int Id { get; set; } - public string EmailAddress { get; set; } - public string FirstName { get; set; } - public string LastName { get; set; } - public byte[] Avatar { get; set; } - public System.DateTime CreatedDate { get; set; } - public System.DateTime ModifiedDate { get; set; } - public byte[] RowVersion { get; set; } - public string PasswordHash { get; set; } - public string PasswordSalt { get; set; } - public string Comment { get; set; } - public bool IsApproved { get; set; } - public Nullable LastLoginDate { get; set; } - public System.DateTime LastActivityDate { get; set; } - public Nullable LastPasswordChangeDate { get; set; } - public string AvatarType { get; set; } - - public virtual ICollection Audits { get; set; } - public virtual ICollection Tasks { get; set; } - public virtual ICollection Tasks1 { get; set; } - public virtual ICollection Roles { get; set; } + + this.Audits = new HashSet(); + + this.Tasks = new HashSet(); + + this.Tasks1 = new HashSet(); + + this.Roles = new HashSet(); + } + + + public int Id { get; set; } + + public string EmailAddress { get; set; } + + public string FirstName { get; set; } + + public string LastName { get; set; } + + public byte[] Avatar { get; set; } + + public System.DateTime CreatedDate { get; set; } + + public System.DateTime ModifiedDate { get; set; } + + public byte[] RowVersion { get; set; } + + public string PasswordHash { get; set; } + + public string PasswordSalt { get; set; } + + public string Comment { get; set; } + + public bool IsApproved { get; set; } + + public Nullable LastLoginDate { get; set; } + + public System.DateTime LastActivityDate { get; set; } + + public Nullable LastPasswordChangeDate { get; set; } + + public string AvatarType { get; set; } + + + + public virtual ICollection Audits { get; set; } + + public virtual ICollection Tasks { get; set; } + + public virtual ICollection Tasks1 { get; set; } + + public virtual ICollection Roles { get; set; } + +} + } diff --git a/Source/Samples/net40/Tracker.SqlServer.Test/ExtensionTest.cs b/Source/Samples/net40/Tracker.SqlServer.Test/ExtensionTest.cs index 11dd2d0..44be2c0 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Test/ExtensionTest.cs +++ b/Source/Samples/net40/Tracker.SqlServer.Test/ExtensionTest.cs @@ -70,5 +70,171 @@ public void TransactionScopeObjectContext() } } + + private void _Insert(TrackerEntities db) + { + db.Database.Log = s => System.Diagnostics.Debug.WriteLine(s); + db.ProductSummaries.Delete(); + var query = from product in db.Products + join item2 in ( + from item in db.Items + group item by item.ProductId into grItem + select new + { + ProductId = grItem.Key, + AvgPrice = grItem.Average(x => x.ListPrice + x.UnitCost) + } + ) on product.ProductId equals item2.ProductId into items + from item3 in items.DefaultIfEmpty() + select new ProductSummary2 + { + ProductId = product.ProductId, + Name = product.Name, + AvgPrice = item3.AvgPrice ?? 0 + }; + db.ProductSummaries.Insert(query); + var source = query.ToArray(); + var result = db.ProductSummaries.ToArray(); + for (int i = 0; i < source.Length; i++) + { + source[i].AvgPrice = Math.Round(source[i].AvgPrice, 2, MidpointRounding.AwayFromZero); //In database, only two digits after decimal point + source[i].Verified = true; //Verified was not set in query. In database, its default value is true (1) + } + Assert.True(result.OrderBy(i => i.ProductId).SequenceEqual(source.OrderBy(i => i.ProductId), new ProductSummaryComparer())); + + db.Item_2.Delete(); + var query2 = db.Items.Where(item => item.ListPrice / item.UnitCost >= 5); + db.Item_2.Insert(query2); + var source2 = query2.ToArray().OrderBy(i => i.ItemId); + var result2 = db.Item_2.ToArray().Select(i => ItemComparer.GetItem(i)).OrderBy(i => i.ItemId); + Assert.True(result2.SequenceEqual(source2, new ItemComparer())); + + + db.Item_2.Delete(); + var query3 = from item in db.Items where item.ProductId == "K9-RT-02" select item; + db.Item_2.Insert(query3); + var source3 = query3.ToArray().OrderBy(item => item.ItemId); + var result3 = db.Item_2.ToArray().Select(i => ItemComparer.GetItem(i)).OrderBy(item => item.ItemId); + Assert.True(result3.SequenceEqual(source3, new ItemComparer())); + } + + [Fact] + public void InsertNoTransaction() + { + using (var db = new TrackerEntities()) + { + _Insert(db); + } + } + + [Fact] + public void InsertInTransaction() + { + using (var db = new TrackerEntities()) + using (var tx = db.Database.BeginTransaction()) + { + _Insert(db); + tx.Commit(); + } + } + + [Fact] + public void InsertInTransactionScope() + { + using (var tx = new TransactionScope()) + using (var db = new TrackerEntities()) + { + _Insert(db); + tx.Complete(); + } + } + } + + class ProductSummary2 : ProductSummary { } + + class ProductSummaryComparer : IEqualityComparer, System.Collections.IComparer + { + public int Compare(object x, object y) + { + if (x == null && y == null) return 0; + var x2 = x as ProductSummary; + var y2 = y as ProductSummary; + if (x2 != null && y2 != null) + { + if (x2.ProductId == y2.ProductId + && x2.Name == y2.Name + && x2.AvgPrice == y2.AvgPrice + && x2.Verified == y2.Verified) + return 0; + } + return -1; + } + + public bool Equals(ProductSummary x, ProductSummary y) + { + return Compare(x, y) == 0; + } + + public int GetHashCode(ProductSummary obj) + { + if (obj == null) return 0; + return obj.ProductId.GetHashCode(); + } + } + + class ItemComparer : IEqualityComparer, System.Collections.IComparer + { + public int Compare(object x, object y) + { + if (x == null && y == null) return 0; + if (x == null || y == null) return -1; + Item item = GetItem(x), item2 = GetItem(y); + if (item.ItemId == item2.ItemId + && item.ProductId == item2.ProductId + && item.ListPrice == item2.ListPrice + && item.UnitCost == item2.UnitCost + && item.Supplier == item2.Supplier + && item.Status == item2.Status + && item.Attr1 == item2.Attr1 + && item.Attr2 == item2.Attr2 + && item.Attr3 == item2.Attr3 + && item.Attr4 == item2.Attr4 + && item.Attr5 == item2.Attr5) return 0; + return -1; + } + + public bool Equals(Item x, Item y) + { + return Compare(x, y) == 0; + } + + public int GetHashCode(Item obj) + { + return obj.ItemId.GetHashCode(); + } + + public static Item GetItem(object obj) + { + if (obj is Item) return obj as Item; + if (obj is Item_2) + { + var item2 = obj as Item_2; + return new Item + { + ItemId = item2.ItemId, + ProductId = item2.ProductId, + ListPrice = item2.ListPrice, + UnitCost = item2.UnitCost, + Supplier = item2.Supplier, + Status = item2.Status, + Attr1 = item2.Attr1, + Attr2 = item2.Attr2, + Attr3 = item2.Attr3, + Attr4 = item2.Attr4, + Attr5 = item2.Attr5 + }; + } + return null; + } } } diff --git a/Source/Samples/net40/Tracker.SqlServer.Test/Tracker.SqlServer.Test.net40.csproj b/Source/Samples/net40/Tracker.SqlServer.Test/Tracker.SqlServer.Test.net40.csproj index 1295e6a..944dc16 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Test/Tracker.SqlServer.Test.net40.csproj +++ b/Source/Samples/net40/Tracker.SqlServer.Test/Tracker.SqlServer.Test.net40.csproj @@ -117,6 +117,9 @@ + + + + \ No newline at end of file diff --git a/Source/Samples/net45/Tracker.MySql.Entities/Tracker.cs b/Source/Samples/net45/Tracker.MySql.Entities/Tracker.cs new file mode 100644 index 0000000..7cc0662 --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/Tracker.cs @@ -0,0 +1,9 @@ +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + diff --git a/Source/Samples/net45/Tracker.MySql.Entities/Tracker.edmx b/Source/Samples/net45/Tracker.MySql.Entities/Tracker.edmx new file mode 100644 index 0000000..a85e3fd --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/Tracker.edmx @@ -0,0 +1,832 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Samples/net45/Tracker.MySql.Entities/Tracker.edmx.diagram b/Source/Samples/net45/Tracker.MySql.Entities/Tracker.edmx.diagram new file mode 100644 index 0000000..41ce5d7 --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/Tracker.edmx.diagram @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Samples/net45/Tracker.MySql.Entities/Tracker.tt b/Source/Samples/net45/Tracker.MySql.Entities/Tracker.tt new file mode 100644 index 0000000..b856ae3 --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/Tracker.tt @@ -0,0 +1,733 @@ +<#@ template language="C#" debug="false" hostspecific="true"#> +<#@ include file="EF6.Utility.CS.ttinclude"#><#@ + output extension=".cs"#><# + +const string inputFile = @"Tracker.edmx"; +var textTransform = DynamicTextTransformation.Create(this); +var code = new CodeGenerationTools(this); +var ef = new MetadataTools(this); +var typeMapper = new TypeMapper(code, ef, textTransform.Errors); +var fileManager = EntityFrameworkTemplateFileManager.Create(this); +var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile); +var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef); + +if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile)) +{ + return string.Empty; +} + +WriteHeader(codeStringGenerator, fileManager); + +foreach (var entity in typeMapper.GetItemsToGenerate(itemCollection)) +{ + fileManager.StartNewFile(entity.Name + ".cs"); + BeginNamespace(code); +#> +<#=codeStringGenerator.UsingDirectives(inHeader: false)#> +<#=codeStringGenerator.EntityClassOpening(entity)#> +{ +<# + var propertiesWithDefaultValues = typeMapper.GetPropertiesWithDefaultValues(entity); + var collectionNavigationProperties = typeMapper.GetCollectionNavigationProperties(entity); + var complexProperties = typeMapper.GetComplexProperties(entity); + + if (propertiesWithDefaultValues.Any() || collectionNavigationProperties.Any() || complexProperties.Any()) + { +#> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] + public <#=code.Escape(entity)#>() + { +<# + foreach (var edmProperty in propertiesWithDefaultValues) + { +#> + this.<#=code.Escape(edmProperty)#> = <#=typeMapper.CreateLiteral(edmProperty.DefaultValue)#>; +<# + } + + foreach (var navigationProperty in collectionNavigationProperties) + { +#> + this.<#=code.Escape(navigationProperty)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>(); +<# + } + + foreach (var complexProperty in complexProperties) + { +#> + this.<#=code.Escape(complexProperty)#> = new <#=typeMapper.GetTypeName(complexProperty.TypeUsage)#>(); +<# + } +#> + } + +<# + } + + var simpleProperties = typeMapper.GetSimpleProperties(entity); + if (simpleProperties.Any()) + { + foreach (var edmProperty in simpleProperties) + { +#> + <#=codeStringGenerator.Property(edmProperty)#> +<# + } + } + + if (complexProperties.Any()) + { +#> + +<# + foreach(var complexProperty in complexProperties) + { +#> + <#=codeStringGenerator.Property(complexProperty)#> +<# + } + } + + var navigationProperties = typeMapper.GetNavigationProperties(entity); + if (navigationProperties.Any()) + { +#> + +<# + foreach (var navigationProperty in navigationProperties) + { + if (navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many) + { +#> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] +<# + } +#> + <#=codeStringGenerator.NavigationProperty(navigationProperty)#> +<# + } + } +#> +} +<# + EndNamespace(code); +} + +foreach (var complex in typeMapper.GetItemsToGenerate(itemCollection)) +{ + fileManager.StartNewFile(complex.Name + ".cs"); + BeginNamespace(code); +#> +<#=codeStringGenerator.UsingDirectives(inHeader: false, includeCollections: false)#> +<#=Accessibility.ForType(complex)#> partial class <#=code.Escape(complex)#> +{ +<# + var complexProperties = typeMapper.GetComplexProperties(complex); + var propertiesWithDefaultValues = typeMapper.GetPropertiesWithDefaultValues(complex); + + if (propertiesWithDefaultValues.Any() || complexProperties.Any()) + { +#> + public <#=code.Escape(complex)#>() + { +<# + foreach (var edmProperty in propertiesWithDefaultValues) + { +#> + this.<#=code.Escape(edmProperty)#> = <#=typeMapper.CreateLiteral(edmProperty.DefaultValue)#>; +<# + } + + foreach (var complexProperty in complexProperties) + { +#> + this.<#=code.Escape(complexProperty)#> = new <#=typeMapper.GetTypeName(complexProperty.TypeUsage)#>(); +<# + } +#> + } + +<# + } + + var simpleProperties = typeMapper.GetSimpleProperties(complex); + if (simpleProperties.Any()) + { + foreach(var edmProperty in simpleProperties) + { +#> + <#=codeStringGenerator.Property(edmProperty)#> +<# + } + } + + if (complexProperties.Any()) + { +#> + +<# + foreach(var edmProperty in complexProperties) + { +#> + <#=codeStringGenerator.Property(edmProperty)#> +<# + } + } +#> +} +<# + EndNamespace(code); +} + +foreach (var enumType in typeMapper.GetEnumItemsToGenerate(itemCollection)) +{ + fileManager.StartNewFile(enumType.Name + ".cs"); + BeginNamespace(code); +#> +<#=codeStringGenerator.UsingDirectives(inHeader: false, includeCollections: false)#> +<# + if (typeMapper.EnumIsFlags(enumType)) + { +#> +[Flags] +<# + } +#> +<#=codeStringGenerator.EnumOpening(enumType)#> +{ +<# + var foundOne = false; + + foreach (MetadataItem member in typeMapper.GetEnumMembers(enumType)) + { + foundOne = true; +#> + <#=code.Escape(typeMapper.GetEnumMemberName(member))#> = <#=typeMapper.GetEnumMemberValue(member)#>, +<# + } + + if (foundOne) + { + this.GenerationEnvironment.Remove(this.GenerationEnvironment.Length - 3, 1); + } +#> +} +<# + EndNamespace(code); +} + +fileManager.Process(); + +#> +<#+ + +public void WriteHeader(CodeStringGenerator codeStringGenerator, EntityFrameworkTemplateFileManager fileManager) +{ + fileManager.StartHeader(); +#> +//------------------------------------------------------------------------------ +// +// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine1")#> +// +// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine2")#> +// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine3")#> +// +//------------------------------------------------------------------------------ +<#=codeStringGenerator.UsingDirectives(inHeader: true)#> +<#+ + fileManager.EndBlock(); +} + +public void BeginNamespace(CodeGenerationTools code) +{ + var codeNamespace = code.VsNamespaceSuggestion(); + if (!String.IsNullOrEmpty(codeNamespace)) + { +#> +namespace <#=code.EscapeNamespace(codeNamespace)#> +{ +<#+ + PushIndent(" "); + } +} + +public void EndNamespace(CodeGenerationTools code) +{ + if (!String.IsNullOrEmpty(code.VsNamespaceSuggestion())) + { + PopIndent(); +#> +} +<#+ + } +} + +public const string TemplateId = "CSharp_DbContext_Types_EF6"; + +public class CodeStringGenerator +{ + private readonly CodeGenerationTools _code; + private readonly TypeMapper _typeMapper; + private readonly MetadataTools _ef; + + public CodeStringGenerator(CodeGenerationTools code, TypeMapper typeMapper, MetadataTools ef) + { + ArgumentNotNull(code, "code"); + ArgumentNotNull(typeMapper, "typeMapper"); + ArgumentNotNull(ef, "ef"); + + _code = code; + _typeMapper = typeMapper; + _ef = ef; + } + + public string Property(EdmProperty edmProperty) + { + return string.Format( + CultureInfo.InvariantCulture, + "{0} {1} {2} {{ {3}get; {4}set; }}", + Accessibility.ForProperty(edmProperty), + _typeMapper.GetTypeName(edmProperty.TypeUsage), + _code.Escape(edmProperty), + _code.SpaceAfter(Accessibility.ForGetter(edmProperty)), + _code.SpaceAfter(Accessibility.ForSetter(edmProperty))); + } + + public string NavigationProperty(NavigationProperty navProp) + { + var endType = _typeMapper.GetTypeName(navProp.ToEndMember.GetEntityType()); + return string.Format( + CultureInfo.InvariantCulture, + "{0} {1} {2} {{ {3}get; {4}set; }}", + AccessibilityAndVirtual(Accessibility.ForNavigationProperty(navProp)), + navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType, + _code.Escape(navProp), + _code.SpaceAfter(Accessibility.ForGetter(navProp)), + _code.SpaceAfter(Accessibility.ForSetter(navProp))); + } + + public string AccessibilityAndVirtual(string accessibility) + { + return accessibility + (accessibility != "private" ? " virtual" : ""); + } + + public string EntityClassOpening(EntityType entity) + { + return string.Format( + CultureInfo.InvariantCulture, + "{0} {1}partial class {2}{3}", + Accessibility.ForType(entity), + _code.SpaceAfter(_code.AbstractOption(entity)), + _code.Escape(entity), + _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType))); + } + + public string EnumOpening(SimpleType enumType) + { + return string.Format( + CultureInfo.InvariantCulture, + "{0} enum {1} : {2}", + Accessibility.ForType(enumType), + _code.Escape(enumType), + _code.Escape(_typeMapper.UnderlyingClrType(enumType))); + } + + public void WriteFunctionParameters(EdmFunction edmFunction, Action writeParameter) + { + var parameters = FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef); + foreach (var parameter in parameters.Where(p => p.NeedsLocalVariable)) + { + var isNotNull = parameter.IsNullableOfT ? parameter.FunctionParameterName + ".HasValue" : parameter.FunctionParameterName + " != null"; + var notNullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", " + parameter.FunctionParameterName + ")"; + var nullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", typeof(" + TypeMapper.FixNamespaces(parameter.RawClrTypeName) + "))"; + writeParameter(parameter.LocalVariableName, isNotNull, notNullInit, nullInit); + } + } + + public string ComposableFunctionMethod(EdmFunction edmFunction, string modelNamespace) + { + var parameters = _typeMapper.GetParameters(edmFunction); + + return string.Format( + CultureInfo.InvariantCulture, + "{0} IQueryable<{1}> {2}({3})", + AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)), + _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace), + _code.Escape(edmFunction), + string.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray())); + } + + public string ComposableCreateQuery(EdmFunction edmFunction, string modelNamespace) + { + var parameters = _typeMapper.GetParameters(edmFunction); + + return string.Format( + CultureInfo.InvariantCulture, + "return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<{0}>(\"[{1}].[{2}]({3})\"{4});", + _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace), + edmFunction.NamespaceName, + edmFunction.Name, + string.Join(", ", parameters.Select(p => "@" + p.EsqlParameterName).ToArray()), + _code.StringBefore(", ", string.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray()))); + } + + public string FunctionMethod(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption) + { + var parameters = _typeMapper.GetParameters(edmFunction); + var returnType = _typeMapper.GetReturnType(edmFunction); + + var paramList = String.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray()); + if (includeMergeOption) + { + paramList = _code.StringAfter(paramList, ", ") + "MergeOption mergeOption"; + } + + return string.Format( + CultureInfo.InvariantCulture, + "{0} {1} {2}({3})", + AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)), + returnType == null ? "int" : "ObjectResult<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">", + _code.Escape(edmFunction), + paramList); + } + + public string ExecuteFunction(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption) + { + var parameters = _typeMapper.GetParameters(edmFunction); + var returnType = _typeMapper.GetReturnType(edmFunction); + + var callParams = _code.StringBefore(", ", String.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray())); + if (includeMergeOption) + { + callParams = ", mergeOption" + callParams; + } + + return string.Format( + CultureInfo.InvariantCulture, + "return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction{0}(\"{1}\"{2});", + returnType == null ? "" : "<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">", + edmFunction.Name, + callParams); + } + + public string DbSet(EntitySet entitySet) + { + return string.Format( + CultureInfo.InvariantCulture, + "{0} virtual DbSet<{1}> {2} {{ get; set; }}", + Accessibility.ForReadOnlyProperty(entitySet), + _typeMapper.GetTypeName(entitySet.ElementType), + _code.Escape(entitySet)); + } + + public string UsingDirectives(bool inHeader, bool includeCollections = true) + { + return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion()) + ? string.Format( + CultureInfo.InvariantCulture, + "{0}using System;{1}" + + "{2}", + inHeader ? Environment.NewLine : "", + includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "", + inHeader ? "" : Environment.NewLine) + : ""; + } +} + +public class TypeMapper +{ + private const string ExternalTypeNameAttributeName = @"http://schemas.microsoft.com/ado/2006/04/codegeneration:ExternalTypeName"; + + private readonly System.Collections.IList _errors; + private readonly CodeGenerationTools _code; + private readonly MetadataTools _ef; + + public TypeMapper(CodeGenerationTools code, MetadataTools ef, System.Collections.IList errors) + { + ArgumentNotNull(code, "code"); + ArgumentNotNull(ef, "ef"); + ArgumentNotNull(errors, "errors"); + + _code = code; + _ef = ef; + _errors = errors; + } + + public static string FixNamespaces(string typeName) + { + return typeName.Replace("System.Data.Spatial.", "System.Data.Entity.Spatial."); + } + + public string GetTypeName(TypeUsage typeUsage) + { + return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace: null); + } + + public string GetTypeName(EdmType edmType) + { + return GetTypeName(edmType, isNullable: null, modelNamespace: null); + } + + public string GetTypeName(TypeUsage typeUsage, string modelNamespace) + { + return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace); + } + + public string GetTypeName(EdmType edmType, string modelNamespace) + { + return GetTypeName(edmType, isNullable: null, modelNamespace: modelNamespace); + } + + public string GetTypeName(EdmType edmType, bool? isNullable, string modelNamespace) + { + if (edmType == null) + { + return null; + } + + var collectionType = edmType as CollectionType; + if (collectionType != null) + { + return String.Format(CultureInfo.InvariantCulture, "ICollection<{0}>", GetTypeName(collectionType.TypeUsage, modelNamespace)); + } + + var typeName = _code.Escape(edmType.MetadataProperties + .Where(p => p.Name == ExternalTypeNameAttributeName) + .Select(p => (string)p.Value) + .FirstOrDefault()) + ?? (modelNamespace != null && edmType.NamespaceName != modelNamespace ? + _code.CreateFullName(_code.EscapeNamespace(edmType.NamespaceName), _code.Escape(edmType)) : + _code.Escape(edmType)); + + if (edmType is StructuralType) + { + return typeName; + } + + if (edmType is SimpleType) + { + var clrType = UnderlyingClrType(edmType); + if (!IsEnumType(edmType)) + { + typeName = _code.Escape(clrType); + } + + typeName = FixNamespaces(typeName); + + return clrType.IsValueType && isNullable == true ? + String.Format(CultureInfo.InvariantCulture, "Nullable<{0}>", typeName) : + typeName; + } + + throw new ArgumentException("edmType"); + } + + public Type UnderlyingClrType(EdmType edmType) + { + ArgumentNotNull(edmType, "edmType"); + + var primitiveType = edmType as PrimitiveType; + if (primitiveType != null) + { + return primitiveType.ClrEquivalentType; + } + + if (IsEnumType(edmType)) + { + return GetEnumUnderlyingType(edmType).ClrEquivalentType; + } + + return typeof(object); + } + + public object GetEnumMemberValue(MetadataItem enumMember) + { + ArgumentNotNull(enumMember, "enumMember"); + + var valueProperty = enumMember.GetType().GetProperty("Value"); + return valueProperty == null ? null : valueProperty.GetValue(enumMember, null); + } + + public string GetEnumMemberName(MetadataItem enumMember) + { + ArgumentNotNull(enumMember, "enumMember"); + + var nameProperty = enumMember.GetType().GetProperty("Name"); + return nameProperty == null ? null : (string)nameProperty.GetValue(enumMember, null); + } + + public System.Collections.IEnumerable GetEnumMembers(EdmType enumType) + { + ArgumentNotNull(enumType, "enumType"); + + var membersProperty = enumType.GetType().GetProperty("Members"); + return membersProperty != null + ? (System.Collections.IEnumerable)membersProperty.GetValue(enumType, null) + : Enumerable.Empty(); + } + + public bool EnumIsFlags(EdmType enumType) + { + ArgumentNotNull(enumType, "enumType"); + + var isFlagsProperty = enumType.GetType().GetProperty("IsFlags"); + return isFlagsProperty != null && (bool)isFlagsProperty.GetValue(enumType, null); + } + + public bool IsEnumType(GlobalItem edmType) + { + ArgumentNotNull(edmType, "edmType"); + + return edmType.GetType().Name == "EnumType"; + } + + public PrimitiveType GetEnumUnderlyingType(EdmType enumType) + { + ArgumentNotNull(enumType, "enumType"); + + return (PrimitiveType)enumType.GetType().GetProperty("UnderlyingType").GetValue(enumType, null); + } + + public string CreateLiteral(object value) + { + if (value == null || value.GetType() != typeof(TimeSpan)) + { + return _code.CreateLiteral(value); + } + + return string.Format(CultureInfo.InvariantCulture, "new TimeSpan({0})", ((TimeSpan)value).Ticks); + } + + public bool VerifyCaseInsensitiveTypeUniqueness(IEnumerable types, string sourceFile) + { + ArgumentNotNull(types, "types"); + ArgumentNotNull(sourceFile, "sourceFile"); + + var hash = new HashSet(StringComparer.InvariantCultureIgnoreCase); + if (types.Any(item => !hash.Add(item))) + { + _errors.Add( + new CompilerError(sourceFile, -1, -1, "6023", + String.Format(CultureInfo.CurrentCulture, CodeGenerationTools.GetResourceString("Template_CaseInsensitiveTypeConflict")))); + return false; + } + return true; + } + + public IEnumerable GetEnumItemsToGenerate(IEnumerable itemCollection) + { + return GetItemsToGenerate(itemCollection) + .Where(e => IsEnumType(e)); + } + + public IEnumerable GetItemsToGenerate(IEnumerable itemCollection) where T: EdmType + { + return itemCollection + .OfType() + .Where(i => !i.MetadataProperties.Any(p => p.Name == ExternalTypeNameAttributeName)) + .OrderBy(i => i.Name); + } + + public IEnumerable GetAllGlobalItems(IEnumerable itemCollection) + { + return itemCollection + .Where(i => i is EntityType || i is ComplexType || i is EntityContainer || IsEnumType(i)) + .Select(g => GetGlobalItemName(g)); + } + + public string GetGlobalItemName(GlobalItem item) + { + if (item is EdmType) + { + return ((EdmType)item).Name; + } + else + { + return ((EntityContainer)item).Name; + } + } + + public IEnumerable GetSimpleProperties(EntityType type) + { + return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type); + } + + public IEnumerable GetSimpleProperties(ComplexType type) + { + return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type); + } + + public IEnumerable GetComplexProperties(EntityType type) + { + return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type); + } + + public IEnumerable GetComplexProperties(ComplexType type) + { + return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type); + } + + public IEnumerable GetPropertiesWithDefaultValues(EntityType type) + { + return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null); + } + + public IEnumerable GetPropertiesWithDefaultValues(ComplexType type) + { + return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null); + } + + public IEnumerable GetNavigationProperties(EntityType type) + { + return type.NavigationProperties.Where(np => np.DeclaringType == type); + } + + public IEnumerable GetCollectionNavigationProperties(EntityType type) + { + return type.NavigationProperties.Where(np => np.DeclaringType == type && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many); + } + + public FunctionParameter GetReturnParameter(EdmFunction edmFunction) + { + ArgumentNotNull(edmFunction, "edmFunction"); + + var returnParamsProperty = edmFunction.GetType().GetProperty("ReturnParameters"); + return returnParamsProperty == null + ? edmFunction.ReturnParameter + : ((IEnumerable)returnParamsProperty.GetValue(edmFunction, null)).FirstOrDefault(); + } + + public bool IsComposable(EdmFunction edmFunction) + { + ArgumentNotNull(edmFunction, "edmFunction"); + + var isComposableProperty = edmFunction.GetType().GetProperty("IsComposableAttribute"); + return isComposableProperty != null && (bool)isComposableProperty.GetValue(edmFunction, null); + } + + public IEnumerable GetParameters(EdmFunction edmFunction) + { + return FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef); + } + + public TypeUsage GetReturnType(EdmFunction edmFunction) + { + var returnParam = GetReturnParameter(edmFunction); + return returnParam == null ? null : _ef.GetElementType(returnParam.TypeUsage); + } + + public bool GenerateMergeOptionFunction(EdmFunction edmFunction, bool includeMergeOption) + { + var returnType = GetReturnType(edmFunction); + return !includeMergeOption && returnType != null && returnType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType; + } +} + +public static void ArgumentNotNull(T arg, string name) where T : class +{ + if (arg == null) + { + throw new ArgumentNullException(name); + } +} +#> \ No newline at end of file diff --git a/Source/Samples/net45/Tracker.MySql.Entities/app.config b/Source/Samples/net45/Tracker.MySql.Entities/app.config new file mode 100644 index 0000000..255c75b --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/app.config @@ -0,0 +1,34 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Samples/net45/Tracker.MySql.Entities/audit.cs b/Source/Samples/net45/Tracker.MySql.Entities/audit.cs new file mode 100644 index 0000000..754ead6 --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/audit.cs @@ -0,0 +1,29 @@ +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tracker.MySql.Entities +{ + using System; + using System.Collections.Generic; + + public partial class audit + { + public int Id { get; set; } + public System.DateTime Date { get; set; } + public Nullable UserId { get; set; } + public Nullable TaskId { get; set; } + public string Content { get; set; } + public string Username { get; set; } + public System.DateTime CreatedDate { get; set; } + public byte[] RowVersion { get; set; } + + public virtual task task { get; set; } + public virtual user user { get; set; } + } +} diff --git a/Source/Samples/net45/Tracker.MySql.Entities/item.cs b/Source/Samples/net45/Tracker.MySql.Entities/item.cs new file mode 100644 index 0000000..db0847c --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/item.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tracker.MySql.Entities +{ + using System; + using System.Collections.Generic; + + public partial class item + { + public string ItemId { get; set; } + public string ProductId { get; set; } + public Nullable ListPrice { get; set; } + public Nullable UnitCost { get; set; } + public Nullable Supplier { get; set; } + public string Status { get; set; } + public string Attr1 { get; set; } + public string Attr2 { get; set; } + public string Attr3 { get; set; } + public string Attr4 { get; set; } + public string Attr5 { get; set; } + + public virtual product product { get; set; } + } +} diff --git a/Source/Samples/net45/Tracker.MySql.Entities/item_2.cs b/Source/Samples/net45/Tracker.MySql.Entities/item_2.cs new file mode 100644 index 0000000..dc42fdb --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/item_2.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tracker.MySql.Entities +{ + using System; + using System.Collections.Generic; + + public partial class item_2 + { + public string ItemId { get; set; } + public string ProductId { get; set; } + public Nullable ListPrice { get; set; } + public Nullable UnitCost { get; set; } + public Nullable Supplier { get; set; } + public string Status { get; set; } + public string Attr1 { get; set; } + public string Attr2 { get; set; } + public string Attr3 { get; set; } + public string Attr4 { get; set; } + public string Attr5 { get; set; } + + public virtual product product { get; set; } + } +} diff --git a/Source/Samples/net45/Tracker.MySql.Entities/packages.config b/Source/Samples/net45/Tracker.MySql.Entities/packages.config new file mode 100644 index 0000000..b3b1903 --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Source/Samples/net45/Tracker.MySql.Entities/priority.cs b/Source/Samples/net45/Tracker.MySql.Entities/priority.cs new file mode 100644 index 0000000..815797a --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/priority.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tracker.MySql.Entities +{ + using System; + using System.Collections.Generic; + + public partial class priority + { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] + public priority() + { + this.tasks = new HashSet(); + } + + public int Id { get; set; } + public string Name { get; set; } + public int Order { get; set; } + public string Description { get; set; } + public System.DateTime CreatedDate { get; set; } + public System.DateTime ModifiedDate { get; set; } + public byte[] RowVersion { get; set; } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection tasks { get; set; } + } +} diff --git a/Source/Samples/net45/Tracker.MySql.Entities/product.cs b/Source/Samples/net45/Tracker.MySql.Entities/product.cs new file mode 100644 index 0000000..54d674d --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/product.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tracker.MySql.Entities +{ + using System; + using System.Collections.Generic; + + public partial class product + { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] + public product() + { + this.items = new HashSet(); + this.item_2 = new HashSet(); + } + + public string ProductId { get; set; } + public string Category { get; set; } + public string Name { get; set; } + public string Descn { get; set; } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection items { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection item_2 { get; set; } + } +} diff --git a/Source/Samples/net45/Tracker.MySql.Entities/productsummary.cs b/Source/Samples/net45/Tracker.MySql.Entities/productsummary.cs new file mode 100644 index 0000000..ac8f8e2 --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/productsummary.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tracker.MySql.Entities +{ + using System; + using System.Collections.Generic; + + public partial class productsummary + { + public string ProductId { get; set; } + public string Name { get; set; } + public decimal AvgPrice { get; set; } + public bool Verified { get; set; } + } +} diff --git a/Source/Samples/net45/Tracker.MySql.Entities/role.cs b/Source/Samples/net45/Tracker.MySql.Entities/role.cs new file mode 100644 index 0000000..62f638d --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/role.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tracker.MySql.Entities +{ + using System; + using System.Collections.Generic; + + public partial class role + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public System.DateTime CreatedDate { get; set; } + public System.DateTime ModifiedDate { get; set; } + public byte[] RowVersion { get; set; } + } +} diff --git a/Source/Samples/net45/Tracker.MySql.Entities/status.cs b/Source/Samples/net45/Tracker.MySql.Entities/status.cs new file mode 100644 index 0000000..a261c4d --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/status.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tracker.MySql.Entities +{ + using System; + using System.Collections.Generic; + + public partial class status + { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] + public status() + { + this.tasks = new HashSet(); + } + + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public int Order { get; set; } + public System.DateTime CreatedDate { get; set; } + public System.DateTime ModifiedDate { get; set; } + public byte[] RowVersion { get; set; } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection tasks { get; set; } + } +} diff --git a/Source/Samples/net45/Tracker.MySql.Entities/task.cs b/Source/Samples/net45/Tracker.MySql.Entities/task.cs new file mode 100644 index 0000000..dfd000e --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/task.cs @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tracker.MySql.Entities +{ + using System; + using System.Collections.Generic; + + public partial class task + { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] + public task() + { + this.audits = new HashSet(); + } + + public int Id { get; set; } + public int StatusId { get; set; } + public Nullable PriorityId { get; set; } + public int CreatedId { get; set; } + public string Summary { get; set; } + public string Details { get; set; } + public Nullable StartDate { get; set; } + public Nullable DueDate { get; set; } + public Nullable CompleteDate { get; set; } + public Nullable AssignedId { get; set; } + public System.DateTime CreatedDate { get; set; } + public System.DateTime ModifiedDate { get; set; } + public byte[] RowVersion { get; set; } + public string LastModifiedBy { get; set; } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection audits { get; set; } + public virtual priority priority { get; set; } + public virtual status status { get; set; } + public virtual user user { get; set; } + public virtual user user1 { get; set; } + public virtual taskextended taskextended { get; set; } + } +} diff --git a/Source/Samples/net45/Tracker.MySql.Entities/taskextended.cs b/Source/Samples/net45/Tracker.MySql.Entities/taskextended.cs new file mode 100644 index 0000000..6129387 --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/taskextended.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tracker.MySql.Entities +{ + using System; + using System.Collections.Generic; + + public partial class taskextended + { + public int TaskId { get; set; } + public string Browser { get; set; } + public string OS { get; set; } + public System.DateTime CreatedDate { get; set; } + public System.DateTime ModifiedDate { get; set; } + public byte[] RowVersion { get; set; } + + public virtual task task { get; set; } + } +} diff --git a/Source/Samples/net45/Tracker.MySql.Entities/user.cs b/Source/Samples/net45/Tracker.MySql.Entities/user.cs new file mode 100644 index 0000000..e0b6e63 --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Entities/user.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tracker.MySql.Entities +{ + using System; + using System.Collections.Generic; + + public partial class user + { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] + public user() + { + this.audits = new HashSet(); + this.tasks = new HashSet(); + this.tasks1 = new HashSet(); + } + + public int Id { get; set; } + public string EmailAddress { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public byte[] Avatar { get; set; } + public System.DateTime CreatedDate { get; set; } + public System.DateTime ModifiedDate { get; set; } + public byte[] RowVersion { get; set; } + public string PasswordHash { get; set; } + public string PasswordSalt { get; set; } + public string Comment { get; set; } + public bool IsApproved { get; set; } + public Nullable LastLoginDate { get; set; } + public System.DateTime LastActivityDate { get; set; } + public Nullable LastPasswordChangeDate { get; set; } + public string AvatarType { get; set; } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection audits { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection tasks { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection tasks1 { get; set; } + } +} diff --git a/Source/Samples/net45/Tracker.MySql.Test/App.config b/Source/Samples/net45/Tracker.MySql.Test/App.config new file mode 100644 index 0000000..45e8c4d --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Test/App.config @@ -0,0 +1,35 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Samples/net45/Tracker.MySql.Test/ExtensionTest.cs b/Source/Samples/net45/Tracker.MySql.Test/ExtensionTest.cs new file mode 100644 index 0000000..06bc028 --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Test/ExtensionTest.cs @@ -0,0 +1,281 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using EntityFramework.Extensions; +using Xunit; +using Tracker.MySql.Entities; +using EntityFramework; +using EntityFramework.Batch; + +namespace Tracker.MySql.Test +{ + public class ExtensionTest + { + [Fact] + public void BeginTransactionObjectContext() + { + Locator.Current.Register(() => new MySqlBatchRunner()); + try + { + using (var db = new TrackerEntities()) + using (var tx = db.Database.BeginTransaction()) + { + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); + string emailDomain = "@test.com"; + + int count = db.users + .Where(u => u.EmailAddress.EndsWith(emailDomain)) + .Update(u => new user { IsApproved = false, LastActivityDate = DateTime.Now }); + + count = db.users + .Where(u => u.EmailAddress.EndsWith(emailDomain)) + .Delete(); + + tx.Commit(); + } + } + finally + { + Locator.Current.Register(() => new SqlServerBatchRunner()); + } + } + + [Fact] + public void NoTransactionObjectContext() + { + Locator.Current.Register(() => new MySqlBatchRunner()); + try + { + using (var db = new TrackerEntities()) + { + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); + string emailDomain = "@test.com"; + + int count = db.users + .Where(u => u.EmailAddress.EndsWith(emailDomain)) + .Update(u => new user { IsApproved = false, LastActivityDate = DateTime.Now }); + + count = db.users + .Where(u => u.EmailAddress.EndsWith(emailDomain)) + .Delete(); + + } + } + finally + { + Locator.Current.Register(() => new SqlServerBatchRunner()); + } + } + + /*** MySQL seems not to support TransactionScope ***/ + //[Fact] + //public void TransactionScopeObjectContext() + //{ + // using (var tx = new TransactionScope()) + // using (var db = new TrackerEntities()) + // { + // string emailDomain = "@test.com"; + + // int count = db.users + // .Where(u => u.EmailAddress.EndsWith(emailDomain)) + // .Update(u => new user { IsApproved = false, LastActivityDate = DateTime.Now }); + + // count = db.users + // .Where(u => u.EmailAddress.EndsWith(emailDomain)) + // .Delete(); + + // tx.Complete(); + // } + //} + + + private void _Insert(TrackerEntities db, bool isAsync = false) + { + Locator.Current.Register(() => new MySqlBatchRunner()); + try + { + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); + db.productsummaries.Delete(); + var query = from product in db.products + join item2 in ( + from item in db.items + group item by item.ProductId into grItem + select new + { + ProductId = grItem.Key, + AvgPrice = grItem.Average(x => x.ListPrice + x.UnitCost) + } + ) on product.ProductId equals item2.ProductId into items + from item3 in items.DefaultIfEmpty() + select new ProductSummary2 + { + ProductId = product.ProductId, + Name = product.Name, + AvgPrice = item3.AvgPrice ?? 0 + }; + if (isAsync) db.productsummaries.InsertAsync(query).Wait(); + else db.productsummaries.Insert(query); + var source = query.ToArray(); + var result = db.productsummaries.ToArray(); + for (int i = 0; i < source.Length; i++) + { + source[i].AvgPrice = Math.Round(source[i].AvgPrice, 2, MidpointRounding.AwayFromZero); //In database, only two digits after decimal point + source[i].Verified = true; //Verified was not set in query. In database, its default value is true (1) + } + Assert.True(result.OrderBy(i => i.ProductId).SequenceEqual(source.OrderBy(i => i.ProductId), new ProductSummaryComparer())); + + db.item_2.Delete(); + var query2 = db.items.Where(item => item.ListPrice / item.UnitCost >= 5); + if (isAsync) db.item_2.InsertAsync(query2).Wait(); + else db.item_2.Insert(query2); + var source2 = query2.ToArray().OrderBy(i => i.ItemId); + var result2 = db.item_2.ToArray().Select(i => ItemComparer.GetItem(i)).OrderBy(i => i.ItemId); + Assert.True(result2.SequenceEqual(source2, new ItemComparer())); + + + db.item_2.Delete(); + //var query3 = from item in db.items where item.ProductId == "K9-RT-02" select item; //Using MySQL provider, ObjectQuery.Parameters is not filled if its parameter is constant + string productId = "K9-RT-02"; + var query3 = from item in db.items where item.ProductId == productId select item; + if (isAsync) db.item_2.InsertAsync(query3).Wait(); + else db.item_2.Insert(query3); + var source3 = query3.ToArray().OrderBy(item => item.ItemId); + var result3 = db.item_2.ToArray().Select(i => ItemComparer.GetItem(i)).OrderBy(item => item.ItemId); + Assert.True(result3.SequenceEqual(source3, new ItemComparer())); + } + finally + { + Locator.Current.Register(() => new SqlServerBatchRunner()); + } + } + + [Fact] + public void InsertNoTransaction() + { + using (var db = new TrackerEntities()) + { + _Insert(db); + } + } + + [Fact] + public void InsertInTransaction() + { + using (var db = new TrackerEntities()) + using (var tx = db.Database.BeginTransaction()) + { + _Insert(db); + tx.Commit(); + } + } + + /*** MySQL seems not to support TransactionScope ***/ + //[Fact] + //public void InsertInTransactionScope() + //{ + // using (var tx = new TransactionScope()) + // using (var db = new TrackerEntities()) + // { + // _Insert(db); + // tx.Complete(); + // } + //} + + [Fact] + public void InsertAsync() + { + using (var db = new TrackerEntities()) + { + _Insert(db, true); + } + } + } + + class ProductSummary2 : productsummary { } + + class ProductSummaryComparer : IEqualityComparer, System.Collections.IComparer + { + public int Compare(object x, object y) + { + if (x == null && y == null) return 0; + var x2 = x as productsummary; + var y2 = y as productsummary; + if (x2 != null && y2 != null) + { + if (x2.ProductId == y2.ProductId + && x2.Name == y2.Name + && x2.AvgPrice == y2.AvgPrice + && x2.Verified == y2.Verified) + return 0; + } + return -1; + } + + public bool Equals(productsummary x, productsummary y) + { + return Compare(x, y) == 0; + } + + public int GetHashCode(productsummary obj) + { + if (obj == null) return 0; + return obj.ProductId.GetHashCode(); + } + } + + class ItemComparer : IEqualityComparer, System.Collections.IComparer + { + public int Compare(object x, object y) + { + if (x == null && y == null) return 0; + if (x == null || y == null) return -1; + item item = GetItem(x), item2 = GetItem(y); + if (item.ItemId == item2.ItemId + && item.ProductId == item2.ProductId + && item.ListPrice == item2.ListPrice + && item.UnitCost == item2.UnitCost + && item.Supplier == item2.Supplier + && item.Status == item2.Status + && item.Attr1 == item2.Attr1 + && item.Attr2 == item2.Attr2 + && item.Attr3 == item2.Attr3 + && item.Attr4 == item2.Attr4 + && item.Attr5 == item2.Attr5) return 0; + return -1; + } + + public bool Equals(item x, item y) + { + return Compare(x, y) == 0; + } + + public int GetHashCode(item obj) + { + return obj.ItemId.GetHashCode(); + } + + public static item GetItem(object obj) + { + if (obj is item) return obj as item; + if (obj is item_2) + { + var item2 = obj as item_2; + return new item + { + ItemId = item2.ItemId, + ProductId = item2.ProductId, + ListPrice = item2.ListPrice, + UnitCost = item2.UnitCost, + Supplier = item2.Supplier, + Status = item2.Status, + Attr1 = item2.Attr1, + Attr2 = item2.Attr2, + Attr3 = item2.Attr3, + Attr4 = item2.Attr4, + Attr5 = item2.Attr5 + }; + } + return null; + } + } +} diff --git a/Source/Samples/net45/Tracker.MySql.Test/Properties/AssemblyInfo.cs b/Source/Samples/net45/Tracker.MySql.Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3b3f8b6 --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tracker.MySql.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tracker.MySql.Test")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("d8f3c9ee-afd3-4291-96f2-4dbeb842e5aa")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Source/Samples/net45/Tracker.MySql.Test/Tracker.MySql.Test.csproj b/Source/Samples/net45/Tracker.MySql.Test/Tracker.MySql.Test.csproj new file mode 100644 index 0000000..2f7a472 --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Test/Tracker.MySql.Test.csproj @@ -0,0 +1,120 @@ + + + + Debug + AnyCPU + {D8F3C9EE-AFD3-4291-96F2-4DBEB842E5AA} + Library + Properties + Tracker.MySql.Test + Tracker.MySql.Test + v4.5.2 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll + True + + + ..\..\..\packages\MySql.Data.6.9.8\lib\net45\MySql.Data.dll + True + + + ..\..\..\packages\MySql.Data.Entity.6.9.8\lib\net45\MySql.Data.Entity.EF6.dll + True + + + + + + + ..\..\..\packages\xunit.runner.visualstudio.2.1.0\build\_common\xunit.abstractions.dll + + + ..\..\..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll + + + ..\..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll + + + ..\..\..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll + + + + + + + + + + + + + + + + + {d390c235-242c-4e92-9e0b-d2463e87b0f0} + EntityFramework.Extended.net45 + + + {e445e980-4ab0-4012-8929-118b01392393} + Tracker.MySql.Entities + + + + + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file diff --git a/Source/Samples/net45/Tracker.MySql.Test/packages.config b/Source/Samples/net45/Tracker.MySql.Test/packages.config new file mode 100644 index 0000000..a1b2edf --- /dev/null +++ b/Source/Samples/net45/Tracker.MySql.Test/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Source/Samples/net45/Tracker.SqlServer.CodeFirst/App.config b/Source/Samples/net45/Tracker.SqlServer.CodeFirst/App.config index f93390f..062780d 100644 --- a/Source/Samples/net45/Tracker.SqlServer.CodeFirst/App.config +++ b/Source/Samples/net45/Tracker.SqlServer.CodeFirst/App.config @@ -10,7 +10,7 @@ - + diff --git a/Source/Samples/net45/Tracker.SqlServer.CodeFirst/Tracker.SqlServer.CodeFirst.csproj b/Source/Samples/net45/Tracker.SqlServer.CodeFirst/Tracker.SqlServer.CodeFirst.csproj index db31bd7..f101e01 100644 --- a/Source/Samples/net45/Tracker.SqlServer.CodeFirst/Tracker.SqlServer.CodeFirst.csproj +++ b/Source/Samples/net45/Tracker.SqlServer.CodeFirst/Tracker.SqlServer.CodeFirst.csproj @@ -1,5 +1,6 @@  + Debug AnyCPU @@ -15,6 +16,8 @@ ..\ true + + true @@ -54,6 +57,22 @@ + + ..\..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll + True + + + ..\..\..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll + True + + + ..\..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll + True + + + ..\..\..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll + True + @@ -120,11 +139,19 @@ - + + Designer + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + @@ -18,6 +28,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -30,6 +72,25 @@ + + + + + + + + + + + + + + + + + + + @@ -112,6 +173,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -136,6 +221,20 @@ + + + + + + + + + + + + + + @@ -221,14 +320,27 @@ + + + + + + + + + + + + + @@ -237,6 +349,10 @@ + + + + @@ -513,7 +629,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -634,6 +872,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Samples/net45/Tracker.SqlServer.Entities/Tracker.edmx.diagram b/Source/Samples/net45/Tracker.SqlServer.Entities/Tracker.edmx.diagram index 0971141..f0f43d0 100644 --- a/Source/Samples/net45/Tracker.SqlServer.Entities/Tracker.edmx.diagram +++ b/Source/Samples/net45/Tracker.SqlServer.Entities/Tracker.edmx.diagram @@ -4,7 +4,7 @@ - + @@ -20,6 +20,14 @@ + + + + + + + + diff --git a/Source/Samples/net45/Tracker.SqlServer.Entities/packages.config b/Source/Samples/net45/Tracker.SqlServer.Entities/packages.config index 9e8db31..2c634d7 100644 --- a/Source/Samples/net45/Tracker.SqlServer.Entities/packages.config +++ b/Source/Samples/net45/Tracker.SqlServer.Entities/packages.config @@ -1,4 +1,14 @@  + + + + + + + + + + \ No newline at end of file diff --git a/Source/Samples/net45/Tracker.SqlServer.Test/BatchDbContext.cs b/Source/Samples/net45/Tracker.SqlServer.Test/BatchDbContext.cs index 0fa818e..c75e390 100644 --- a/Source/Samples/net45/Tracker.SqlServer.Test/BatchDbContext.cs +++ b/Source/Samples/net45/Tracker.SqlServer.Test/BatchDbContext.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; -using System.Data.Entity.Infrastructure; using System.Linq; -using System.Text; using EntityFramework.Extensions; using Xunit; using Tracker.SqlServer.CodeFirst; @@ -17,6 +14,7 @@ public class BatchDbContext public void Delete() { var db = new TrackerContext(); + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); string emailDomain = "@test.com"; int count = db.Users .Where(u => u.EmailAddress.EndsWith(emailDomain)) @@ -26,6 +24,7 @@ public void Delete() public void DeleteWhere() { var db = new TrackerContext(); + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); string emailDomain = "@test.com"; int count = db.Users @@ -37,6 +36,7 @@ public void DeleteWhere() public async void DeleteAsync() { var db = new TrackerContext(); + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); string emailDomain = "@test.com"; int count = await db.Users @@ -48,6 +48,7 @@ public async void DeleteAsync() public void DeleteWhereWithExpressionContainingNullParameter() { var db = new TrackerContext(); + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); string emailDomain = "@test.com"; string optionalComparisonString = null; @@ -61,6 +62,7 @@ public void DeleteWhereWithExpressionContainingNullParameter() public void Update() { var db = new TrackerContext(); + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); string emailDomain = "@test.com"; int count = db.Users .Where(u => u.EmailAddress.EndsWith(emailDomain)) @@ -71,6 +73,7 @@ public void Update() public async void UpdateAsync() { var db = new TrackerContext(); + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); string emailDomain = "@test.com"; int count = await db.Users .Where(u => u.EmailAddress.EndsWith(emailDomain)) @@ -81,6 +84,7 @@ public async void UpdateAsync() public void UpdateAppend() { var db = new TrackerContext(); + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); string emailDomain = "@test.com"; string newComment = " New Comment"; @@ -94,6 +98,7 @@ public void UpdateAppend() public void UpdateAppendAndNull() { var db = new TrackerContext(); + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); string emailDomain = "@test.com"; string newComment = " New Comment"; @@ -112,6 +117,7 @@ public void UpdateAppendAndNull() public void UpdateJoin() { var db = new TrackerContext(); + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); string emailDomain = "@test.com"; string space = " "; @@ -124,6 +130,7 @@ public void UpdateJoin() public void UpdateCopy() { var db = new TrackerContext(); + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); string emailDomain = "@test.com"; int count = db.Users @@ -136,6 +143,7 @@ public void UpdateWithExpressionContainingNullParameter() { // This test verifies that the update is interpreted correctly when the where expression uses a parameter with a null parameter var db = new TrackerContext(); + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); string emailDomain = "@test.com"; string optionalComparisonString = null; diff --git a/Source/Samples/net45/Tracker.SqlServer.Test/ExtensionTest.cs b/Source/Samples/net45/Tracker.SqlServer.Test/ExtensionTest.cs index 5598da6..9977111 100644 --- a/Source/Samples/net45/Tracker.SqlServer.Test/ExtensionTest.cs +++ b/Source/Samples/net45/Tracker.SqlServer.Test/ExtensionTest.cs @@ -1,5 +1,4 @@ using System; -using System.Text; using System.Collections.Generic; using System.Linq; using System.Transactions; @@ -9,7 +8,6 @@ namespace Tracker.SqlServer.Test { - public class ExtensionTest { [Fact] @@ -70,5 +68,281 @@ public void TransactionScopeObjectContext() } } + + private void _Insert(TrackerEntities db, bool isAsync=false) + { + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); + db.ProductSummaries.Delete(); + var query = from product in db.Products + join item2 in ( + from item in db.Items + group item by item.ProductId into grItem + select new + { + ProductId = grItem.Key, + AvgPrice = grItem.Average(x => x.ListPrice + x.UnitCost) + } + ) on product.ProductId equals item2.ProductId into items + from item3 in items.DefaultIfEmpty() + select new ProductSummary2 + { + ProductId = product.ProductId, + Name = product.Name, + AvgPrice = item3.AvgPrice ?? 0 + }; + if (isAsync) db.ProductSummaries.InsertAsync(query).Wait(); + else db.ProductSummaries.Insert(query); + var source = query.ToArray(); + var result = db.ProductSummaries.ToArray(); + for (int i = 0; i < source.Length; i++) + { + source[i].AvgPrice = Math.Round(source[i].AvgPrice, 2, MidpointRounding.AwayFromZero); //In database, only two digits after decimal point + source[i].Verified = true; //Verified was not set in query. In database, its default value is true (1) + } + Assert.True(result.OrderBy(i => i.ProductId).SequenceEqual(source.OrderBy(i => i.ProductId), new ProductSummaryComparer())); + + db.Item_2.Delete(); + var query2 = db.Items.Where(item => item.ListPrice / item.UnitCost >= 5); + if (isAsync) db.Item_2.InsertAsync(query2).Wait(); + else db.Item_2.Insert(query2); + var source2 = query2.ToArray().OrderBy(i => i.ItemId); + var result2 = db.Item_2.ToArray().Select(i => ItemComparer.GetItem(i)).OrderBy(i => i.ItemId); + Assert.True(result2.SequenceEqual(source2, new ItemComparer())); + + + db.Item_2.Delete(); + var query3 = from item in db.Items where item.ProductId == "K9-RT-02" select item; + if (isAsync) db.Item_2.InsertAsync(query3).Wait(); + else db.Item_2.Insert(query3); + var source3 = query3.ToArray().OrderBy(item => item.ItemId); + var result3 = db.Item_2.ToArray().Select(i => ItemComparer.GetItem(i)).OrderBy(item => item.ItemId); + Assert.True(result3.SequenceEqual(source3, new ItemComparer())); + } + + [Fact] + public void InsertNoTransaction() + { + using (var db = new TrackerEntities()) + { + _Insert(db); + } + } + + [Fact] + public void InsertInTransaction() + { + using (var db = new TrackerEntities()) + using (var tx = db.Database.BeginTransaction()) + { + _Insert(db); + tx.Commit(); + } + } + + [Fact] + public void InsertInTransactionScope() + { + using (var tx = new TransactionScope()) + using (var db = new TrackerEntities()) + { + _Insert(db); + tx.Complete(); + } + } + + [Fact] + public void InsertAsync() + { + using (var db = new TrackerEntities()) + { + _Insert(db, true); + } + } + + private void _InsertBulk(TrackerEntities db, bool isAsync = false) + { + db.Database.Log = s => System.Diagnostics.Trace.WriteLine(s); + db.ProductSummaries.Delete(); + db.Database.ExecuteSqlCommand("TRUNCATE TABLE ATable"); + + //Create 1000 random records + Random r = new Random(); + int n = 1000; + var entities = new List(); + int m = (int)Math.Pow(10, 8) - 1; + for (int i = 1; i <= n; i++) + { + entities.Add(new ProductSummary + { + ProductId = i.ToString(), + Name = Guid.NewGuid().ToString().Replace("-", "").PadRight(80).Substring(0, 80), + AvgPrice = r.Next(-m, m), + Verified = r.Next() % 2 == 0, + Date = DateTime.Now.AddDays(r.Next(-100, 100)), + }); + } + + var start = DateTime.Now; + + if (isAsync) db.ProductSummaries.InsertAsync(entities).Wait(); + else db.ProductSummaries.Insert(entities); + + /** + * Compare the execution time with these two lines of commented code below + // * **/ + //db.ProductSummaries.AddRange(entities); + //db.SaveChanges(); + + System.Diagnostics.Trace.WriteLine("***** Executing bulk insert (" + n + " items) takes " + + DateTime.Now.Subtract(start).ToString(@"hh\:mm\:ss\.ffffff")); + + Assert.True(db.ProductSummaries.Count() == n); + + /** Dealing with Identity Column **/ + var entities2 = new List(); + for (int i = 1; i <= n; i++) + { + entities2.Add(new ATable + { + A = r.NextDouble(), + B = Guid.NewGuid().ToString().Replace("-", "").PadRight(50).Substring(0, 50), + //C is an Identity column + D = DateTime.Now.AddDays(r.Next(-100, 100)), + E = r.Next() % 2 == 0, + }); + } + + if (isAsync) db.ATables.InsertAsync(entities2).Wait(); + else db.ATables.Insert(entities2); + Assert.True(db.ATables.Count() == n); + } + + [Fact] + public void InsertBulkNoTransaction() + { + using (var db = new TrackerEntities()) + { + _InsertBulk(db); + } + } + + [Fact] + public void InsertBulkInTransaction() + { + using (var db = new TrackerEntities()) + using (var tx = db.Database.BeginTransaction()) + { + _InsertBulk(db); + tx.Commit(); + } + } + + [Fact] + public void InsertBulkInTransactionScope() + { + using (var tx = new TransactionScope()) + using (var db = new TrackerEntities()) + { + _InsertBulk(db); + tx.Complete(); + } + } + + [Fact] + public void InsertBulkAsync() + { + using (var db = new TrackerEntities()) + { + _InsertBulk(db, true); + } + } + } + + class ProductSummary2 : ProductSummary { } + + class ProductSummaryComparer : IEqualityComparer, System.Collections.IComparer + { + public int Compare(object x, object y) + { + if (x == null && y == null) return 0; + var x2 = x as ProductSummary; + var y2 = y as ProductSummary; + if (x2 != null && y2 != null) + { + if (x2.ProductId == y2.ProductId + && x2.Name == y2.Name + && x2.AvgPrice == y2.AvgPrice + && x2.Verified == y2.Verified) + return 0; + } + return -1; + } + + public bool Equals(ProductSummary x, ProductSummary y) + { + return Compare(x, y) == 0; + } + + public int GetHashCode(ProductSummary obj) + { + if (obj == null) return 0; + return obj.ProductId.GetHashCode(); + } + } + + class ItemComparer : IEqualityComparer, System.Collections.IComparer + { + public int Compare(object x, object y) + { + if (x == null && y == null) return 0; + if (x == null || y == null) return -1; + Item item = GetItem(x), item2 = GetItem(y); + if (item.ItemId == item2.ItemId + && item.ProductId == item2.ProductId + && item.ListPrice == item2.ListPrice + && item.UnitCost == item2.UnitCost + && item.Supplier == item2.Supplier + && item.Status == item2.Status + && item.Attr1 == item2.Attr1 + && item.Attr2 == item2.Attr2 + && item.Attr3 == item2.Attr3 + && item.Attr4 == item2.Attr4 + && item.Attr5 == item2.Attr5) return 0; + return -1; + } + + public bool Equals(Item x, Item y) + { + return Compare(x, y) == 0; + } + + public int GetHashCode(Item obj) + { + return obj.ItemId.GetHashCode(); + } + + public static Item GetItem(object obj) + { + if (obj is Item) return obj as Item; + if (obj is Item_2) + { + var item2 = obj as Item_2; + return new Item + { + ItemId = item2.ItemId, + ProductId = item2.ProductId, + ListPrice = item2.ListPrice, + UnitCost = item2.UnitCost, + Supplier = item2.Supplier, + Status = item2.Status, + Attr1 = item2.Attr1, + Attr2 = item2.Attr2, + Attr3 = item2.Attr3, + Attr4 = item2.Attr4, + Attr5 = item2.Attr5 + }; + } + return null; + } } } diff --git a/Source/Samples/net45/Tracker.SqlServer.Test/Tracker.SqlServer.Test.csproj b/Source/Samples/net45/Tracker.SqlServer.Test/Tracker.SqlServer.Test.csproj index a0bfffc..3f9f6b0 100644 --- a/Source/Samples/net45/Tracker.SqlServer.Test/Tracker.SqlServer.Test.csproj +++ b/Source/Samples/net45/Tracker.SqlServer.Test/Tracker.SqlServer.Test.csproj @@ -1,5 +1,6 @@  + Debug AnyCPU @@ -15,6 +16,8 @@ ..\ true + + true @@ -72,8 +75,21 @@ - - ..\..\..\packages\xunit.1.9.2\lib\net20\xunit.dll + + False + ..\..\..\packages\xunit.runner.visualstudio.2.1.0\build\_common\xunit.abstractions.dll + + + ..\..\..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll + True + + + ..\..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll + True + + + ..\..\..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll + True @@ -96,7 +112,7 @@ {D390C235-242C-4E92-9E0B-D2463E87B0F0} - EntityFramework.Extended + EntityFramework.Extended.net45 {FA68FB7C-D87E-497B-A300-F2A7827FE92C} @@ -121,6 +137,12 @@ + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + +