From f57fbb5f68e84b36545537b372db35e3b47d73e1 Mon Sep 17 00:00:00 2001 From: zzzprojects Date: Fri, 16 Mar 2018 16:31:51 -0400 Subject: [PATCH] Add LinqToSql Add LinqToSql --- docs/404.md | 10 + docs/CNAME | 1 + docs/_config.yml | 20 + docs/_data/meta.csv | 91 ++++ .../component-rotator-dark-begin.html | 6 + .../_includes/component-rotator-dark-end.html | 6 + docs/_includes/component-scroll-to-top.html | 3 + docs/_includes/custom/_global_variable.html | 27 ++ docs/_includes/custom/section-aside.html | 13 + docs/_includes/custom/section-sidebar.html | 131 ++++++ docs/_includes/custom/site-footer.html | 25 ++ docs/_includes/custom/site-header.html | 91 ++++ docs/_includes/infozzzprojects-email.html | 1 + docs/_includes/mail-info.html | 1 + docs/_includes/mail-sales.html | 1 + docs/_includes/page-home-featured.html | 0 docs/_includes/section-article-end.html | 2 + docs/_includes/section-article-start.html | 2 + docs/_includes/section-faq-begin.html | 2 + docs/_includes/section-faq-end.html | 2 + docs/_includes/section-header.html | 18 + docs/_includes/template-example.html | 8 + docs/_includes/template-exception.html | 4 + docs/_includes/under-construction.html | 1 + docs/_layouts/default.html | 232 ++++++++++ docs/_sass/_mixin.scss | 73 ++++ docs/_sass/component-card-box.scss | 49 +++ docs/_sass/component-card-code.scss | 47 ++ docs/_sass/component-rotator-dark.scss | 57 +++ docs/_sass/component-scroll-to-top.scss | 32 ++ docs/_sass/page-index.scss | 138 ++++++ docs/_sass/page-pricing.scss | 31 ++ docs/_sass/section.scss | 110 +++++ docs/_sass/site-default.scss | 116 +++++ docs/_sass/site-footer.scss | 14 + docs/_sass/site-header.scss | 125 ++++++ docs/_sass/utilities.scss | 50 +++ docs/css/master.scss | 19 + docs/images/arrow.png | Bin 0 -> 4285 bytes docs/images/list-checked.png | Bin 0 -> 1253 bytes docs/images/logo.png | Bin 0 -> 1439 bytes docs/images/logo256X256-opacity.png | Bin 0 -> 19064 bytes docs/images/logo256X256.png | Bin 0 -> 22802 bytes docs/index.md | 404 ++++++++++++++++++ docs/pages/api/api.md | 69 +++ docs/pages/api/bulk-delete.md | 90 ++++ docs/pages/api/bulk-insert.md | 93 ++++ docs/pages/api/bulk-merge.md | 118 +++++ docs/pages/api/bulk-savechanges.md | 86 ++++ docs/pages/api/bulk-synchronize.md | 85 ++++ docs/pages/api/bulk-update.md | 108 +++++ docs/pages/api/delete-from-query.md | 39 ++ .../api/options-summary/include-graph.md | 76 ++++ .../api/options-summary/options-audit.md | 43 ++ .../api/options-summary/options-batch.md | 31 ++ .../api/options-summary/options-column.md | 67 +++ .../options-context-factory.md | 65 +++ .../options-summary/options-execute-event.md | 25 ++ .../api/options-summary/options-identity.md | 31 ++ docs/pages/api/options-summary/options-key.md | 21 + .../api/options-summary/options-logging.md | 48 +++ .../api/options-summary/options-sql-server.md | 14 + .../options-temporary-table.md | 80 ++++ .../options-transient-error.md | 27 ++ docs/pages/api/options-summary/transaction.md | 43 ++ docs/pages/api/options/allow-concurrency.md | 5 + .../pages/api/options/allow-duplicate-keys.md | 19 + .../api/options/allow-update-primary-keys.md | 14 + docs/pages/api/options/audit-entries.md | 34 ++ .../pages/api/options/batch-delay-interval.md | 27 ++ docs/pages/api/options/batch-size.md | 38 ++ docs/pages/api/options/batch-timeout.md | 23 + .../api/options/bulk-operation-executed.md | 27 ++ .../api/options/bulk-operation-executing.md | 16 + .../api/options/column-input-expression.md | 20 + .../options/column-input-output-expression.md | 20 + .../api/options/column-output-expression.md | 16 + .../options/column-primary-key-expression.md | 18 + .../ingore-on-merge-insert-expression.md | 25 ++ .../ingore-on-merge-update-expression.md | 25 ++ .../pages/api/options/insert-keep-identity.md | 16 + docs/pages/api/options/log-dump.md | 21 + docs/pages/api/options/log.md | 19 + docs/pages/api/options/merge-keep-identity.md | 16 + docs/pages/api/options/retry-count.md | 29 ++ docs/pages/api/options/retry-interval.md | 31 ++ .../api/options/sql-bulk-copy-options.md | 17 + .../api/options/synchronize-keep-identity.md | 16 + .../options/temporary-table-batch-by-table.md | 17 + .../temporary-table-insert-batch-size.md | 17 + .../api/options/temporary-table-min-record.md | 17 + .../options/temporary-table-schema-name.md | 17 + .../options/temporary-table-use-table-lock.md | 17 + docs/pages/api/options/use-audit.md | 25 ++ docs/pages/api/options/use-log-dump.md | 20 + docs/pages/api/options/use-permanent-table.md | 17 + docs/pages/api/update-from-query.md | 41 ++ docs/pages/articles/articles.md | 12 + docs/pages/articles/benchmark.md | 132 ++++++ .../bulk-insert-vs-bulk-savechanges.md | 39 ++ docs/pages/articles/concurrency.md | 208 +++++++++ docs/pages/articles/custom-column.md | 42 ++ docs/pages/articles/custom-key.md | 53 +++ docs/pages/articles/emdx.md | 35 ++ docs/pages/articles/fastest-way-to-insert.md | 172 ++++++++ .../articles/improve-bulk-savechanges.md | 55 +++ docs/pages/articles/soft-delete.md | 111 +++++ docs/pages/faq/faq-general.md | 20 + docs/pages/faq/faq-installation.md | 12 + docs/pages/faq/faq-license.md | 76 ++++ docs/pages/faq/faq.md | 8 + docs/pages/faq/issue-tracker.md | 13 + .../dbbulkoperationconcurrency-exception.md | 89 ++++ .../problems/dbupdateconcurrency-exception.md | 129 ++++++ ...y-constraint-autodetectchanges-disabled.md | 42 ++ docs/pages/problems/md5-exception.md | 27 ++ docs/pages/problems/out-of-memory.md | 36 ++ docs/pages/problems/problems.md | 9 + .../trial-period-expired-exception.md | 35 ++ .../problems/type-not-supported-exception.md | 20 + docs/pages/site/contact-us.md | 101 +++++ docs/pages/site/download.md | 114 +++++ docs/pages/site/pricing.md | 154 +++++++ docs/pages/site/trial.md | 20 + docs/pages/tutorials.md | 52 +++ docs/pages/tutorials/installing.md | 51 +++ docs/pages/tutorials/licensing.md | 53 +++ docs/pages/tutorials/overview.md | 94 ++++ docs/pages/tutorials/requirements.md | 11 + .../tutorials/tutorial-batch-operations.md | 40 ++ .../tutorials/tutorial-bulk-operations.md | 51 +++ .../tutorials/tutorial-bulk-savechanges.md | 51 +++ docs/pages/tutorials/tutorial-introduction.md | 107 +++++ docs/pages/tutorials/upgrading.md | 15 + docs/robots.txt | 6 + 135 files changed, 6197 insertions(+) create mode 100644 docs/404.md create mode 100644 docs/CNAME create mode 100644 docs/_config.yml create mode 100644 docs/_data/meta.csv create mode 100644 docs/_includes/component-rotator-dark-begin.html create mode 100644 docs/_includes/component-rotator-dark-end.html create mode 100644 docs/_includes/component-scroll-to-top.html create mode 100644 docs/_includes/custom/_global_variable.html create mode 100644 docs/_includes/custom/section-aside.html create mode 100644 docs/_includes/custom/section-sidebar.html create mode 100644 docs/_includes/custom/site-footer.html create mode 100644 docs/_includes/custom/site-header.html create mode 100644 docs/_includes/infozzzprojects-email.html create mode 100644 docs/_includes/mail-info.html create mode 100644 docs/_includes/mail-sales.html create mode 100644 docs/_includes/page-home-featured.html create mode 100644 docs/_includes/section-article-end.html create mode 100644 docs/_includes/section-article-start.html create mode 100644 docs/_includes/section-faq-begin.html create mode 100644 docs/_includes/section-faq-end.html create mode 100644 docs/_includes/section-header.html create mode 100644 docs/_includes/template-example.html create mode 100644 docs/_includes/template-exception.html create mode 100644 docs/_includes/under-construction.html create mode 100644 docs/_layouts/default.html create mode 100644 docs/_sass/_mixin.scss create mode 100644 docs/_sass/component-card-box.scss create mode 100644 docs/_sass/component-card-code.scss create mode 100644 docs/_sass/component-rotator-dark.scss create mode 100644 docs/_sass/component-scroll-to-top.scss create mode 100644 docs/_sass/page-index.scss create mode 100644 docs/_sass/page-pricing.scss create mode 100644 docs/_sass/section.scss create mode 100644 docs/_sass/site-default.scss create mode 100644 docs/_sass/site-footer.scss create mode 100644 docs/_sass/site-header.scss create mode 100644 docs/_sass/utilities.scss create mode 100644 docs/css/master.scss create mode 100644 docs/images/arrow.png create mode 100644 docs/images/list-checked.png create mode 100644 docs/images/logo.png create mode 100644 docs/images/logo256X256-opacity.png create mode 100644 docs/images/logo256X256.png create mode 100644 docs/index.md create mode 100644 docs/pages/api/api.md create mode 100644 docs/pages/api/bulk-delete.md create mode 100644 docs/pages/api/bulk-insert.md create mode 100644 docs/pages/api/bulk-merge.md create mode 100644 docs/pages/api/bulk-savechanges.md create mode 100644 docs/pages/api/bulk-synchronize.md create mode 100644 docs/pages/api/bulk-update.md create mode 100644 docs/pages/api/delete-from-query.md create mode 100644 docs/pages/api/options-summary/include-graph.md create mode 100644 docs/pages/api/options-summary/options-audit.md create mode 100644 docs/pages/api/options-summary/options-batch.md create mode 100644 docs/pages/api/options-summary/options-column.md create mode 100644 docs/pages/api/options-summary/options-context-factory.md create mode 100644 docs/pages/api/options-summary/options-execute-event.md create mode 100644 docs/pages/api/options-summary/options-identity.md create mode 100644 docs/pages/api/options-summary/options-key.md create mode 100644 docs/pages/api/options-summary/options-logging.md create mode 100644 docs/pages/api/options-summary/options-sql-server.md create mode 100644 docs/pages/api/options-summary/options-temporary-table.md create mode 100644 docs/pages/api/options-summary/options-transient-error.md create mode 100644 docs/pages/api/options-summary/transaction.md create mode 100644 docs/pages/api/options/allow-concurrency.md create mode 100644 docs/pages/api/options/allow-duplicate-keys.md create mode 100644 docs/pages/api/options/allow-update-primary-keys.md create mode 100644 docs/pages/api/options/audit-entries.md create mode 100644 docs/pages/api/options/batch-delay-interval.md create mode 100644 docs/pages/api/options/batch-size.md create mode 100644 docs/pages/api/options/batch-timeout.md create mode 100644 docs/pages/api/options/bulk-operation-executed.md create mode 100644 docs/pages/api/options/bulk-operation-executing.md create mode 100644 docs/pages/api/options/column-input-expression.md create mode 100644 docs/pages/api/options/column-input-output-expression.md create mode 100644 docs/pages/api/options/column-output-expression.md create mode 100644 docs/pages/api/options/column-primary-key-expression.md create mode 100644 docs/pages/api/options/ingore-on-merge-insert-expression.md create mode 100644 docs/pages/api/options/ingore-on-merge-update-expression.md create mode 100644 docs/pages/api/options/insert-keep-identity.md create mode 100644 docs/pages/api/options/log-dump.md create mode 100644 docs/pages/api/options/log.md create mode 100644 docs/pages/api/options/merge-keep-identity.md create mode 100644 docs/pages/api/options/retry-count.md create mode 100644 docs/pages/api/options/retry-interval.md create mode 100644 docs/pages/api/options/sql-bulk-copy-options.md create mode 100644 docs/pages/api/options/synchronize-keep-identity.md create mode 100644 docs/pages/api/options/temporary-table-batch-by-table.md create mode 100644 docs/pages/api/options/temporary-table-insert-batch-size.md create mode 100644 docs/pages/api/options/temporary-table-min-record.md create mode 100644 docs/pages/api/options/temporary-table-schema-name.md create mode 100644 docs/pages/api/options/temporary-table-use-table-lock.md create mode 100644 docs/pages/api/options/use-audit.md create mode 100644 docs/pages/api/options/use-log-dump.md create mode 100644 docs/pages/api/options/use-permanent-table.md create mode 100644 docs/pages/api/update-from-query.md create mode 100644 docs/pages/articles/articles.md create mode 100644 docs/pages/articles/benchmark.md create mode 100644 docs/pages/articles/bulk-insert-vs-bulk-savechanges.md create mode 100644 docs/pages/articles/concurrency.md create mode 100644 docs/pages/articles/custom-column.md create mode 100644 docs/pages/articles/custom-key.md create mode 100644 docs/pages/articles/emdx.md create mode 100644 docs/pages/articles/fastest-way-to-insert.md create mode 100644 docs/pages/articles/improve-bulk-savechanges.md create mode 100644 docs/pages/articles/soft-delete.md create mode 100644 docs/pages/faq/faq-general.md create mode 100644 docs/pages/faq/faq-installation.md create mode 100644 docs/pages/faq/faq-license.md create mode 100644 docs/pages/faq/faq.md create mode 100644 docs/pages/faq/issue-tracker.md create mode 100644 docs/pages/problems/dbbulkoperationconcurrency-exception.md create mode 100644 docs/pages/problems/dbupdateconcurrency-exception.md create mode 100644 docs/pages/problems/foreign-key-constraint-autodetectchanges-disabled.md create mode 100644 docs/pages/problems/md5-exception.md create mode 100644 docs/pages/problems/out-of-memory.md create mode 100644 docs/pages/problems/problems.md create mode 100644 docs/pages/problems/trial-period-expired-exception.md create mode 100644 docs/pages/problems/type-not-supported-exception.md create mode 100644 docs/pages/site/contact-us.md create mode 100644 docs/pages/site/download.md create mode 100644 docs/pages/site/pricing.md create mode 100644 docs/pages/site/trial.md create mode 100644 docs/pages/tutorials.md create mode 100644 docs/pages/tutorials/installing.md create mode 100644 docs/pages/tutorials/licensing.md create mode 100644 docs/pages/tutorials/overview.md create mode 100644 docs/pages/tutorials/requirements.md create mode 100644 docs/pages/tutorials/tutorial-batch-operations.md create mode 100644 docs/pages/tutorials/tutorial-bulk-operations.md create mode 100644 docs/pages/tutorials/tutorial-bulk-savechanges.md create mode 100644 docs/pages/tutorials/tutorial-introduction.md create mode 100644 docs/pages/tutorials/upgrading.md create mode 100644 docs/robots.txt diff --git a/docs/404.md b/docs/404.md new file mode 100644 index 0000000..d3b6d06 --- /dev/null +++ b/docs/404.md @@ -0,0 +1,10 @@ +--- +permalink: /404.html +--- + +
+Oops! The page has moved, or the link is broken. + +Let us know how you landed on this page, and we will try to fix the link: info@zzzprojects.com + +Go to Home diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 0000000..fe1243a --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +linqtosql-plus.net \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..8400585 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,20 @@ +highlighter: rouge +gems: + - jekyll-sitemap +ga: "UA-55584370-8" + +includes: +- _includes_custom + +defaults: + - + scope: + path: "" + values: + layout: "default" + - + scope: + path: "" + type: "pages" + values: + last_modified_at: "2017-03-13" diff --git a/docs/_data/meta.csv b/docs/_data/meta.csv new file mode 100644 index 0000000..21952b9 --- /dev/null +++ b/docs/_data/meta.csv @@ -0,0 +1,91 @@ +permalink,title,meta-description,meta-keywords,h1,h2,h3,nagivation,template,css +index,Learn how to use Entity Framework Bulk Insert with Tutorials & Examples for Code First & Database First.,Learn how to use Entity Framework Bulk Insert with Tutorials & Examples for Code First & Database First.,,,,,,container-none, +/404.html,Page Moved,Page Moved,,Page Moved,,,,container-none,section-article +download,Download,Download,,Download,Free monthly trial available,,no,container-page,section-article +pricing,Purchase,Purchase,,Purchase,"Unlock better performance, be more responsive!",,no,container-page,section-article +contact-us,Contact Us,Contact Us,,Test our oustanding support,"We usually answer within the next business day, hour, or minutes!",,no,container-page,section-article +tutorials,Tutorials,Tutorials,,Tutorials,,,,container-page,section-article +overview,Overview,Overview,,Overview,,,,container-doc,section-article +requirements,Requirements,Requirements,,Requirements,,,,container-doc,section-article +installing,Installing,Installing,,Installing,,,,container-doc,section-article +upgrading,Upgrading,Upgrading,,Upgrading,,,,container-doc,section-article +licensing,Licensing,Licensing,,Licensing,,,,container-doc,section-article +tutorial-bulk-savechanges,Bulk SaveChanges,Bulk SaveChanges,,Bulk SaveChanges,,,,container-doc,section-article +tutorial-bulk-operations,Bulk Operations,Bulk Operations,,Bulk Operations,,,,container-doc,section-article +tutorial-batch-operations,Batch Operations,Batch Operations,,Batch Operations,,,,container-doc,section-article +api,API,API,,API,,,,container-doc,section-article +bulk-savechanges,Bulk SaveChanges,Bulk SaveChanges,,Bulk SaveChanges,,,,container-doc,section-article +bulk-insert,Bulk Insert,Bulk Insert,,Bulk Insert,,,,container-doc,section-article +bulk-update,Bulk Update,Bulk Update,,Bulk Update,,,,container-doc,section-article +bulk-delete,Bulk Delete,Bulk Delete,,Bulk Delete,,,,container-doc,section-article +bulk-merge,Bulk Merge,Bulk Merge,,Bulk Merge,,,,container-doc,section-article +bulk-synchronize,Bulk Synchronize,Bulk Synchronize,,Bulk Synchronize,,,,container-doc,section-article +update-from-query,Update from Query,Update from Query,,Update from Query,,,,container-doc,section-article +delete-from-query,Delete from Query,Delete from Query,,Delete from Query,,,,container-doc,section-article +audit,Audit,Audit,,Audit,,,,container-doc,section-article +batch,Batch,Batch,,Batch,,,,container-doc,section-article +column,Column,Column,,Column,,,,container-doc,section-article +context-factory,Context Factory,Context Factory,,Context Factory,,,,container-doc,section-article +execute-event,Execute Event,Execute Event,,Execute Event,,,,container-doc,section-article +identity,Identity,Identity,,Identity,,,,container-doc,section-article +include-graph,Include Graph,Include Graph,,Include Graph,,,,container-doc,section-article +key,Key,Key,,Key,,,,container-doc,section-article +logging,Logging,Logging,,Logging,,,,container-doc,section-article +temporary-table,Temporary Table,Temporary Table,,Temporary Table,,,,container-doc,section-article +transaction,Transaction,Transaction,,Transaction,,,,container-doc,section-article +transient-error,Transient Error,Transient Error,,Transient Error,,,,container-doc,section-article +sql-server,SQL Server,SQL Server,,SQL Server,,,,container-doc,section-article +faq,FAQ,FAQ,,FAQ,,,,container-doc,section-article +issue-tracker,Issue Tracker,Issue Tracker,,Issue Tracker,,,,container-doc,section-article +faq-general,FAQ - General,FAQ - General,,FAQ - General,,,,container-doc,section-article +faq-installation,FAQ - Installation,FAQ - Installation,,FAQ - Installation,,,,container-doc,section-article +faq-license,FAQ - License,FAQ - License,,FAQ - License,,,,container-doc,section-article +problems,Problems,Problems,,Problems,,,,container-doc,section-article +trial-period-expired-exception,Trial Expired,Trial Expired,,Trial Expired,,,,container-doc,section-article +md5-exception,MD5 Exception,MD5 Exception,,MD5 Exception,,,,container-doc,section-article +dbupdateconcurrency-exception,DbUpdateConcurrency,DbUpdateConcurrency,,DbUpdateConcurrency,,,,container-doc,section-article +dbbulkoperationconcurrency-exception,DbBulkOperationConcurrency,DbBulkOperationConcurrency,,DbBulkOperationConcurrency,,,,container-doc,section-article +foreign-key-constraint-autodetectchanges-disabled,Foreign Key Constraint,Foreign Key Constraint,,Foreign Key Constraint,,,,container-doc,section-article +type-not-supported-exception,Type not Supported,Type not Supported,,Type not Supported,,,,container-doc,section-article +allow-concurrency,allow-concurrency,allow-concurrency,,allow-concurrency,,,no,container-doc,section-article +allow-duplicate-keys,allow-duplicate-keys,allow-duplicate-keys,,allow-duplicate-keys,,,no,container-doc,section-article +allow-update-primary-keys,allow-update-primary-keys,allow-update-primary-keys,,allow-update-primary-keys,,,no,container-doc,section-article +audit-entries,audit-entries,audit-entries,,audit-entries,,,no,container-doc,section-article +batch-delay-interval,batch-delay-interval,batch-delay-interval,,batch-delay-interval,,,no,container-doc,section-article +batch-size,batch-size,batch-size,,batch-size,,,no,container-doc,section-article +batch-timeout,batch-timeout,batch-timeout,,batch-timeout,,,no,container-doc,section-article +bulk-operation-executed,bulk-operation-executed,bulk-operation-executed,,bulk-operation-executed,,,no,container-doc,section-article +bulk-operation-executing,bulk-operation-executing,bulk-operation-executing,,bulk-operation-executing,,,no,container-doc,section-article +column-input-expression,column-input-expression,column-input-expression,,column-input-expression,,,no,container-doc,section-article +column-output-expression,column-output-expression,column-output-expression,,column-output-expression,,,no,container-doc,section-article +column-primary-key-expression,column-primary-key-expression,column-primary-key-expression,,column-primary-key-expression,,,no,container-doc,section-article +ignore-on-merge-insert-expression,ignore-on-merge-insert-expression,ignore-on-merge-insert-expression,,ignore-on-merge-insert-expression,,,no,container-doc,section-article +ignore-on-merge-update-expression,ignore-on-merge-update-expression,ignore-on-merge-update-expression,,ignore-on-merge-update-expression,,,no,container-doc,section-article +insert-keep-identity,insert-keep-identity,insert-keep-identity,,insert-keep-identity,,,no,container-doc,section-article +log,log,log,,log,,,no,container-doc,section-article +log-dump,log-dump,log-dump,,log-dump,,,no,container-doc,section-article +merge-keep-identity,merge-keep-identity,merge-keep-identity,,merge-keep-identity,,,no,container-doc,section-article +retry-count,retry-count,retry-count,,retry-count,,,no,container-doc,section-article +retry-interval,retry-interval,retry-interval,,retry-interval,,,no,container-doc,section-article +sql-bulk-copy-options,sql-bulk-copy-options,sql-bulk-copy-options,,sql-bulk-copy-options,,,no,container-doc,section-article +synchronize-keep-identity,synchronize-keep-identity,synchronize-keep-identity,,synchronize-keep-identity,,,no,container-doc,section-article +temporary-table-batch-by-table,temporary-table-batch-by-table,temporary-table-batch-by-table,,temporary-table-batch-by-table,,,no,container-doc,section-article +temporary-table-insert-batch-size,temporary-table-insert-batch-size,temporary-table-insert-batch-size,,temporary-table-insert-batch-size,,,no,container-doc,section-article +temporary-table-min-record,temporary-table-min-record,temporary-table-min-record,,temporary-table-min-record,,,no,container-doc,section-article +temporary-table-schema-name,temporary-table-schema-name,temporary-table-schema-name,,temporary-table-schema-name,,,no,container-doc,section-article +temporary-table-use-table-lock,temporary-table-use-table-lock,temporary-table-use-table-lock,,temporary-table-use-table-lock,,,no,container-doc,section-article +use-audit,use-audit,use-audit,,use-audit,,,no,container-doc,section-article +use-log-dump,use-log-dump,use-log-dump,,use-log-dump,,,no,container-doc,section-article +use-permanent-table,use-permanent-table,use-permanent-table,,use-permanent-table,,,no,container-doc,section-article +benchmark,benchmark,benchmark,benchmark,Benchmark,,,no,container-doc,section-article +concurrency,concurrency,concurrency,concurrency,Concurrency,,,no,container-doc,section-article +custom-column,custom-column,custom-column,custom-column,Custom Column,,,no,container-doc,section-article +custom-key,custom-key,custom-key,custom-key,Custom key,,,no,container-doc,section-article +fastest-way-to-insert,fastest-way-to-insert,fastest-way-to-insert,fastest-way-to-insert,Fastest Way to Insert,,,no,container-doc,section-article +improve-bulk-savechanges,improve-bulk-savechanges,improve-bulk-savechanges,improve-bulk-savechanges,Improve BulkSaveChanges,,,no,container-doc,section-article +soft-delete,soft-delete,soft-delete,soft-delete,Soft Delete,,,no,container-doc,section-article +bulk-insert-vs-bulk-savechanges,BulkInsert vs BulkSaveChanges,BulkInsert vs BulkSaveChanges,,BulkInsert vs BulkSaveChanges,,,no,container-doc,section-article +articles,Articles,Articles,,Articles,,,no,container-doc,section-article +trial,Trial,Trial,,Trial,,,no,container-doc,section-article +edmx,Edmx,Edmx,,Edmx,,,no,container-doc,section-article +out-of-memory,Out of memory,Out of memory,,Out of memory,,,no,container-doc,section-article diff --git a/docs/_includes/component-rotator-dark-begin.html b/docs/_includes/component-rotator-dark-begin.html new file mode 100644 index 0000000..f4af7ab --- /dev/null +++ b/docs/_includes/component-rotator-dark-begin.html @@ -0,0 +1,6 @@ +
+
+
+
+
+
\ No newline at end of file diff --git a/docs/_includes/component-rotator-dark-end.html b/docs/_includes/component-rotator-dark-end.html new file mode 100644 index 0000000..c571e64 --- /dev/null +++ b/docs/_includes/component-rotator-dark-end.html @@ -0,0 +1,6 @@ +
+
+ +
\ No newline at end of file diff --git a/docs/_includes/component-scroll-to-top.html b/docs/_includes/component-scroll-to-top.html new file mode 100644 index 0000000..543d90a --- /dev/null +++ b/docs/_includes/component-scroll-to-top.html @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/docs/_includes/custom/_global_variable.html b/docs/_includes/custom/_global_variable.html new file mode 100644 index 0000000..dc35ece --- /dev/null +++ b/docs/_includes/custom/_global_variable.html @@ -0,0 +1,27 @@ +{% if page.path contains "tutorials.md" %} + {% assign is_context_home = true; %} + {% assign is_menu_context_gettingstarted_css_active = "active"; %} +{% elsif page.path contains "/tutorials/" %} + {% assign is_context_tutorials = true; %} + {% assign is_menu_context_gettingstarted_css_active = "active"; %} +{% elsif page.path contains "/api/" %} + {% assign is_context_api = true; %} + {% assign is_menu_context_api_css_active = "active"; %} +{% elsif page.path contains "/faq/" %} + {% assign is_context_faq = true; %} + {% assign is_menu_context_faq_css_active = "active"; %} +{% elsif page.path contains "/problems/" %} + {% assign is_context_problems = true; %} + {% assign is_menu_context_problems_css_active = "active"; %} +{% endif %} +{% for num in (0..site.data.meta.size) %} + {% if site.data.meta[num].permalink == page.permalink %} + {% assign meta_index = num %} + {% endif %} +{% endfor %} + + +{% assign show_menu_context = true %} +{% if site.data.meta[meta_index].permalink == "index" %} + {% assign show_menu_context = false %} +{% endif %} \ No newline at end of file diff --git a/docs/_includes/custom/section-aside.html b/docs/_includes/custom/section-aside.html new file mode 100644 index 0000000..d8de213 --- /dev/null +++ b/docs/_includes/custom/section-aside.html @@ -0,0 +1,13 @@ +
+ diff --git a/docs/_includes/custom/section-sidebar.html b/docs/_includes/custom/section-sidebar.html new file mode 100644 index 0000000..64320b8 --- /dev/null +++ b/docs/_includes/custom/section-sidebar.html @@ -0,0 +1,131 @@ +{% if page.path contains "/tutorials/" %} + + +{% elsif page.path contains "/api/" %} + + +{% elsif page.path contains "/articles/" %} + + +{% elsif page.path contains "/faq/" %} + + +{% elsif page.path contains "/problems/" %} + + +{% endif %} diff --git a/docs/_includes/custom/site-footer.html b/docs/_includes/custom/site-footer.html new file mode 100644 index 0000000..e42513f --- /dev/null +++ b/docs/_includes/custom/site-footer.html @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/docs/_includes/custom/site-header.html b/docs/_includes/custom/site-header.html new file mode 100644 index 0000000..15a9aee --- /dev/null +++ b/docs/_includes/custom/site-header.html @@ -0,0 +1,91 @@ + \ No newline at end of file diff --git a/docs/_includes/infozzzprojects-email.html b/docs/_includes/infozzzprojects-email.html new file mode 100644 index 0000000..c57c078 --- /dev/null +++ b/docs/_includes/infozzzprojects-email.html @@ -0,0 +1 @@ +info@zzzprojects.com diff --git a/docs/_includes/mail-info.html b/docs/_includes/mail-info.html new file mode 100644 index 0000000..c57c078 --- /dev/null +++ b/docs/_includes/mail-info.html @@ -0,0 +1 @@ +info@zzzprojects.com diff --git a/docs/_includes/mail-sales.html b/docs/_includes/mail-sales.html new file mode 100644 index 0000000..2421c08 --- /dev/null +++ b/docs/_includes/mail-sales.html @@ -0,0 +1 @@ +sales@zzzprojects.com diff --git a/docs/_includes/page-home-featured.html b/docs/_includes/page-home-featured.html new file mode 100644 index 0000000..e69de29 diff --git a/docs/_includes/section-article-end.html b/docs/_includes/section-article-end.html new file mode 100644 index 0000000..540afba --- /dev/null +++ b/docs/_includes/section-article-end.html @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/docs/_includes/section-article-start.html b/docs/_includes/section-article-start.html new file mode 100644 index 0000000..91f8e48 --- /dev/null +++ b/docs/_includes/section-article-start.html @@ -0,0 +1,2 @@ +
+
\ No newline at end of file diff --git a/docs/_includes/section-faq-begin.html b/docs/_includes/section-faq-begin.html new file mode 100644 index 0000000..91f8e48 --- /dev/null +++ b/docs/_includes/section-faq-begin.html @@ -0,0 +1,2 @@ +
+
\ No newline at end of file diff --git a/docs/_includes/section-faq-end.html b/docs/_includes/section-faq-end.html new file mode 100644 index 0000000..540afba --- /dev/null +++ b/docs/_includes/section-faq-end.html @@ -0,0 +1,2 @@ +
+
\ No newline at end of file diff --git a/docs/_includes/section-header.html b/docs/_includes/section-header.html new file mode 100644 index 0000000..c03e650 --- /dev/null +++ b/docs/_includes/section-header.html @@ -0,0 +1,18 @@ +{% if site.data.meta[meta_index].h1 != null %} + +
+{% include component-rotator-dark-begin.html %} + +
+

{{site.data.meta[meta_index].h1}}

+ {% if site.data.meta[meta_index].h2 != null %} +
+

{{ site.data.meta[meta_index].h2 }}

+
+ {% endif %} +
+ +{% include component-rotator-dark-end.html %} +
+ +{% endif %} \ No newline at end of file diff --git a/docs/_includes/template-example.html b/docs/_includes/template-example.html new file mode 100644 index 0000000..9b9c19a --- /dev/null +++ b/docs/_includes/template-example.html @@ -0,0 +1,8 @@ +
+{% if include.title == null %} + Example +{% else %} + {{ include.title }} +{% endif %} +
+{:.code} diff --git a/docs/_includes/template-exception.html b/docs/_includes/template-exception.html new file mode 100644 index 0000000..8285735 --- /dev/null +++ b/docs/_includes/template-exception.html @@ -0,0 +1,4 @@ + diff --git a/docs/_includes/under-construction.html b/docs/_includes/under-construction.html new file mode 100644 index 0000000..88dd777 --- /dev/null +++ b/docs/_includes/under-construction.html @@ -0,0 +1 @@ +This page is under construction. \ No newline at end of file diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100644 index 0000000..f324919 --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,232 @@ + + + + + + + + {% include custom/_global_variable.html %} + + + {{ site.data.meta[meta_index].title }} + + + + + + + + + + + + + + + + + {% include custom/site-header.html %} + + +{% if site.data.meta[meta_index].template == "container-none" %} + +{% elsif site.data.meta[meta_index].template == "container-page" %} + +{% elsif site.data.meta[meta_index].template == "container-doc" %} +
+ +
+ +{% endif %} + + {% include custom/site-footer.html %} + + {% include component-scroll-to-top.html %} + + + + + + + + + + + + + + + + + diff --git a/docs/_sass/_mixin.scss b/docs/_sass/_mixin.scss new file mode 100644 index 0000000..c31c4d1 --- /dev/null +++ b/docs/_sass/_mixin.scss @@ -0,0 +1,73 @@ +$color-z: #c00; + +$color-light: #fff; +$color-dark: #000; + + +$box-shadow: 0 5px 5px 0 rgba(0, 0, 0, 0.3); +$box-shadow-dark: 0 5px 5px 0 rgba(0, 0, 0, 0.3); +$link-color: #c00; + +$font-size-xl: 1.5rem; +$font-size-lg: 1.25rem; +$font-size-md: 1.125rem; +$font-weight-light: 300; +$margin-section: 60px; +$padding-section: 60px; +$margin-header-bottom: 20px; +$margin-section-sm: 20px; +$padding-md: 5px; + +$font-size-home-h2: 3rem; +$background-black-transparent: rgba(0, 0, 0, 0.7); +$background-black-transparent-hover: rgba(0, 0, 0, 0.9); +$border-dark: 1px solid #000; +$box-shadow-dark: 10px 10px #333; +$box-shadow-light: 10px 10px #999; +$box-shadow-right: 10px 0 5px -2px #333; +$text-shadow-lg: 2px -1px rgba(0, 0, 0, 0.7); +$text-shadow-xl: 2px -1px rgba(0, 0, 0, 0.7); +$margin-bottom-header: 30px; + +@mixin background-toright-dark { + background: #222; + background: linear-gradient(to right, #333, #111); +} + +@mixin background-black { + background: #222; + background: -moz-radial-gradient(circle, #333, #111); + background: -webkit-radial-gradient(circle, #333, #111); + background: -ms-radial-gradient(circle, #333, #111); + background: -o-radial-gradient(circle, #333, #111); + background: radial-gradient(circle, #333, #111); +} + +@mixin background-black-light { + background: #333; +} + +@mixin background-red { + background: rgb(204, 0, 0); + background: -webkit-radial-gradient(circle, rgb(204, 0, 0), rgb(170, 0, 0), rgb(154, 0, 0)); + background: -o-radial-gradient(circle, rgb(204, 0, 0), rgb(170, 0, 0), rgb(154, 0, 0)); + background: -moz-radial-gradient(circle, rgb(204, 0, 0), rgb(170, 0, 0), rgb(154, 0, 0)); + background: radial-gradient(circle, rgb(204, 0, 0), rgb(170, 0, 0), rgb(154, 0, 0)); +} + +@mixin background-light { + background: #fff; + background: -webkit-radial-gradient(circle, #fff, #fff, #ccc); + background: -o-radial-gradient(circle, #fff, #fff, #ccc); + background: -moz-radial-gradient(circle, #fff, #fff, #ccc); + background: radial-gradient(circle, #fff, #fff, #ccc); +} + + +@mixin transition_ease_slow { + -webkit-transition: all 0.3s linear; + -moz-transition: all 0.3s ease; + -ms-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} \ No newline at end of file diff --git a/docs/_sass/component-card-box.scss b/docs/_sass/component-card-box.scss new file mode 100644 index 0000000..51a44ea --- /dev/null +++ b/docs/_sass/component-card-box.scss @@ -0,0 +1,49 @@ +// +// card-box +// +.card-box { + border-radius: 0; +} +.card-box .card-header { + border-radius: 0; +} +.card-box .card-header { + @include background-red; + color: #fff; +} +.card-box .card-header h2 { + padding: 5px 0; +} +.card-box .card-header a { + color: #fff; +} + +// +// card-box-nav +// +.card-box-nav .card-body h3:not(:first-child) { + margin-top: 15px; +} +.card-box-nav .card-body ul { + padding-left: 20px; +} +.card-box-nav .card-body li { + list-style: none; + padding: 5px 0; +} + +// +// card-box-light +// +.card-box-light { + border: $border-dark; + box-shadow: $box-shadow-dark; +} + +// +// card-box-dark +// +.card-box-dark { + @include background-black; + box-shadow: $box-shadow-dark; +} diff --git a/docs/_sass/component-card-code.scss b/docs/_sass/component-card-code.scss new file mode 100644 index 0000000..20e924b --- /dev/null +++ b/docs/_sass/component-card-code.scss @@ -0,0 +1,47 @@ +// +// card-code +// +.card-code { + border-radius: 0; +} +.card-code .card-header { + @include background-black-light; + border-radius: 0; +} +.card-code .card-header h5 { + color: $color-light; + font-size: $font-size-xl; + font-weight: $font-weight-light; + text-shadow: $text-shadow-xl; +} +.card-code pre { + font-weight: $font-weight-light; +} + +// +// card-code-dark +// +.card-code-dark { + @include background-black; + box-shadow: $box-shadow-dark; +} +.card-code-dark pre { + color: $color-light; +} +.card-code-dark pre .c1 { + color: #009900; +} + +// +// card-code-light +// +.card-code-light { + @include background-light; + box-shadow: $box-shadow-light; +} +.card-code-light pre { + color: $color-dark; +} +.card-code-light pre .c1 { + color: #008000; +} \ No newline at end of file diff --git a/docs/_sass/component-rotator-dark.scss b/docs/_sass/component-rotator-dark.scss new file mode 100644 index 0000000..465c360 --- /dev/null +++ b/docs/_sass/component-rotator-dark.scss @@ -0,0 +1,57 @@ +// +// rotator +// +@media (max-width: 991px) { + .rotator { + @include background-black; + color: #fff; + margin-bottom: 30px; + } +} +@media (min-width: 992px) { + .rotator .rotator-header { + transform: rotate(4deg); + position: relative; + z-index: 1; + } + .rotator .rotator-header-inner { + position: absolute; + border-style: solid; + border-width: 200px 600px 0 0; + width: 600px; + border-color: $color-z transparent; + left: -5%; + } + .rotator .rotator-body { + transform: rotate(4deg); + left: -5%; + position: relative; + width: 110%; + } + .rotator .rotator-body-inner { + transform: rotate(-4deg); + } + .rotator .rotator-footer { + margin-right: 500px; + transform: rotate(4deg); + } + .rotator .rotator-footer-inner { + left: 105%; + top: -217px; + border-style: solid; + border-width: 0 0 200px 500px; + border-style: solid; + border-color: $color-z transparent; + position: absolute; + } + + // + // rotator-dark + // + .rotator-dark .rotator-body { + @include background-black; + } + .rotator-dark .rotator-body-inner { + color: #fff; + } +} \ No newline at end of file diff --git a/docs/_sass/component-scroll-to-top.scss b/docs/_sass/component-scroll-to-top.scss new file mode 100644 index 0000000..441cbd3 --- /dev/null +++ b/docs/_sass/component-scroll-to-top.scss @@ -0,0 +1,32 @@ +// +// scroll-to-top +// +#scroll-to-top { + background: $background-black-transparent; + border-radius: 35px; + bottom: 60px; + display: none; + height: 50px; + position: fixed; + right: 20px; + width: 50px; + z-index:1; +} +#scroll-to-top i { + @include transition_ease_slow; + color: $color-light; + font-size: 1.875rem; + position: relative; + text-align: center; + top: 7px; + width: 100%; +} +#scroll-to-top:hover { + background: $background-black-transparent-hover; +} +@media (max-width: 575px) { + #scroll-to-top { + bottom: 10px; + right: 20px; + } +} diff --git a/docs/_sass/page-index.scss b/docs/_sass/page-index.scss new file mode 100644 index 0000000..dc90619 --- /dev/null +++ b/docs/_sass/page-index.scss @@ -0,0 +1,138 @@ +// +// hero +// + +.page-index { + .hero { + color: $color-light; + padding: 60px 0; + min-height: 800px; + } + .hero .hero-header { + background-image: url('/images/logo256X256-opacity.png'); + background-size: 100%; + background-repeat: no-repeat; + background-position: center; + } + .hero .hero-header h1 { + margin-top: 60px; + margin-bottom: 40px; + } + .hero .hero-header h1 .display-1 { + font-size: 10rem; + font-weight: 700; + } + .hero .hero-header .download-count .item-text { + color: #888; + font-size: 1.2rem; + margin-top: 30px; + } + .hero .hero-examples .row:first-child { + padding-bottom: 30px; + } + .hero .hero-examples .col-lg-3 h3 { + @include background-red; + border-radius:50%; + font-size:20px; + font-weight:700; + height:140px; + width:140px; + text-align:center; + padding:40px 0px; + margin:0; + text-shadow:2px -1px rgba(0,0,0,0.7) + } + .hero .hero-examples .hero-arrow img{ + width: 90px; + } + .hero .hero-examples .hero-arrow-ltr { + text-align: right; + } + .hero .hero-examples .hero-arrow-rtl img{ + transform: scaleX(-1); + } + @media (max-width: 575px) { + .hero .hero-header .download-count img { + width: 350px; + } + } + @media (max-width: 991px) { + .hero .hero-header { + text-align: center; + } + .hero .hero-header .download-count img { + width: 350px; + } + .hero .hero-examples h5 { + margin: auto; + } + .hero .hero-examples .hero-arrow { + display: none; + } + .hero .hero-examples h5 { + margin-bottom: 20px; + } + .hero .hero-examples .row:last-child { + margin-top: 40px; + } + } + @media (max-width: 1199px) { + .hero .hero-header .download-count img { + width: 350px; + } + } + + // + // featured + // + .featured { + padding: $padding-section 0; + } + .featured h2 { + font-size: $font-size-home-h2; + margin-bottom: $margin-bottom-header; + } + + // + // testimonials + // + .testimonials { + margin: $margin-section 0; + } + .testimonials .container { + padding-top: 80px; + padding-bottom: 40px; + } + .testimonials h2 { + font-size: 3rem; + margin-bottom: 30px; + text-align: center; + } + .testimonials hr { + background-color: $color-z; + margin: 40px 0; + } + .testimonials blockquote { + font-size: $font-size-lg; + } + .testimonials blockquote a { + color: $color-z; + } + .testimonials .more { + text-align: center; + padding: 30px 0; + } + + // + // features + // + .features { + padding: $padding-section 0; + } + .features h2 { + font-size: $font-size-home-h2; + } + .features hr { + margin: $margin-section 0; + } +} \ No newline at end of file diff --git a/docs/_sass/page-pricing.scss b/docs/_sass/page-pricing.scss new file mode 100644 index 0000000..5250c9d --- /dev/null +++ b/docs/_sass/page-pricing.scss @@ -0,0 +1,31 @@ +.purchasing-step { + margin-top: 60px; +} +.purchasing-step h2 { + padding-bottom: 5px; + margin-bottom: 20px; + margin-top: 40px; + font-size: 2.5rem; + border-bottom: 1px solid #ddd; +} +.purchasing-step .more-option { + font-style: italic; + margin-top: 40px; + margin-bottom: 40px; +} +.purchasing-step a { + color: #c00; +} + +.page-pricing .bg-danger { + @include background-red; + color: #fff; +} +.page-pricing .step-1 { + width: 450px; +} +@media (max-width: 575px) { + .page-pricing .step-1 { + width: 350px; + } +} \ No newline at end of file diff --git a/docs/_sass/section.scss b/docs/_sass/section.scss new file mode 100644 index 0000000..795227b --- /dev/null +++ b/docs/_sass/section.scss @@ -0,0 +1,110 @@ +// +// section-nav +// +.section-nav { + @include background-toright-dark; + border-right: 3px solid $color-z; + box-shadow: $box-shadow-right; +} + +.section-nav .card { + background: transparent; + border: 0; + color: #fff; +} + +.section-nav .card .card-body { + padding-left: 0; + padding-right: 0; +} +.section-nav .card a { + color: rgba(255, 255, 255, 0.5); +} + +.section-nav a.active { + color: rgba(255, 255, 255, 1); + font-weight: 700; +} + + + +// +// section-aside +// +.section-aside { + position: relative; +} +.section-aside-inner { + position: fixed; +} + +// +// +// section-main +// +.section-main { + padding-left: 40px; + padding-top: 40px; + min-height: 1000px; + padding-bottom: 100px; +} + +.section-main h1 { + font-size: 3.5rem; + margin-bottom: 30px; +} + +// +// section-article +// +.section-article h2 { + margin-bottom: 10px; +} +.section-article .card-code { + margin-bottom: 30px; +} + +// +// section-faq +// +.section-faq h2 { + margin-bottom: $margin-header-bottom; +} +.section-faq .card { + margin-bottom: $margin-section-sm; +} +.section-faq .card .card-header h3 { + font-size: $font-size-lg; +} +.section-faq .card .card-header h3 a { + display: block; + position: relative; +} +.section-faq .card .card-header h3 a span { + margin-right: 20px; +} +.section-faq .card .card-header h3 a:after { + content: "\f078"; + font-family: 'FontAwesome'; + position: absolute; + right: 0; +} +.section-faq .card .card-header h3 a[aria-expanded="true"]:after { + content: "\f077"; +} + +// +// section-header +// +.section-header { + min-height: 200px; + text-align: center; +} +.section-header h1 { + font-size: 5rem; + text-align: center; + padding-top: 50px; +} +.section-header .h2-outer { + padding-bottom: 40px; +} \ No newline at end of file diff --git a/docs/_sass/site-default.scss b/docs/_sass/site-default.scss new file mode 100644 index 0000000..0a5e2ad --- /dev/null +++ b/docs/_sass/site-default.scss @@ -0,0 +1,116 @@ +// +// default +// +a { + color: $link-color; +} +a:hover { + color: $link-color; +} +body { + overflow-x: hidden; + margin-top: 120px; +} +hr { + background-color: $color-z; +} +input.form-control:focus{ + outline:none; + border-color:$color-z; + box-shadow:0 0 10px $color-z; +} + +@media (max-width: 991px) { + body { + margin-top: 76px; + } +} + +// +// container +// +.container-page { + padding-bottom: 80px; +} + +// +// bootstrap hidden restore +// +@media (max-width: 575px) +{ + .hidden-xs-down, .hidden-sm-down, .hidden-md-down, .hidden-lg-down, .hidden-xl-down, + .hidden-xs-up, + .hidden-unless-sm, .hidden-unless-md, .hidden-unless-lg, .hidden-unless-xl + { + display: none !important; + } + +} +@media (min-width: 576px) and (max-width: 767px) +{ + .hidden-sm-down, .hidden-md-down, .hidden-lg-down, .hidden-xl-down, + .hidden-xs-up, .hidden-sm-up, + .hidden-unless-xs, .hidden-unless-md, .hidden-unless-lg, .hidden-unless-xl + { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) +{ + .hidden-md-down, .hidden-lg-down, .hidden-xl-down, + .hidden-xs-up, .hidden-sm-up, .hidden-md-up, + .hidden-unless-xs, .hidden-unless-sm, .hidden-unless-lg, .hidden-unless-xl + { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) +{ + .hidden-lg-down, .hidden-xl-down, + .hidden-xs-up, .hidden-sm-up, .hidden-md-up, .hidden-lg-up, + .hidden-unless-xs, .hidden-unless-sm, .hidden-unless-md, .hidden-unless-xl + { + display: none !important; + } +} +@media (min-width: 1200px) +{ + .hidden-xl-down, + .hidden-xs-up, .hidden-sm-up, .hidden-md-up, .hidden-lg-up, .hidden-xl-up, + .hidden-unless-xs, .hidden-unless-sm, .hidden-unless-md, .hidden-unless-lg + { + display: none !important; + } +} + +/* +@media (min-width: 1400px) +{ + .container { + max-width: 1340px; + } +} + +@media (min-width: 1600px) +{ + .container { + max-width: 1540px; + } +} + +@media (min-width: 1800px) +{ + .container { + max-width: 1740px; + } +} +*/ + + +// +// Bootstrap +// +.bg-danger { + background-color: #c00; + color: #fff; +} \ No newline at end of file diff --git a/docs/_sass/site-footer.scss b/docs/_sass/site-footer.scss new file mode 100644 index 0000000..928938e --- /dev/null +++ b/docs/_sass/site-footer.scss @@ -0,0 +1,14 @@ +// +// site-footer +// +.site-footer { + @include background-black; + color: $color-light; + font-size: $font-size-xl; + margin-top: 60px; + padding-top: 5px; + padding-bottom: 5px; +} +.site-footer input { + margin: 0 15px; +} \ No newline at end of file diff --git a/docs/_sass/site-header.scss b/docs/_sass/site-header.scss new file mode 100644 index 0000000..4e2c830 --- /dev/null +++ b/docs/_sass/site-header.scss @@ -0,0 +1,125 @@ +// +// site-header +// +.site-header { + margin-top: 0px; +} +.site-header { + background-color: white; + box-shadow: $box-shadow; +} +@media print { + .site-header { + position:relative; + } +} + +// +// nav-site +// +.site-header .nav-site .navbar-brand { + padding-bottom: 0; + padding-top: 0; +} +.site-header .nav-site .navbar-nav .nav-item a.nav-link { + color: #000; + font-size: $font-size-md; + font-weight: 300; +} +.site-header .nav-site .navbar-nav .nav-item a .fa { + margin-right: 5px; +} +.site-header .nav-site .navbar-nav .nav-item a .fa-angle-right{ + margin-left: 5px; + margin-right: 0; +} +@media (max-width: 575px) { + .site-header .nav-site .navbar-brand { + font-size: 0.8rem; + } + .site-header .nav-site .navbar-brand img { + height: 36px; + } +} +@media (max-width: 991px) { + .site-header .nav-site .navbar-brand img { + height: 60px; + } + .site-header .nav-site .navbar-nav { + padding: 1em 0; + } + .site-header .nav-site .navbar-nav > .nav-item { + border-top: 1px solid rgba(0, 0, 0, 0.3); + text-align: center; + padding: 0.5em 1em; + } + .site-header .nav-site .navbar-nav .nav-item-download { + padding-top: 1em; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .site-header .nav-site .navbar-nav .nav-item:not(.nav-item-download) i { + display: none; + } +} +@media (min-width: 992px) { + .site-header .nav-site { + padding-bottom: 0; + padding-top: 0; + } + .site-header .nav-site .navbar-brand img { + height: 64px; + } + .site-header .nav-site .navbar-nav .nav-item { + padding-left: 1em; + padding-right: 1em; + } + .site-header .nav-site .navbar-nav .nav-item a.nav-link { + position: relative; + text-decoration: none; + } + .site-header .nav-site a.nav-link::after { + border-bottom: 2px solid #c00; + bottom: 0; + content: ""; + left: 0; + position: absolute; + transition: all 0.5s ease 0s; + width: 0; + } + .site-header .nav-site a.nav-link:hover::after { + width: 100%; + } + .site-header .nav-site .navbar-nav .nav-item { + border-left: 1px solid rgba(0, 0, 0, 0.3); + } +} + +// +// nav-context +// +.site-header .nav-context { + @include background-black; +} +.site-header .nav-context nav { + height:40px; + padding-bottom:0px; + padding-top:0px +} +.site-header .nav-context nav li { + font-size: $font-size-lg; + text-transform:uppercase +} +.site-header .nav-context nav li.active { + @include background-red; +} +.site-header .nav-context nav li .nav-link { + padding-left:1rem !important; + padding-right:1rem !important +} +.site-header .nav-context nav li .nav-link .fa-home { + font-size: $font-size-xl; +} +.site-header .nav-context nav li a.nav-link:hover { + color: rgba(255, 255, 255, 1) !important; +} \ No newline at end of file diff --git a/docs/_sass/utilities.scss b/docs/_sass/utilities.scss new file mode 100644 index 0000000..8be34ed --- /dev/null +++ b/docs/_sass/utilities.scss @@ -0,0 +1,50 @@ +.btn-z { + background: rgb(204, 0, 0); + background: -webkit-radial-gradient(circle, rgb(204, 0, 0), rgb(170, 0, 0), rgb(154, 0, 0)); + background: -o-radial-gradient(circle, rgb(204, 0, 0), rgb(170, 0, 0), rgb(154, 0, 0)); + background: -moz-radial-gradient(circle, rgb(204, 0, 0), rgb(170, 0, 0), rgb(154, 0, 0)); + background: radial-gradient(circle, rgb(204, 0, 0), rgb(170, 0, 0), rgb(154, 0, 0)); + border-color: rgb(154, 0, 0); + box-shadow: 2px 2px 6px 0 rgba(0, 0, 0, 0.48); + color: #fff; + font-weight: 600; + text-shadow: 2px -1px rgba(0, 0, 0, 0.7); +} +.btn-z:hover { + background: transparent none repeat scroll 0 0; + border: 1px solid $color-z; + color: $color-z; + text-shadow: 2px -1px transparent; +} +.btn-xl { + border-radius: 0.3rem; + font-size: 2rem; + line-height: 1.75; + padding: 0.5rem 1rem; +} +.btn-sm { + font-size: 1rem; + padding: 5px 15px; +} +span.text-z { + color: $color-z; +} + +.list-underline li { + text-decoration: underline; +} +.list-light li a { + color: $color-light; +} +// +// list-checked +// +ul.list-checked { + margin: 20px 0; +} +.list-checked li { + background: rgba(0, 0, 0, 0) url("../images/list-checked.png") no-repeat scroll 0 center; + line-height: 30px; + list-style: outside none none; + padding-left: 30px; +} \ No newline at end of file diff --git a/docs/css/master.scss b/docs/css/master.scss new file mode 100644 index 0000000..317eeb1 --- /dev/null +++ b/docs/css/master.scss @@ -0,0 +1,19 @@ +--- +--- +@import "mixin"; + +@import "site-default"; + +@import "component-card-box"; +@import "component-card-code"; +@import "component-rotator-dark"; +@import "component-scroll-to-top"; +@import "utilities"; + +@import "site-footer"; +@import "site-header"; + +@import "section"; + +@import "page-index"; +@import "page-pricing"; \ No newline at end of file diff --git a/docs/images/arrow.png b/docs/images/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..d476391882b71e774f2454db02442b6957d70df8 GIT binary patch literal 4285 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 Z0Ma2btLTJXlRtkbIPZ72ueS?I`yc;mZ+ZX# literal 0 HcmV?d00001 diff --git a/docs/images/list-checked.png b/docs/images/list-checked.png new file mode 100644 index 0000000000000000000000000000000000000000..1083e02c7034ff16d0b3bc6486072efa839fa490 GIT binary patch literal 1253 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`f(~1RD^r68eAMwS&*t9 zlvv ztM~P_^2{qPNz6-5^>ndS0-B(gnVDkc=wf7Qv4~Pj*wm=R%;iu*SQ+p9GS@-^tR$^dajP!JI45_%) zbNQ?`Yof^Uk29@RJPWs9a}qpx+euMcT3UbNnl~@BrcH~u6%lbmGw_wxO$8zDZfzy* z#OLxCz6Ql9)zp_RTbB9mPW7wJGiE-YWBJ)8{m$oP**r73H zPmk1`B=Pbe&bqrcG`Rcx^mhvX1-s^i`LiM@&e3-z9k6CwIxjwwU;=|J?#(E z*No#Uf-8I$aOQIEw$M>nDXD#JUy{3iXrs}bC!W_%<|sDn?=D{xlj~)f_jVcAKR1=- z6S+!%Em-V#!}9mT$k}_#?q;RWKlO3uI;#q2*>xX#mCq~|wlzF?^~9=)d&d)&Q!HYGVouVymev58aLBrNx_@jsPw3$Glzd3y4izSRcO zGO0%m=56ekwBDCA`#+n{;{(Tb+P_NwwD_>ti}H0_lFvnbw4K8${-4``p~=S0^WoXA Q(?JD~r>mdKI;Vst0L8hw*8l(j literal 0 HcmV?d00001 diff --git a/docs/images/logo.png b/docs/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a25dd5370a993537f336388acc6c2825f7019cf6 GIT binary patch literal 1439 zcma)6`B&0;6#bxxs9y+65K$>Jb1K}LQBljleanb&X>`;ktAl1Pm9{#Cg}Izu%G}B* zmu%5QElbC(2r)~HO2yrzNGTOFtyCPE`3L5m^X`4`{qWAc=biIXXuj?!O@bx>0Ojf7 zLRYfo&qS&!F>FBNfs)_{sN1Oka5J#1J}5XeFfho%!WM-ltia%(!(gti zUPR(XOG|PIgE1kK6>r)kEGg;s^_`!ZN&$ck!1DC8Qence)5hur~y2S6zR901lDo7V$iU}$P;x*4ObkJB}_w%L{sz~aI}1pp2X zE^h9={sF-xlC6)=uJ02QX#j+WGk4Mhtu{L}HnyrGagTAhv9b4mgoK-zm@dxFMnuGE zXrOZth<-M^+0XAah0-SIm=cNRB@%gGUxA59V&ZvmOw5~8ryA_+HlY(^rhxV0a1b3YarmzUoi;c~kR3$rg3q#799!(b{xLV7!1c=w#yska%BUQ72CbCo4F?2mFqmD{$jgZpi$AH_UujeUO9vy(=T zoYQBM$2x~Zxn133{K=Hp(+uh7^!$dA|IY9~P+{NKcN+ke@18DHhDY1y9BDuw4bN9) zm6NsShx}xd)hFx3Dy;NOOBYNR#}#v~KHx#;!@r`ZP+#Is)UI9{`C`&;*F5hye|o48 z{&ezaKq+0omdRwv`%*>AtsVPzsGMz?P@zqqub#2_n=yxPY2^r|^2?MB9nm38u&xcq z5{E_us}IiwU~Q+ds#c`Gr)*wnRDN25TaEMXN|dX$1mm&@L~kEND9fUgo~ zTjs9Ec}w)V+^A`hmCYQ4AN*-3H9{WO^KQUX56`^tTI=n%`IlqFS=y}CqFq>azfq02 zdSUBcioTw(T5IMyCQ0;rK@aO~g3}?}$jueEQ24z(^_VT(@#R4Osv80<(a}Mq$}Ovf z9gxf|x10?<_+!ah0HrqMS#J?DRYl{0bF|I97Iwpz4xx(^m;2*>qnGhY?W$jPW^-6e zS(mH(yswpolL$wD^h*Sp3+E<;Q=UmMMyCDX3B@P#iK`SvavX2X&1*be+zU=5`Dj$ZjbEH)Lek{^-Q6hfs~2GY*4fARUKi5XkB)p=*>BVsqQ3u0{owk; zhN80(_6ry5>S$eSPT{t3v)17??uBjNAMTvzl;02?J${7wFaxTwG$*g3y^A-_Vi{tk zTWb^eRDXJ~NT(GqOO>dtc9$>@#vqVn0^rBfK|A0Nh^W&i*H literal 0 HcmV?d00001 diff --git a/docs/images/logo256X256-opacity.png b/docs/images/logo256X256-opacity.png new file mode 100644 index 0000000000000000000000000000000000000000..9e36e8c36380abcdb8b874fe3560fb9cbaa6d979 GIT binary patch literal 19064 zcmdpe^;=Zm7w#E`lx~o21f;tLq?Ht;Q>42ahAwI86ckVzq+1XW36ahrB&2(2?)iN0 zbN`9^!#ro6HG9rEd!N15de^(&nOIGACEO=Zp8x=WtD-Fb8UP^RTL^%O4jzo%%dNo! zmaDRX2LNCb|M!9bIe8SI5yMkOO#x#K4IP)6)b=a0(Em&d`ku00p0+OTz?bR~WzdA< z37X`sJS^SqTs`evoB?7i1}4z{sfzosF$0P>DYx4qEa4XLYx-_-`n^r=61( zAcVxn0zbj}?-OkoYfm2wcPqfe_3^*q*#A4Zork5P1vu0lXzuxz1e!7bGwWHnJKH(i z06kP&(Vz|E|9;=g-O>uUcnshBf5YTloSdwjJ%P)SjBe0|{@*YiJ5NU|p#1O;8vxJ) zD)O>AzIg}vK7k}w4}&o6ChJMLC;vial$AeKW+i{k zC!g)xNR59t&?3>{B1ypuB}h$9E;tZ4yL*^RT^`*(bbKW|zkN^SV{@53pS>R_jX2WY zqKqOyc@mkLRVx<+kUX*4DMFX|$jmzhuzx^}dJ06Q_Gm(jG>Ite0g{&}a=7ppD(2-7 zO?E6CA>av1=*Ryb1|Nen|1g)FpFg^D;jdUT%jX|NR5D>pS+GsfXgF#s_%vg~mlvmx z7e~gJN(=!WFl8`9nN|9on+YqXIk3WHDs?&Q^tt-q@uzfkN&ort=fxcjl;yz!^J6!{ zwd~WU2o((t8*Odv*1vz>>6T4;7*=I$zu^E+nqj3+25ej>5v>1iKMP4DN15G}k&(=U z;7PcWq+&A2r!uP$>=%z(la5+9*a}|8=I7I_Pm~<|S?i1bry!(SgwBie?D=!6`uh5o z{e4Gi7MAqcy$g;4JrAy5uBhgi5IN>`5m>F-AH1VOl2t?`b98icV{&p*M?By3 z^Xo5uQ5Iq^Fqu?PBb1@?cvo@lu-$;zMWy3I$D$AnS>(nF9h4Ub8fAgmC&Qd-+n_)4 z!pEn%v$IoeuI<9cj^N=PNu(w;M%&%pJ?ri+P#6X?OHWDpGGl*XpJCAhv`gqO7bl*~7hArD4930d&H`9^g(MfaBh`C3Y!sRf9 z;G!j8zs5c1;CO9imGEchLd8DHEp~;$mnX%)3z;_X3wuT4Pe9NX=N;q?0IL~G*la@H zNk>`q)N!qe>JljAZthIzI>^a|yB@E~`ZM4`rhs+$-Q9$$n;Vv%re?W{n%bl*bxlTI zvCs4x1i`*{h3N5@xQkz~xefKY*NouNThTi{ee*<*GRmUp^%wa>7TuD%*@ZuU91-)@ z3zKJEHl52Act>enP$=3F(MP?0pP)k)RmO&u#z>Cu;^^u1>(&2j&}AxnaX>bB@X;oXzKtcMrP;N<<@lI-?q#inw|Ns9b3UQZRi< zHE>i6E9muAFD`DK0xtJIk~@7ULMM=`Z)nJli+j@5(js3rvE!A>EEWknF2)GM3O4_Q zOZKsImXn}hANfpmO^##lxo1e!nzZ-N6jED3`)Bh-4OyzorBVUj*wOeR6Y(N1$|3zR zZEfPtOD!i0e?RDSG83)nUCF?A_Khi$4LM02AIH8E2gfj8ieJiDy&&uw31;3lFJtah z7o-p@ZE7MrLn1;n0&p4OPh~zlNDFROh^W#tr6AXukUkZUv zN7a43MU{ga0eS{|o$UnH?%f>{I%89N$SRi zPF+>w{5QKv)&;9_z#bsvwfn>DeRqYW!qF(KLV~I&Z7<78d|XI*j=f|?B9ECOrOfPTqAjV<-f(BsLLg}j?`t_?Gt{*U4WyB``z?tM&4vF~L;dgdb zT>R(V3yLb6VV=i@kdzzKZ(ZaMJ@F>$f!r29v0=$sP};&tl8$CCChP~Jx12>}T4gwhjCqsZPQYF+9!a^ooP{@BA1G*y?Op|^XF0YB48 z6$piGKIv6V4N>KXFD%4niTDV!s(lSrEE(8Hg2j)GahD6(pP!%CwIlUk55IiXqLRi+ zN!)6(DjYQdC4l%+0;2#4zq7HJwuwoFUd07^`|=n{0pYmz>O(}#amhCqgQQKF7d|wW zwl9!u>&KDR%yP;1RD>w9Bo++|GMKV2?fHja#`D#+5owpHfA9bL^6&PxY>h@3JLc8; zubSHZuT&O|3qAFTST!^UC^!QjNVE36EfLL#;9OUeNO11h^fWTt;Ss*s^x%E)T6{-s zYVxixu<#3?wzs5qAdQN5c@Vz;C&kMVKvJsuapT za;@z0s{EMN!IAIZ?9#Lh4ROMIfkbUqe+^Vw8M!`&yN$w{FlD?AD*C`##Qeq_Wkzp- z6o!!HAlc`UY=JVH`y0YstWPKebjIW$q0V)mE66iryx z<6Afg6sPchz$d~5-dCc9l#$Yy<{0qOF}}zt6i!( zN%;NqoTE274hd$LS-&d@zUDw{p$wyECRQE;DpA8M`-?~f>C!t%9K7K_9OWc*psCiieHS*zt$=o#V$J!j>BB~TDMK32Kq)dE8akpsAySN#W9eG zF}J&7_P1}R^##VUr4T{QZu0MmTSiX?Y0w7yLX0*IA5DJa^n`b4b!I4P!cg^WvMPhC0ZY`n3mtu8z*&_r6>2;D!xYKXv|4}NAZ@r<1PuDrm{$dD#E|+>%-4pEg>kXu1MPeLuZO6qXJrTRtkviG} zbuN1|gnUQl`~V(YEcri2btZc*E?YJE`BT;iSq6k2ayr3p{$W4qd?hS1b|mGAiN*b* z$OW#I(IY~`ym_9c>QJ19Rh1&z&%?&zp>D9q{k!j{vNE~PuNB^$7sM3PN5Jn$UYglF8Q&h`N z=aG~hiH5!XvD%vvggPH}9p2skD~V-R;eDE*-+5#8O^{ADmEot<&R_`osw6(_h!VXP z8>PW+lDqGl9dUnHSl}zmjoP5^b&y0hnMH83l2y8Xr;>4UdTwNB=)Cif?+X?t{g2mI z_vi%Ew+GNeo+07mG!{`a7L|x;`*3EJq2b~F_mtYTR}pBUTUpuc92{ZlWza#lRZ;FH z*au=+g5%`@y5q5KScGATn+7Ih?p8ov?p?q(znf(J$ehi)CgU8ifNFzyw?d6!_s^$;!46UmSE%pWas5P(sF6#{!x?}+W zC3h4rcRGq$j;K`qOW*g%GhUxV#}Dc0j6y;}#bkG`gbIY6Qd0Vjy9%B@UNRN0!hB}U z9>x3$^d1Ao&!}5Q+^NME7F&aEJ%4&^kCArY>{hJJNM+$Doo5192RCQTA90K7>t9+5 zE~M^<(YXG7fc_|x_awAI?V1od77k@>;!jH!(yq1``9$%CrjZ0; zc6Rn5*`0prRVaZ1#4PYyNZR+2>6oLcA!SDUZcOBu%{S@Hr-pIm7fy6kl-$>;Z|~$x zOq|BIMvbBrN{Y^$VT~RWM3pDw3g4ghEVX)EfBJO(u3>(N9|x+pK}OFbjkt0BjUyYo z8ZOxM?3UZgAQZMHQQV0uoJ;fN*|RK(AR=|+4uZ3-QAIa5K2Px~?ep-o^;W|PU^_dDHhimfva6`~O`Yzkg>PR?HN zd4RiPgV*gX>7U8T;u$l#=ki)T5=R|LjfFL6gAU8f!7_rVN6Zr&}=lW-LNb zom8n_>O57epSIu3^UFSveX;+tSxp(r{*1EZV0V8qE)^BMi!mx`HE5JRdG$lwY>7R< z&av2?a7%v|QZv{krELs`OmB%wU8>Y`@ewI&R&|LB`H@@^Dg}keL?g#&-XF+ldQ4k; z`|sKsFnleNo(i3@v-s52O>E41B}pes)npYF{g)I1G^l-W7f!|`=*;&rM$N^l+BXpwt%E2rAWnXez$~(5e)+z90LtjRvQ;pRVI=Y zaOFQTgzcvHF|*xb5gd1#muq$T-Fn$)1gL~$@n}yIo@$p)t)EY-_qz>_%BiRjp5J_u zJ?O$F*CLtt?TV=ZJJT3^qLHFxaxBe@6T|%WHW7N0vs)+JulGjgwr_X(*=_J$%JgLo z_A_uLtU({O6r`c)6c54Q!D(K5p5x{7BMiBWcb^Skc8>n>R>9DagNz17*DZdgGg2T# zV_;yQ`DMzD>LAE%`S5n3d!_f#1O|OyvF1WxA?oS<&Ew!;{szPg7JD;=8z1##EO&R5 zZ?6v9rO>z_ywPnX5q$7}lVxt`av3X*O}se2a0tYKtGzL8esk7$z33xkADj`7_xDxT z!XSFII9W#%J<}^IuC7LZ_Uzf=qEj?+F}pdU>)!XUm3)n2L0ZRkuCd)z!a=u@)FOs! zxE%5+DEO$;*1SEWZB&4LWRl4EZ*A^*T zw{j$C`%A4<tpxY2LWt{dAx#$uo^Iv2f_8--Rz9Mb~UvWEV)ah^i$ z(MA|?{UA60FQ&AmCFV<(W|f3zc{()DF1Y;p z@>-YVHnin+k*3DAJ|mY4C)_%ivhth=cY-Y#PM%o||Khw@ULNJ5K#x#f`JQC(Dk%Bj zT?Ef;6^5wNe)jWKQ8Iy2je+a!!h|$+!-%CN>gHo5qC}j*h>*JtQcoYDL6vi41h}jE z+T!Afuz?>;hu{032Lo4Emy2%STIXkpBSMg~#co zNA+QYJ-fhf*dFe$`Ya(2j^MLg7X5Fw5O?=_rBBBum|<|W+@{q8k;jCVxCd?uyaT00 zv34mlBYk~(YVj$G3N9J6!O1{TVD9mH`|7fFyC||`bNu>q+|kY1V2lvFxR?>-Q8-NW ze4?3d0@TP4hJm~n7{+lIyHEB*+-AD(v*0#j1o*N6AD9ktF-osjZW#`>0>H>O@aOZk zeNo|DB<>kglTMglCi zvPX4d-pI*|?VsS)K^Es>XTrIPJYV5;VafiITId;bB835TWC}-+-hLPA~Im9`{ZLg@hrO3Za94 zsmMMgQN@4G%!_Xr6NiGyVAb!<3rsp!`Nx6+TFH}s58hnybe#D&$3#TZ&z)>$?$ue3D(w_b@)xZA z{ZjAW4~`XYlf6oAvlg9|r-7 zN|=&mev%BSl0VCY@ro#VH54<&TsZsV?4DaM+V<)&XXby=&#;P&TBHNxI3k=qZs+iD zU~>G9ILsV1>(fW+PpiB*@)HB!8oeF9R%VZ7>>J;Ue%x{i={v-wLf46+ z=y4ArDTeW);F^Drcp@ytq+!Wt)Z<<$cUS)cm*fOPcM`B%-^N~VobSV^eH_dCm^ zULn0lvOyXVa`f;GhOAiDKyt7!I9RATo-Zqe7L+V*(2^xY8%?LNC9DxXgk>A*BFM$}b_>Ct*OZ z^FUVJX3Nbkr|YGG4LzsBhXD6cc?A*$Pj7Egwp(84h^z8rJ}=k%prFbhjCLS3vTxyu z#aa@=!6PD{dVE-K1%lMPj`urd# zFVC15uKDLw=gMw>?l`mCd^Xbz&-TjWo3%potcAQuXd0{9I*_kOfa*$3{-SePLkH=I z?MmiDio+WG0?3_yBJ;hNm~4H3D#LPX=*Z0gQ1dhDJswSH$C?$}?-E_sg!L z?w|5`p8wR6&4%#03SR!a^k{ON4@){~!?yQD>~8m8-m)u(m`6~`7#fOq`x^Y68uHe=veAKNmkY3EiNy|nKeOni*Dx$q@<@~C2EImL?NnL>p)Mv+lD#Rp0v9F z)}o3bqAsMu0-Zs+YIb&C8o_>srVu=`B+2aZQnB}KuSBK^di?zUn;xe7q|2=E6e}RY zb$4Y&I?65a&O;Y4eu8U`qDk*N?v2u;eO!MSgmybEKEU3NkpWSD>J$SfGtoE7L!mx zgf%r4@n*aW6Att((^I1B#%I^f%L}1PYinXCg%={y_ML5e{#!lK!JAw8U;?G{q@N8> zl-@&J^9-jaCkHQ^w=h)xZ7!fJ?cE}-h+#1$`Jn_%U;=Xk-E8fAQX{N4S#sZIBUUJk zeid;P9OJYoY;mO&LQd4yb^`+U^nIRgM<3iL{5=!X+vF4WKNiVNA`&ymTDf7f?o&7S zL6n5gUt11*;A3r2v#Oh0-F?i&grqPd8#ZF)^TJq?nNecTyV=H&^6ru>LycTw7=#y@ z9`{iB3G^4Jc_FVb?<%}D66PMzEseDkZGYkt+Stg1!S$!-7oX*?Ch*TqP|pD zTer2fy(W~u18PrB2J1YQ#lagOZwiph+k=rPMnJ%dy1~RGh~uZ+u`@9yy|0TF22qEG zSRMYeXXtk)N!^2%Nz(5@NDLA`Ij5X5B&c_{2s-myo?J+)k#W>>u0&cVO9%ViDZ0R8 zS${)A!{5@QrF6kPWwa&tfmOd-sngoJ;|aCUlwZEw%E`%<+PZ_%r>)$U9@934)YyNA zTOk2PEI3vg+j!4C5)s+zVIx;E@rNup5=_Pe1B#OEy9)2icQi2JraEubegq+x(_ZW7 zkO`@pT(pI-6W?rO!9X+!7+p8<2lgQ8}M9}o>N z&oK2Db8f%z{|~Z#evSLC7G7rjnkZ>YOQyuY3sU#((Qs*4h;pJV3EI>wU5@~m7nnY6VG$7HM0s*` z-}oCh?z_LU*=Dzg-rR&@)c&h#{(E?OCJ5P+;!Aw!!Q_RHjHs5jwxO}cV-FLY}J0*LmncMN;RZq`vQ*EhHfruJ-yauCA@Kd)``-dSPj17 z=}f%8^}$J641&ta1Je@ z{8z0A{KE$w=a8V>_6NF@RVfA(Kw`|mo%YbcPvYgPR~yosBDCTW1EAyfHm|(ci^Aol zN;oV})zU?mQ~8-pow-M7#?x^n4qs)Ab%>$lNXP4LKYe#0d8IkC!n!WsB(0` z;Xs%Z`cfJ}^Z&E}QF5Q!FaQE#clXniXxLITSZm^n=Sv?NUMs|-Rqf4uT+8?QUGM!| z+~*(+buj5ml#d`G@a{v#+wZ5Fa_*I3^ybJzsjF?6Szm3!!&rI9{HEU8fZK!l^ z?q0OnxsT%g*Vr`I?R=57PsAE<(;ECQkSu~QBu_g|`%JZ$$j#4~6|I?xFe!Gg5c0km zU~9avW}&hD*-x;rGG~;;wRwENV#^DIJzgW(d3cg?Z@M;z2nD;4w0IroLC51GYj(Sp$QIt3M6nc=551tqCP`Z3#Ai;p2n^zzrv<#y;1;#jop7* z>HCd44gDIWI$i6KCz)vTe!gqwkEM3hjc*xn3-|A=S(V~ppA{$T={Itr>1R5MCP1l} z{;!rHe*XNT&pgM4tsk!^s;%uy%k|b{p9c!y5ziyx-qvsqWoIA44;ULr2zd~YHmO75z(7=RbVZQc! z8>(y56OLcq|K}CAYx|w1>-k=d*5loo=-rqEueT>WQtqm&Icj+N=-vvzfyeqR@iF%~ znM^!>&NLfLVZvCKxRIy`iTcZx=P?%9a(5c9Wu$%J{D{Rye76R|)DV{rLP=_aEZABA zMf2tu#mX^pjD;02NE=XTzdfc1c7YNrS2R??dNBd^@DGybwe{t6?v_zZxm z<`-PijrSfW?FjB4=l`^qI;GciAt8bLe3jSTkI?9cQoGh~hz%bSh-b7P8KHn9j``_d zmCDgEszhorB7@FC3N1r%ypYFRGq993E}!0&b^3R-Qjc~~p||ndp{93k;R*VwT`+xU z`wH|Fy%$p6b$dvWFKf;m3-+v5>BhUmnwp}n;vXVL=O*(OWvO| zWr=$|ncDqrE0al7M8MtxID|Ggojvm z84{W#WbkIX2!UQ&5J3+^VAz*QYxDW~Uv7V5ceK)AgzZ|@T|-FkH5a!bd$=CpBmY4^+&$s2&rOD-=QTaD%(qNNe z@avnTk8N#FIMT&Smjj!cgsF`?pZ>QF1vmaaIY(_%A4;!2>OcXd<&gb(8z#%)54Ht~ zZ$VZQNfiRRaCbCA$WXLWe@$g2SVfbs>UE2gqM@OwuPJT+dHh#5c#I(U6O7-O>zvff z)%}rZ7M&ODnx>_sR3MsN%EVKLV1C1@mHwAnAYdENx!a0Drw%+6qtfj}&pYw zQs~4L4z53cY;U|5P*;%cwMDkv+df=U=~nlXBbT7G44?0-H@g<2L@#^@o6&h4W>l*` ze;zmIzl_WTmtVC&lDI-wDsFgqE(X!!Kz@0@$zvP%k40aN^_W6*^^M)Hpq3-ZAmE;$ z8;{kDpk1SkjAmBZ`FGe$9P)@UvQ^znbEd%zSOfN|xzbQ_6JKt1F)Kch#EbXu_X*68 z7|-At9AGQd5d^zU^TF5*atp`XD#lM`3=E#7`lE7QWH@6zG`Et1;93f!yJa3P9sJ4bnO@p>#9EgS0n zk>uRHZi8cT-k0ph)cD-!;cci5ln&gjsIcyb8#tC!*c4JKbAu6FgUtV&@$17$*|L94 zcjaqkI*@H#o427;c=N{dhl`jeCI)Q)4(_-l)WfHF|DgFJxciOEk63`VzwdN#CbB|Q zQh!fQhHvY3qiXRE2;UI*@U@5HQf8NcKw@wskHyAf;QR|%s-O-2IMmwPn$hj>S@D}g zUT+_cjcTf{v^sYA5tLp(iEI&ogB?VVDknub7Y(1CFEGAh`}KE~hNR2ru%B;xAEN0L z?-38^uauO2S4+}+*8OrS`P&H;tq*g4ar@_w zd!ERPmGF+N34t25t zIN8}0KKB=E`Nk0~#g7eOjn&>Max+ml2hs06K_AHxqqE8Pda5qE<_l^m#FShIg5S=R zUhJJb_-%jO`^_-VhD5!^m6G1;^utuTyJo7!q35ZQ>2%xhHW~7R)zM2x&}m3t>w(x* zjAQ+1p%xOLS1rHCRtQkA-^naX_O3)XBrHX;pil%%zxlnj73J$aAq%d@#k4=T9&9m& z=RQ6gu@pjIfp`sLILJKFfSjU&q9VF)0md)IW(5RY05~l=6aQyiK|%FM+beF2tEy2E zqPK|$6H!V_6g{8>re%!VDD@}F+X`4+Z*pGLAl)PJ*0==g`Zt98G5zIo2n?^r6jzp{ zlXV%B#s61&yeHK-k_i5H-|>Ct&2I8I-_w}lnCfb7$?K`J+QnPOqz8Gp+?C3VOOQXyKo$Mwc_`oc(LQ8MjOWSTffa zvvT?Ar0dy=7+}49!dAF3slil!ON>=5D`8+z;&<$`eIja6nONxJedmi*hacr>6u{@gMDB!x;Uc9dj1 zrZJQ1QiNb{j9!3=IPYvA?_*9})xV0G;}e(Q@I)vE`iMEf*pWQ2h#S%Gw0rb+2$x<& z#O!`~fQCW%j?!%_`<3hCJ?Gr{`TJVM0Gi+}%Kh$J=PV;b^d)oZ*yBy zshrL1{`zF_WLiz6*ShX1zXA3E5o<*e%R7>+c1rj}&K>|IJr)7}{mcztG_G-ApYR22 zMhEF0Tt({Z`Q^yE?Y7nTTOa(tRU1Ijp=DF(#cYAIHWQVM1i*$~B_M%{e+^JigpB5B zob(|PvS5hAO6(O!5zG-(%@rmt%X3FblyIgU{x$gBoVP^*Hid6U_?)b=``Y^Me9qDo z=^}qBp#ty^yeG^&oENb5xK;X|{1k3lSiIcf7k?^oA4B=siu7uc2_GcCFeT|0-lZjg z8SkD`w`XB`QyN589zDOa!t#f{WzRS1zrt><>=*X*320^%( z$JX)1g_BCLtsdEZEbg-}l)is!@Qa(87Uq}B_S?B`k(S8D+2V_PWTzn#a!ohqBQ{g` zj1O~mI~`vd(>jJ$mobh}`hFkVajAt6j!v%&c=Nue{qf_o{sNPwTz`QqJRzK76RAv;c9@ zozGjyyEktpaOepX6h40)HM;!Q5hOss%GG(^+;X*kmPf9C9K-lDVJ>7N!8UOBS+`eE z&#ltA3Em~;-G>BSVHwHc-Pf;q*FHw07wpjY^5QHkEb!UuuvWJ}SdZigLDTl^Q*tw* zjfNZQN6~GjM@iNB5+|ES!O>A(d+6s!N_##iK!RepRvN1o^jOL3LOz4Q>9vm@TN&34 za_vfi&2n>Dq|aPgS1?_B{N`e=!I849*%^0XXxs1-=_e?F#-hkX?#2vkICs^#nJ3eYv)|`d@Nm%|mYJM#-8#u3%;cmhKO-ZjfV-6J z?5c;ub~C{^Yb1;HhfIxrI=U{5)-fe-w32@*O0|zoi}c_l^$Mb|)ejG%t5{=&93x@_fpwI{1`N|gN zRtPrIxT8-4ySw%V@sZO;T&1hHA^muA?&1&UWeCgf5phN9+KG*KwIxcf=e~Qc4 zzQFVH<6S^!2K;OaaixVwNj9k;t}H9Nx1N4GSP)w6eHSWEV;AmpIrZgoC$D#vw;Vk= zBjd~b@#y$&(L|v#z`WGBPDb5*JXe$u+|(Cc=QP21zCTCkZ9+%LJ-9A_l^81>pUH!v zKzUg}d)MO568x}dMx*`NFOckIkTiApD)4tSM*&wR@r!n;YyPr#XZ@gGuIq#g_m9t+ zrl?-Wim(b02HC8%i{u{_W>doJ+k$I1KaPO+i)K@p@b@c+W|+s-M$*Z_#catzrdd%K z@<);2ZuI2UV2{?L#>-bs*>B$T4Fl*^;ktz%ip6}7YdL(+MJ!JL8tA)iCxC<|mhhh% za+&Dh@2I)VaYWF;q_u3$D{iL#P4n9{Bi+}+bKXGF>k7WDrbQX7_n)h9sWP7Tg^=?o z4)S!jU|gc!-l7NaAdRjAcpyVxt4PyM&!W|!^t{THJ)m5yrF6@*lYI_FDder3{Vu!Y z`R`?RZVr_3+bZNMS4qu@d-*qbwM0p0v5M#TP1Neb^m@9^5`;28(a3vvh zT#ZLk6obZ*AKw9z@FjzW^_v+pv9|?~kvy?92g#++OsVi5uMlF8-9+PV-+zJZA)<5y z+Ey`>O$k7yPE-oT3w?Uu<>iJEa~o*2Rmd$NgoMZBNsylyyR@p&-H7${@Q7LW2EVi3K<} zFko+8i-NFaBr6kLN+YS8mOSwN@#tueQA?Gz?`(CT^1!na#gy+q;yV{UMPc&^zzrI# z(UKl`*Ya4%QQLl&k;@dWA2Iho;P%Zy%EJ}BXWR6fNh4nC0-Ax#UYgr~aYUQtOAab( zYOlv6CcZh-=+pnr_DAOgHN7N--Z^S%1=5brkV|H3^d7gTY95m*zy#v`$%cdLY+P<~ zP7bS2ng%}g1WbooBQC;yA|NAHkm}e(*Pe(7kPDW65^Y;N?%V6T3N(QL^|HzoS1T3$ z;MuRWcK}diZJ=u06{xQmLa&I<3wBx$l`AGf&e<3RbC{QW5Hu7L-tUb&yQvcWLxyH_lX|OuN#NV^g%V5r?3ArIwJvflPJrDgj4xj>l zX>6~uy}YIX$q8GWoPmL$j>j)uTrIm_H$_kSH-ZMQiADSAF12;6i5P&bu{SNS6Y z>)LwAw$rDf?)4|F+D}geJ8n3dmVM~Nz4woEa>pZId7flI2ms4*7~(tcNUg)Y51|({ zOW5h@toPKXv^%v6h4)!f+xo@<2S-Jd|0MVBQ4^&fVwOJuti10N86p^@3nO!JeKTUc zg=K&b)%pN!A$|ghrPtI%=G<;RVFtH3r1||7JY8c(BJ?5 zo5MZF{Emj>e>m*usGX*@wY5MlsDw2b$a6ZZ%h+cUej-j3Xs|qI!z|gO6{XR`Vzf?W=Z-HElzUU zSqhT9z6uTCj!uQlK|VY;<$9-<&F@I{Xe>Vp z*xP?KXgB%XFh9aSfr!h?dt0gR#w1zrm#LTV+A`w>AC4tz^3&>`%^8J;Dmdt|$Yq&4 zwOpF#jt2*GkH~II1hGcZxEQAg{Tj6H6{64X?-{ZHsu?t?#_Icc*OyvODdX>7YQKS$ zu-dxuxJz*Eyb#|GeBdxA=*I`-Q%B4VpiC;pk13)tx{ER`iVOfnqc0!7y0}VjHV#ij z0quVbPXL`Cs#G*ys9cB%*TP$zG6)aRWF3@U@=%oTXwEV^=muZ@=YMK10ei2nV{e6r zL9(K`TqQrX&-+7!@#czT6`PQ#$xkx+o zC1d4EihQ#uQlFKWZ&QND)G*t1A378U>sm*mJSWIU`QTQsiE`E$z2CDU+z-c&Z>KnC*nTyCC z>3u9JFV|tmh9X$-hw6PnH@Sl|VPBbk-c7?)@i>d#}n;1IGz(p6SVbgHpMES6O07_t73R*hn>y%P@Xi4SN-U`{+`m0zb@r+9$=l= z#9#yeZC=2k!EbvnImTe}$$jrLq+|_SaXFsI>8~p6viF$uk0RZ&uhrBrZ3xWtb93Ex zuD9J*vu%C{toFbs0@j`wJLmfT1RQ~{++A}8LQV@Yu@5p4#9<^Pe+7gkzU9;8=gs!e zy_KDx;{d^r;-}J56$dch^PjX^WSR1g0J$jCu=*qakj)p%V+}ZvB6W4eiF_Xp(bcOy z9kV1Fk>v;;2m9KC%S8)m*B+_c>TSQ9fF$~(a3{LmTXRI&c_(U5az@lbI%fdi_ZW64 zD8AjgoNc!4T&GR}qWa<_oMk|Li|44&tf%zNPKlhfp?%J>^Q~!>Fk!n14|x@2Q_I9T zKb0Q^{vC0Tw~(4jkQ8kDZ?O)F@%Z2)*mcFo1!^+~_n;{Xf6W*1-=Nc@l(*h{zj|%4 zR-1RuL_kOhguV>;tDHNo22xT6{L+P_oNDx`X5Ri3YN zEEML@c|Epp9yBd8$>by2Pm=Ug3Snd*fyLB%*tXYR;J^FDmk3rm@AwDb(5Z$w?n^bg ztQhfev#I*|%LYt{%uieqnfzR;tqFWQke5h7uJnCmE9{@pfJI`qFa@(S;^~f=$r%X> zz?B;?uo9!X|0Tgz2JIUA+`lK8M>qi;FUy?m<~L4?@KK^HT=%MGRmLUHbdcH_Qly#x z{^-R2I1ksYNUzjIYL|S_#riw*>?Z{?5VijHed2~vAeM=VZSa8*wf~Ksr_%~f&&jX) znCfGb&0?Cy@B@*&eOWLZUQ9Rbi+Oy{&a&1g$bhKk=nP&`#_AFsm`;TBp0Fvm`#k}PUY#!BM@}OXV`*UfzKW)(Y zL`yf!|LZizL(#-}n8j->2B@?i(RF$?6YzQf}zUqj;CADc3BQH29&+MkQj{J zy1(7qT$o%ZV~mr+8Lx<;KTZ)uZ=310=|rUu8l!$!;GwRQC}OM{a9Ok&N&frv^w&;B z4aRS?Zj53ckb$TZj?t%xrjhyilPx~IdFf9iDm^olor}v{F^PNH+smuYTpvzg`%V0{ zZpLi0_km3x_nRF1=2x(Con`YZ9D?sdu@suL*Cu;XvzrKi&MbzOB8chLxx(94wg(%|d9N z^K`&ho*U8k68;OKx-=gABH!a~RbrwLV=YYI98`NB2k3~?Sa;vK*9ePOwl;H064|YB~boiry*%EoFf&` zKYJ^s

A~O;`RHwqyB;$4l*Ns=&b!_uee{x>YIzLsVb2(J&x*%HD7M1R}FD53I(p ziftEQ_nrTnfNA1`1WCz-+2f17ikjl1?LrLs0GWsHV2M;!pOO);DE#rAnfL#onr@rt zznH_*G`Tv+r_Wa9!B=k0C3{IR>~tan3zL(4j)wQ73@Z7R>Y2~7M@{9H(`S$-RyzJt zPY$~zSfkmWChXjtYg7BJp?LF69!7QM~O=%FLc<5 z2o%tHtyL-0a&k(9a^K?spFV$%pPzp=z%x@#qlL?&?I>LDba$nGo5Do-!UqZORx2t; zAUIIocb&ep{q?KF-?0-Bl2r0|L!S6>i{L$2+wKU7-I5xa1@8W`9H?RNM2|$%u0pl`hFD~q@3r}136^c_$S6nsN zV?5Y(FS~j$Je8VNuoTOfhcDTre83*0mj|Nm0{OR>eIzb^{9xiwe#TM``MbGQr>3SP z1V_zZk$D;C{@!6WSeWtX{pqK}9j)7$^>w@eZSAPN%QcyQ-Ka8VhH-hk&Q}a!@D-PC zh1*=0;1c z@qYjEdOzOp$LsYRk$F&{JFJ;X$?%oUg@=`x@z$svc?~a>m*B^25t4OvYNK`T`Wn4q z0hGusX&dG6gRg&JbBbYT9YRv= zqCqkDt$>^wcv0=ACdQkvx#{Fr#w=~C5N=5!`&cT9N~Jca#p3QrAr8gDhfWT8a~#gt zC$Jb3Uh(IUu^*o&2@-0>wkUT671|ET0Eh{RMS7_rJytAmb_xsYGv6CL&Hzb0VeRZh z{rcrItr71wI^yKaCy}Of1(ppoU7Q-BN{oO*c+{yTbs{x{eNuMw2b2-mPt==;| ze69!+zaJ%HU?9Ed?4)co9&*ngg@S7r}dDY&XTy%Ee4Rmh&N@@1~8Px;C{2{E${E>MA0qP z_ji9lN24>i3McjT(X8<{+{I`@%_gHlvTbCsw>l@MsWBxbsl9PH_x@aTR=|ad&D|NM z`0$$vJZK2b2a4_JqTyHKg6ra^?$9hR)Uk1i#(%QorjKq=rXYkk-|pz<^UFPnP< zV~Doiy5_Rf^2Z19s=H10YW7N8+`c!4SU~bed!B&yBpP&!CulV_?G4-8jnA1Jmesst zxxj&zN;&sW^_rQp*kiB1_wLcrT;mQ=#LTRKH&efte~Jh^GL|wk?J?OOnv%oz-1_!L ztsq1g>{1?(h7BAie6lF_cAf&dd9SHs1j!Ce_rsRkE_SR&!^c+1&kbO5mur<&)FRUlIN+VA)w| zljQx`<|jdnfPnG`zstJ~womS!p{e*VQ#BA-Q$8NGuc@!k%oG)~$T3nd8nQ3==?{YK z;G*OPU28twbnWvAQk@6R$GM|c7fA4DvCl`o;821dUs+zBC(k3nMm(G82vl+OB5J53WtG#YdT`LWB=>@im=DE%O>n&;q5s<^ zGI9axvC~4b)MBav0;izkWazQg#hcJm@A>BZW6{rkRHc46Ol@@)v2NMeGiZAsR62fnjG?fG)QTXbRY-bT4|o0qyr!|t6S8GpYc=N5Po5d+IZ z##9y2dJHnu?-Vp43&4XUYwq)K7Q90-YOT5J1tdpXac?KL*F@sC=!Ze{53X%FXh#~YyXM8|YAP;9c{^fuw*nCdwd zB#u;X5xMDaYR{jBnF06&bt5Iq>aVfePNmU&pKQjQQ8Cok3$5mG3oIej%0oe+u1os0 zHzSQZ86kBIRdaDRAOP1g4Nc`rm>q?UJ z?khLvmg?cM@CD^4_YxmCG7S8w zk$Ef{Br_$Sjz=on#b{_Rk66CL%r<#&qd2UC&mpzB!&c} zvuM|nK(RiOmz9uJ5@m%b_bTM^8@0Mw4tgka7z+CB1I7S^D;C>go~06PAE z9}tj{MFIe58Xsk4H8t(QpTX|-U>6!?Sy>tvH?Zx;Pc{JXZ7EyZPDlHINc?u~N=7vt z@?91Do)CrRy-XB@Ac2XE78OS&oHqY2p;i~JygUN=U|u+UY%C<2P>UTS5^WKAo33J6@bRz z0^p$3eV}!JrUwCceqv&8=sJ=bgO}HFj zFA9`T=tar{2HXIFt!l3@u*d;$E9=`T0o6@F=Qs{}Er5anaBGE!umT9)fW;s^{Wl;u z9UxG+&=)&@Q;D<32Aiq$TCrvZVfg@K6b@HpeSJ$eD#ynKVjHo{ISxCJUg@l?wqAB7%3P!XVB@pj)C)UT9T`Lv z3F7opz<7dSZ-$=t6J0I9M<=JvFkSP z)PMeT?M68lZ@9x86N^rS_9zA`vy%YGpT0@u>;@^@(zZu25R<7<}&Byaj-Z z7I4=r3kp2MK4@dYT0x&nZi90RA$aGm4;3INFE1+Z01lV5d_uy-O+ zbRn*Ep+8v&1j{h=cFW+%pnZT)xLL542gprjnLYMWoP_KEcjrC{GGFf}ZqEK5nHnK>)FkVX8oF|fvVO8^y>j@Lh->SK z8V>}#0QpW-0R#^j8cQl^B?C1B^+ly(8VZKDxJ#&lsPMsB-OO}J#j5p8e{k=6NvwEz z!VHwy>F4p{@VRij!)1E~8So-xd6}Ez;goBB=uG2HD@;4Tr$1mX$$YCsMxQja^ue(f zS@=6U&6~lH?dtZQ2WCv}`LW*B^Jd%UTl&~%viT4u z45KBhBr_$GvvKK^l>RDRD@E76)E&`@D>2jdtyIwE)7~mUolPmzEzQI>q!3aGklIfGVD?7(UAS2l~-fF)!I*kZcSSEjh)sJvn=#W0Dmu2&DdX`uWT)8 z&y+1u;-w||!m@lSeEN0oFTdMLB5$R+-erAON8Mv7O1<=pTq8JT-DD;I^;WH!$Hv65 zG$l2~piHSut4#5zO`!6)DEn8Ne2d{@0G9NC3bP5bqFvlLV)mZ)U+vW*v?8K+;v(0T zoTZLG$@5#}JUX0UNKCX$s_zcp zon*X!*Zhn1m#CVk+Q8W8Si#tQI)A1(&jRmW=3eGPCbY@I=$jFHV{zke8|B(l7-oD;VcnDq4zgi<;Gw)XQ?_?Ru)u8;2T8nn3drp$tl6?R8#ypE7V}||3Dx)-_^mDIwBM{LOS<4vDI+674yGl9WvNM># znONl8YQ!I5?fsaoojIduM{L*Z9&{NV6`>k9!kH?;nMvNiI@q?Y^7-1;bi-@zKKIFB8wt1EEr~5L!8P7BL-SF=&Zfbp5se;jj(G@F)}Q|M!>iZp6i@_V z1lhqy1V{%M!#&=4`OtR6N{TGo+|>R(mX6MAmL`;r3#8hZ$AN&_zL3_KGHl8s4 z5i3N~Z-0Ig*>cx1s>ct5IV3DZKU6Z-CES2)iYJxdV`@d#9V+)Amm;^8X~&}>T*aZn z&n8jI=^(Zw_~-2($$m~-!_hf|Yy;&_suaSUY?T7epW2~M$CqK7*_-HF-o$BKgQhN? z`QzPJAw@(boOtXaDN<_T>O$Yoq;c4aiJ}=V@I4q~(LB2;yY1+>rUa(K7iCS@sMIf% z*xq?1{!3`(_hjhf`^mo39L!u2->QbGwwfuDLzMBA#)(&4q>U#iF(KYnrj+(wQls6W z-LCD|k#d`m+Lu1(s3tC|WaJ^oy7+QLLk_e?nP2-lMl1_#$hCGh`nDZo5yQeMWjSxg zjz{Z;m*WMqPIF(6@w)Lg5*vSps_Ju48tk@}I|$c`xq2?6Z4n~A3DrX?7yBLA$mTSs zQFg4KTItuuX+ zCG=lpS^2g@9tIxnNMHG0UsBfF{9(d&+V)^~jU&exE2T7bHxD30yg*)e|6LRm?o45bwmW^9) zpCyLcmvuq9@8)dhY#x;#>ux10BT5hMQXZX5E7YA_j|bqV;h&M|u^JbeXXhxV#dY4t z&A&NP#2TP(f5|@e;J_5X)Q!pN-=ueu^V~kTMTOo{VTvq$jrK0zK%SxgN@+*QOo$+XFW&B5DRAOrWaLwyUahV!B>#dlfr^=t|Gnm^&SQJ`{UNn$Z|& z$!f`{Y&LOhKJjX6@V31@AkPsTU%hJcJSTdcpUV*zUv0be0^j!CUPFmi{oI(J$46TJ zdN7| zJ<1W15EkB)bbCH{Dw3V}Fu{~V{8I2TQb|n2<##uCv@kxEHkF@xk($)ur{duM(|QC5P>zooN~*3qeclhQ!zXVDW_P-$bjfJB62px0TsSVNjQZnNB>n5DIFy?L?i^z(9qZb0s;aZ0Cra~pb5J`u>1a>-S~eG(aIw5^Z~Ai`%0fQ z&0@4E)$&^o@<^>(>g}IE0H6(4N<@&x3E$zD@mINZL4{BNp=Pb2b|^Jm0KxNeVbait z=-k}E+e__XUAE+0m7h8#Ixir!klc(t;Sdu}Y)uw|E{cIi9*iD73=%6MU|zhI+o=|9s z@WC&VQO$~(0W>s}PHg}VJnbatM+nX|gYx?jnzYCmg&x*ybq|#?Ct+Q4bN%<)+Q!SX zv&Az9SAi^%c-JHkcQkaSCU9hMSDxJ?GBPr=8yg!u2?+^7@bE!yI&8XF6C*Q*DG`iP zIJ6ewa_kIDMDEV{Ux>SN?=?IwJP1J32a5tb7VNLqo!s^`!C80+Gk$ID*HVsUHwI2l z$LFP`rNjOG{dyI8j)@Ehf!nUGuDE0|Ok84On-s~z{$xGXq_%IsOg_wsA{+h2%szIi z(A7TX)ro~;A#ym2olDABsvhoj1HB2?e_C2^{fxA=ujdYCisE$j^cqPpkSuAu5n;RS zPr#n11TU{la$4GVGU{9xbxqB)PqAByD#0v_$_{ZGEyjk%t}T@BJsLJwt$g*v!N+%% z!A(@}>nVG9W0|15AeB8E_&D7|Sn%n>JFGY1*&1K7}EyN}ev=i)8n>`Q_}z@RBxR<8;8L z;Hka7{?0;K`D2iJ5jnRR2$m?$#3mfyX5?L6U1?2C)##59`t9LI1lKp;QEuI+^Y{?o zu99smD=iLfHnl+`(t3xFoN}vu)=FLKS*1M|)(+1pW52La5ov^3k_>LwdNpT39p2Xa z85kMWKF^jE9PaKCY5Nnyu>p2G+it?t#KgpDSy@@+u!*UV$!}FlRDv)l&u?8fE+`Sx ziQ<4B|9UwFPS1%f53+u~6U7oo4;xrILtEjj_V_pvkks?QCFm)+^kj#jfx+1kY&FSZ6q2M6A!t(ONaVP<`J;n_gKBDOMtPdW zmGKO$KPrg&ooiy~7naOIJB8b8J})uW>E~$&<9xEzh z9Al{^zvh*fw-P=VKc%5{{sk%gd_OcjGh>a6NhZcc!@Vz{%rImc0bURhRauJ5Cxql2Y`kf8sHt~yK!dM!44zh}4;L6y6g zS?67i*u_-V|Kej{%LZ`f;v;~Pb-yG%5nOD1{7C9ZM@OeeDe}2EucV{|Ize=`-}#dY zve#kx?b~m2v$g6PSJ(46oNm|{ryAHqjVo&@7gicD+I%lW+++E)V;UngL`I46$m!g7 zm&DN}mtvC`F296?ARS*_TIWi*ZZ2XMsb@RW246L=0M`Ig-bij*G3w~hPzyH$!#`AM z9Q-kDgB#v!_3v{=rUj1K_3HTT_@0#1N0r{rk7D}-XwBQSLU+c&I66A>vF}U1AI%`! zv{O(})ZR?y%kC%?YULGv_W~pWOgQ)W`1q`mv8mjO)J{B7Sx{8GZK~CA*G^`$j%Gf^ zMuD@0`%zE33CoUIwxC+<$DXvN@@NnS6$=9*9-fU%X^dB~Z)fY!>+9?Oc09aEhIIgU ztg}VJ)^A8)r@y@eqsA;MVJubj{ks)!c+ zwdODI)jP>RJOfLS#%V!? zAx#Y~T7mvsj^g`7B-Ha76japiMyHN~@>Z{6y)rY=4@&d+FE6Drig8qq2$N-X2r+G< zU!MUCP<1LA#M@$PYisWQ{@(rhIVgvh>|M=xWyCGZ*ITXR?4z2F+e>)8ON6fyZzAcU ziB!2#hj8)9LsnKksbvUZ^@Q$7<;Pp^3=3+RLxE^HmG z2hN1W9=SYt?5;nL8Z_Z_(Ma?tv?v&8o$Fm62dOe5aOp#7Mc?4Ny7Fk2Jkg@T`8^#F z`#k(5s;02Zp|k*k)&{ACjjp5|RD3@B`Mo50-=2ui84q=lMLka3`iS9y)0UNNdt zLpcI{d}6}<4{Rh!3WZa%-0si0YwK$-OGP<0b#HGE+5#KRmN*Ao zZ+GWi4rPA{;EcdMy_Bf~d_sI;AF;EulgAz(^itza$duRGPw_cAwDQ127RxYlXRADo zScK}mA5XScPQ7cd`)Makq@}enI5gCMcV5Ut=TDM|$FGT8+;z!Y&AuFS<%9#vG0B7m zP0sWf3iRLo{PYkyeK0W~Tg>XYsTp_^aTLN<=ehnbo}(7~hPW)J_xVqF5LrN76XcTf zWTK~MyS?6(9!G|`IactKKh^z5gTA}Q3KnL${@=fJ*;}nad$bTf!{?Jdp{+G|+yvag ziHW`+5!O7P3^?)lQP1?tmO0uASwG64s4>yE-)%bnTWKJMO^H?J5%i}maO^Y)*&5Io zQ+hYknwFdU>fhpVDzTPCHyKIAp^}DTApp4-XfrWFp3HuQrNk~z&z@AWciR#}8x$Sa z8BaMSjYkhnVrMv6>if+y-!A<{`>$|uEeFTO`g>8WdEB;L7?_!5D)fT3vgmyk)6|$? zcz*rR@il-xELL`-XkXpO;0-Swjy&qej~U?EmzB-cmRGSUZ8{vRb=$NitBV>O7vL*A z3Md|_6Jb&W2(#=^C`26{A8-C^Pv?Qo1X?9N`n>?mw7mJ(YSCbd%WQXnX`0hya|)v2 zrK4zWHcYdiZ4>^5?XonzT>GL>2s-tzCPl`k2z_s({Pd;Gmi&>P8zZPtG0N5kL;d0Q zY@;Xj-&$Ky9dq!U#XpmAojhc!s%Two;s!lx;_SN@DSCr?4@vz~N zrap}Sd6P`S`vHgP9YxfTHWQ8epaqP3NHHaOCSOs~Ml$_d_6JVeAOFK$qoRxrGi^aA zpUvGZIo`&jbhY~`g2{#1%EZK1e{U|kLD>}orqWlSY?Ya%r;fB~O|5b(F^*QXPCtr$cqbNUJNXvKahrw3=W1zhKC!@&(4Y@LV))gqb1&+ZQ>>@ zRUwWoPfCd>L0u@yi8xeLp;LvIJdV3>)zY|;$YPLGe&SIK1Z@4LYPJicS&z&1x4L9D zm#);T7euHz+!bYbB@M79L0TfJxabT>dL11jeP24~(8T}t?ZbzS9PGMJNubd>F|)mB zVs`;_pm555R#~~EiJ!m0jI;4r<3O(tT_XjGx2Jq$m7LwcYwR6S8$0s>w#yWPa99>jWT{t z0aT_-j)QZ;uZ?JqCQ3KW2Kjb;hNy5_@p*!2F=ho!RN6)AozbM)37MHO)z#HE80}o9 zK96uT>jSxdeW~U?@MgPq%F|yNI_SGSvM~3l*wV(}!e)x1E&~JMsVI0Etj}MbkxN^% zv5P@@lJ4?r7c8)BKYTH*2$Yrpix4%Yt-9LUP$j(EH1(ouJCa|IS1Ejk?p0&U-Ub-k zpA^l>H$S{3vwWL@LqHN9Q5d?hVmQO|aaxFhiAkp9sxCg~XwI7n1@7?h@T|Y|dh(z? z{*BHqW$+)hb79BhiV$?W&W%YZ^KKkv>ZP5J&l5Q#Bcl=6k2tAA(m**-x#$w@p48oU z>Z0*2DrBzmH>O?oQEpBS5g7r6AK27M8_C7?4clYNYLE;yv+_Tq{W{{ZU7XCU_0G56*YYomoRj3$z4cfBj{ zF?8qGX<1d(t6|xkSH*jm(fW@DSO4m`9U7>@;Ql;#eM;lo(+cXsu|6O1gF9m;1jxg~ zQEpXLRI-;fp}gkb8Mp>9e~QjHWhc6DsvrHuMz*M9n78Ncvf%DE|Je)MM=l%x z-2a;*`?sjOjE!yko6B`CHa0fjtmnMK3ji~wquTT0u;3;(I0~}EqXLx?8S2qd3OB2T zO3A1;LbPpc>e%8@wW=q9qDFAX8VyR52To#gB@@;-+k*dK{OG4PvsS3ZTNjKTsY3+` z?{u%<{NU4BG~ujtKe;eduL_N!>=M4}>^@0%r$h$nDnSTN;N2ZbG+BCFv%8)3_MlI2 zXy}!&BQ&`)(4u>H%zU%+#n(c(<7U)fFwi4rPaG+1i#hUF9C@bqI~kd$k-k1gjy0j9 zJn5j;%jNLRv0SL{t$QHLh1;d-0N|sH*ctk(=m$gC-6JwbX{mz}58%q+-j4Io54@YJw*p&>QysuBj`M{i+aOtAQ>V{PPTQ*o2M3C;4@VZs%tMc9 zX(T^>{P^ajOWZg=S8;z+GjNB6;EYf`HHV)~2-nGtA^Po%CT2?MWd7jFE!5@@ZrduN z2SJ&4HPM# zXrS=e*!Q6!@}^p5T7rR{t$VHBx?d}C*3>!L@mmmuuW&?g%&P>Y66G*dH2Sil#(T2R zC;HaAg4lJvd~#I}g&m(`6zB!oo@v!{MbNkp*IGzI1BQzCq9WN&$==#e#!9{{dUmfO z$|fs+!)N0j!<`W^py^q zDtS(%Nj$CLNA5L0f=Konp0=&U%af{0*F9hUls!%ANY|xLhuIQGBwQ?oaOm|B6p7{( z-kBk6bLMBy)|T5|U$0z;fu3IFu_cHEYh4=$?_o#$Rtc#vK{v}2{N_*n<1aW1X%mz3 zj$z5OjLpr`;ID$vonbNZ-Y>#_O^x*N;+s9gp(M7O?i67O^q1WJYm909jv||zR*$+q zVC-E(bn*Ghep5Mcdj>VY}iVP+wV^y)z#dv#cIABa0mH- zXxvUiF@@@#j1@27JJCEk<{(5sv&lGP(U0BvIRSIV$b!Cymc-7>^5OCH;B4*7+mz~` zW1AXj++>0#{)|i-IS|-^C?OuRmvc>A1BQY=EnR^|$(OE@Kj6ic4j;mzEbZRawPwIH zo2d1y8y%O5>ICb)0}iLKqOxCKHTCOQC?oaa?_F z{jzDCIqz5(Y8y3Sbyd9a`>=GxWzCZhhmvwm{V4#UE^H?9_2t&-t-$wN+#~1#n(M`f z16@*5W$Kial;ec)a`~H($J_-4Kj7{rKTK2GY)uyr8jRc~k5mr0Pz=EGH)chJQ`Q@m z#JNT2+=2MAC$P8Tp-AZ{Lex z(iWz!o#3SFU8sOL5QwO6IY0U_Jep#$7kv5E$hhH~`xw$&LEUTVBmaJM78dpvHy5wz zM;n`+$Lt|Q7;dNM=b!s4$&J;?%nd$3Oi~YFS9u*2TE6G&w7Bx>ooxyo_!fD&!AR9Xc6 zybq;12%4^54}Ifu@RL}&P#KsQ8Asb}GJO5@i>dYD&}iT2=%M-=oce|!RmU_V9_LkE zUcQfKu>|V_3DV{6nEUPz;?9-9y62J9leHM?9B-`1lL2Q0mq;{7GE`JTf;PXseFsmP zpsP{;xmm@BIqAzhnZ^=sY%C_LoK~>eLS*qii;4F!$M2J+dnMI(0cw>(j^X}HH-Z~Q zxsBE%DPW-ZAt*N@^5U?3dwZW1=7Pw_#5694!Aua#-f-Mlbs_4`R|ua;svNF4yAeXr z)S@yF-kdwAx^_nd@BAGR326`xUY3bcQcDCOSSrz?&b-}w#=Wt;`O8N2TAW#6r7m)^ zN=R8%PS~=uF{HJX;_m)FVC$~V8H}VwFtxZC4m)#@r6=K{{Uy2iFyy8Nb@chovS8Ej z(c0QNq(ZjnU1sRyq^7rB3t^`tchjZA0GO*I+FJDMXY^1K3qDAp4p7eg8fg5bKk7^)*Aj{OfT1+#N4)X$XD#BAV*R%M3cX%U?F zV0WxPRxAT7k5kEYEUXn|l0F89nmK!p2-4Lelpf1YO@Bp)f`FWp2dnFR*}Ib|#eAtI zr(Ont>)R1I1`B9iC^jZKdYJtUm_$Qr{2%UVUip0G&(lTw>0d=a=7`P&`xqfj+GnMA zsspATt1z>?4P|2k_jrtdLNB}^{NX`FwGNxIv-n}6kB_~cg9GH%_V$g4h=U?bV}`M= zxVR?4=UXv|_n&qp2Gra&SLAvlrq^!)3t9$u;2s=&j33&zGtB~<0th~j#{y4xTN=-! z54k*pJA@5<1qB6A7FJgAzx<@%Uhemdjh~r=JZECbE3#b&(7D$4H6*{NKBdcgoro4lIu~L-cGpZJOu*^L9lWxQof?CHE$xT(KIbhwq(18 z7HIO5uCA`Z{h<-g&}2usf7k~L8yhEExA(Is$ts4kOQlEKh$dbKKUduXx$VyEj75$6 zUY_r6rW9!h(tr9<66_cQqQ!tg01Pw-2FccHWR;VkoXuGZP)E_MS+k+MKQ2-SXR})+2=vS#~1YHQDD&A%q&2+ z3|hP0@KC4Nn^#-w>|^rjo0^uEmiF?xLA||};;kh1E*y2{4g|_&92&UVvJ6iC=iYd~tzI-PLN-^@EHbwZ_mGz8F2)sGFz1qvDVnVL{`73E?6zM^gFH)0}EyprqcJsw8 zf)k}pO|@-5{NQB~6>a&rJDOev`aM2X^tI9?f?o3VQ^iu1lgiWB&XB|<4TNY&+~bA4tl3SxIZ5?|WMmx1XJxh4nET!Dq;_?6VGWtz?By;lIrKXPRkQcNm;ysea;oE!iI3fF@F~voGSsTH4Wa}$8M)D;xK&a_)z=%bm8W?( zh0%dN-|^!I0=V)ocXhcWEs&9r%rEn@ofKC!Y5x|Bm~S6OI?wqRq@YV^h91*RF=LV> z?%Ft-plXn$BqMVYYv@}+N8RkwR})&F1xnlUVm+Zc2Re z#*-L)!e#-%vYQS`%;x00UUo?Idyflvfhf;%@l(GfV_YJl5JhTloCPy+>O;s&^8QT9 z_q>Z#a~$!Hcsj1GZCejfaA@dJ)n3=HNGjW?@p{E`v8Es9h%x`)d*8FCOC@pIjW7Jxe-K-v{CWUj<6{1~*+()^Wa zG}E7v%KQZb)<@eQ(;Kod}CITI^SUcYoGmb0w2g{Wz}S6yw13mgs~g2(>H2J zd2W(9a=KcCG1xfxwdE13cVIwNoU`=xg`67d0xzY+OkI3bPYuyvPxjXV{?XD%aaao* z!US<&29kLP57S%cS`cqDoGSHiYINckcv@Oo-^K!s*#pg&RS%*2n`M^QU2=PJvQC4n ze~n&l^bqN$6}a)Ly}gy?raKtUR*8(eH9rE^Jfs_X8r%#%3%$0IYL-4_!-}Wo4;_5C z!Bj?vhaz+LN#iNhy*@1|x3dd}6L6g{P#CtLBWP;HOGd&?(OT=u{!v~>hvMbBikZjb zBt(-<*OzmI>+rhx;odH5t(BBe@(J=#s7Pz*{HryJ9~TH_VzwUa4rz0%fGJrp&F&8R zx^~<#54E}m|G8IRY1k(LmRcANcURo~o|EXO z+Y(tGCu+qyY^ivi!8ksyGw*~R zda#d`CHuWru&vfMA4_tcBA?#_1Zar42|OS6r>y&K)1$qpqQlI4csnHBcM z%`Fgb`uf^1sz|(2$dd~eJS>=763ADlkPmo}DD@7n;{gn6*^xiqRPHw{zV6ppFD^o@ z{NVr*mn>=`_TPlJD|I+SL&`9Gz!?`&5k+i$D|-6bc*Bk!bO#5Sfkgtu#*mZQ&i>Q8 zn468^$Vi=uAuc%X%}{dZ?u!9xIknHx+SQXt6vrnZ^Fp%H{oE~7@B;+}7%wstu6Cg=Q6@bLM8w>;;* z_EvFqtbF`45qr%AoLOo3uf8w=qcGAOh(d5nCE??O)#>R|XPDCUjLqIBu6iP;saZXv zOlh9i@B@L7+6U5&Nv_%C0d9%ns>^+Q__lb7Dhk+SdM7g)P1kH zoxq^q-G&)!lT+ObxnNt|@Nhx9(=*3Lt_Tgq<*sQ^Cb*rdSy*=YQu5?mpnv-lZ+rW# z*%=YnDABnn%IzMv2O1n9u^;%30iMu^3zoDbIK0n>d?f>a+C!4R? zAc%WVv)En$M`+xb=dvm?`}FVz0exfVtCd%OEb`=e4XV`2ch>N9;X3`3WEvEq&-*9> zPEUaE*Dh>Yz=$@f%ymj$e|_Gcy|Y;B{I zc9~vVFfRQCZR&_O!;A(4YO=Y1Ot)^CW{nMcG?R8q1GB)Uw+A&kkZ3!hF#Dagjp*@o zwS^ko@eF#*e%lE3Pv~^vABObBi=&~nN7E5Z4dtTpNjX%=R30R@M`NWT}C(-whE#+r9OYI zUl6eQTW2NTvSUZFQiL^u%G2^<#0E4z`K9dC*7D*`$@}esIfGza%Xyb9Go1A*eJ8`PJS1RWR3ms?UQF1HyQt(ejTscz5qM;~LuFE-3ME z=YI9TL`})=XS=J(Zs5Yt+5ACZb8CyE_jY^|T4#mW{_wt}lbX%3?5{R)XGtB!QmAq#2J9+<|H8 z+cx74dus(y1CUHz5d&-MVBMas+%rqO{wrInc{v^uNBS%4?$UFuzfllnOD`eO*yaq) zy!9Kn*tt7DALwe?y=fBnj|3gU6#LK5q|UG&G77qfk&PNS9GXo0rvo>7U{9Q(AD@0e ze&HBL)i*?JCNv|*%Xj=# z|L19*u-3Z=J|19!hl`(5<$q0N$S)~DbzE=?X0i8md`7h};{?mu8?cW{o>IVo468yM zS-|=_jZ4;PqtSw{?#AVts@@@|(KcBA{RK_A*Ooj6r3isrv&W$Mc^9(K z{nbn{w5dwG>=eDWWebD@99DB<7}fsJuXxP_J41$M|M?zir~w%3-}w7u)1y_n+Hm;n za)N#^#QY4Lxs5R#X#@`t>zhS{Zd#Rz-U|H*qg-oA1r5VoJt--O5fMJVq$kYaT4?@v zi!V+`zjgL-#AVeRzF|h|-xEtIRO2ID3WK24GCtljVzE@-Z|<4llv*y;@8lI>JNZuW9R{&eiqba(0t*kmh-mDy2;%CkU(AH znm}ctB8Vn3JHz?6Ra>_5nkOET5&%a>pYV0TwC(#H{?z0oWC3b`omA52ex!kbe*PSv zDT*{J4#C}+Yx&0Un^!E3& z5TacZA|gIAH7odmc+)Xny>3uVT)Nof93CTvf;aWe`-X~gL)-uS@#Tb?-mWcJLJ(+t zhwuh_dc2kY6GT=8KCK=~|I=WoCp-=g8?ZX8kNAC8aLMERL?WjsfB)fSZR3`gy$=!9pim`DE~IkHhWf`<;2nRIWr!(nw1FzltWQ@+Xp$mCxp( zC{A&VKoHe8z(-07mY%BG*CL_*%NwoNV2^W82F4| z`QqX_@pI+pPo;5Nz8x0@Gcmm*!;WF1axyap3z|PW?x;MuL4COouLZnsTHJCCLO(KL zxWkXSr^0G#An!CZ;y5`fT2vR73fx3)m^n!JzVgDD!vM_j-sQbFj-%*0XH?Z}ut6vJ z3@$l-xA{mXM*|>n86(Y4RHY(Fb*69_pYK&lmK*!ib(xgYOXZ{V4<=ZIEv3o3`jNi`p<3`J2k2sN=$yERsD$+0~7Pue5I?j!VDkLF*gB_izW;C zeShg40~65Z4C-uU?T(5zWn&O6V=(pl4TsxU`v{(1Oh`A=6nLwid^U*j!bt|yWjmy;e{BweH5EB)7#6;vq@ z4m^NQq7c&C`(ZSV2eHofouc0hH%zjU;Y6Bq>1k=VfQR%#$JUw?T_6EUg7mw#V*jridzy7>kFuxub6>9&+bCsODTKm}c z&PTr$1d`g^Nu~E$sy8EL3C5|fueZ29Y_f2+!iO<;HMML3(9AFO?#X<^@TjN|nS5Zx z&DRatX2`yG+-9U2mOua@X!=m{V=o-a#IOind_15Gs}cSj0xN9%_;!f?_E^$Wwn<#e zN%6$MWlPfK`C8uyDa|^H&Y^+j_pRCY*7MLYgN~zj^@2EFJ>>fa7iAb2z43Or#|;79 z+!&>0j<~qEp?#_+1B*3xz>f)c6+l zKW0Z4iYZ!-f>r=$;Y0z`AcJAf2G^%g#c?j<4^8V?q+A}xDLVg33 z_F^ubmWdOT-Cior`W&$c7L&5r(#eU_j_@Hka4}3EFxUt_XK%^$v0d#!AZxK6wPVFs zu)d)|v-3O$?IhHZ4g$pd5}={Y2iVaY<6b$%IROyJ0anVpy)F52_b68M=Mj%`dZrFW zDyS6eZALg1S-cMz3B>Mb5Zchx^HzpSA*@PMMVh!8hsJt_odBQ!`IYNa)i;Ec7K~ck%%r6%wqN zDh_e~rQw=(#g~$@xgJewFXFR!Y(PyVaogvOHyR^>Pt5rv`YRsHr1@voPT}8nSJ14R z5ri|DNd+L&*#29D8a7j~(>`zB9lFQ85}Mc{W^W zQB@YV(QSd`RdgJ57V)=i=W`R7CqKG5eDWv2z$cf`f3$VOVvrVfP&Q!nn1w=fa9Eaq@>2l%j3^Id z;ilMPkcV!WvwexxqnMPVafw(`Nk8O~OQsU)XFmyI2uyPgQTvsl{oajzLgJngK){yt zq3(~PhBsrXBV;9j`wh1{r&ny!MussFlsqJn^!X30!?l?oxuR!%rJ*Ope9t-g6Ah|fombo8ufma*%{+_8HYBdlcmLvkg!i+W5#ZO*z zsMWdm;69in+4WA)bjHlU3b6$kh1Wy?{#XxaHhjb!4*%>u+Fr|B)V*0FVukV-Rfs&?>@s5+4af5;gFColZo4oPOwkFi$TGD>bYhg zVe(Pn)-xyDn~KrK$D(i|dWGnL9&8S2DahFG*EfJZyuH15zHJW@iU_69L^4m&V_(X3>atsh0AUlOP`+J}H3YlfYLuHsJ;zDL{+gb47UlMIkCXT4fzcNW zxnLg4`Eo9y5I9ZPyI2NRuRppA&>rWhE7AmC9lWD_UQo$fiUoY08yZsm>$Xu9Jl`Ok z={a|%TO$GyQN*%Tgz~G;=6+r6id52nCnSTewGt=DsURpc=iTTYEHW~&Nq*ILMMv-5 za#5t@WrtHiE8jDeobG^`*VThMSS-f$iR+I_=1`Ub+q7%2n18S12 zuh%62H%1Qwlf!0|YU%FZ`WLxinT!JSKai2wtqA)JKJT{%Phvn5$O(r zp-Z}(dw%zRzt8=6&p&XUbM}7se)rmIE#`}-KwFz4NJKuHN=i!p@w)bGaG_WF=KPd< z-ob623QTh!!Ze41$i}6#%A^Y{-j|d#CxFf~g2sEj zXDsys)kDY$43;*myNBEGo&9s!cFGCU(A10<6e?=arPGNW(QQ$Vd9#3>-D-3JTj~bW z@q560A@af&B~#^pJc)B9Xd(-Tj~>v^yl3=^TOOag8MDEJw*5j}S!?CeSl zdh>BYqeX9rfqr%sj24K=F;S81$eYoo>kOWXZPjv%_da#{BSrnrdusO!H%f^Z1ia)K zVKA|^?G~E&%I0~!nEk#MrZFot_oADM*%Y2&)(xEKag)h8Wk(15n`jmHR$ zkhx%nL6co8GGH~(qQpPJSYtXj!Mw&B_>dr?Iws?Kwc4 zbaQRzYA<~@??*d=w<4aeRJv2{IFh#E_M!oh8K`i0_;vsAfzz=iS~-Sd#XP#WtofE$ z{VmEL;-#^^yE?;%*-;cx0{n!yxtoiN!ovXvYy~N zMo8Xfde|WWsbgwQ5TYp!C#l-PZ|^m6!|kbzkA&2pL>H&w%`|?L_Nf2^?kfn_?u?+h z^|9gEgR{fi0hfnf^IaQIYZrfDOO_EpX8Aj7bRVph(a;YZ83Xh4^TUFs3rm7MaSB-_ zAhs0#lZyr)lc!YK+GVc;2)RXE0R0XA657?(r8k9OgKe%;H|XI1q)Ug_1zj+}tb-U* z$ZT|*G@+=O9XnRm@gFQpOGATqzENo>dk>iMr34;!*o@!Mdq|O+2ztz9uhfr^*TK;o zeAz=X!uV+ZvL<#T^EY=cE>fJ$u8t}<@ig8yP3ay_wSU{lQl?jHa6H8=QAGmtrH#~A zQc{;*{Y-zl9ybNbL>rc=x`Tt{x{QnG#HJQIhE{&`aEybJL&}Yc1on^)1I|vL212C{ zJr5sek)tEo@4Phe@tDAYJ3!~jZw_7D!JHSf-PEAGltjw#_dpY>@%*M{BoJQDLAg(; z6luV}9oaOqLjnbSH_E_3 zAM0IPChA)|h0gDwZ3(g3HHjJ8W5!&i{6yYktS|sM<;Q=Klyo-2`BEx?2@4(&Zr1zq z`0*FXC)spOU{OP0K18seb<4r$+$lvw3baUXJU{l0iHb7h=AmlXKE@vlZ!caYKkLpx z3tpY$jjE5Q+_yiKwOpM^WLqv4JkH-)wL-&Olb@iSiX^!#M~Zgb#k0$5`DnA?m? z%aVIwU(!uk2Zo!?x?>x{ydZX;g|iko+TsW5I$ zMFBpR?i$*kpBU!(7}Ncfn4}Air9w0g>2_y>WmmmnC0kZ6&{iyOZ@=&H#o52Yi3SEl zzw@p|MZ*@)q@Qh6StVZS8}dr^tNCePka}P(F{h-Y`me5(AwIr%8Y%q~C6Mu%CS)tj*! zVUAaCccxv(RrB+o(W%?M`-u0DRbXWlkPJrB!rVxI?4#)vprJALUc3^VkVvbBDm|fN zCmAnF2Nzt}w>Z`Tw{`jq>X5dq>3EbNteHN(baSHZ?%l(BJz3xP+;q7FKt@*}AwjSj zo2;9?cH<#0-SGO`u~L;oY))J5(1gIuu04gvFH*&MC)%}>Q{B=Q^Y{wKQGtb#bre&p zs|hf_U`NRE-Xopqz*ME9EvLJC_#P-ux>7D4If_|IRE8N=xSeWuT4y+RT^@%^$OA|L zD{2rG8EdH=pNjpWC#N#e;8}P+7ooe0!?t@zq@YH?437=C*mY^^h(|#PZwZkBef#G2 z_S(yMbdIe4krokHe9t9y1NINr=C3LrXeP-k@7@nziMXMlzK3Lfp#?<(@P!Vp*E3Bs zp8E+LYCp|f@@$8As^}TLqPI~B0WOI+>^`LY*`yQ9Nn zKHlFCqYfvA2DRzERM&{|4ZOa>5r155Z2sMBETTn}mpOMzY@P9yGqf_D(&N{j*^P+0 zPg?$;%miqOhEd0Cf51|(nQqlqI0C-T0$y7zgcD9eH}3%t0xbd9hZJPIW#bWvi1wXc z0!hLD;Gdu_GYT8cFT9n3XHQBzb9Qi;kO1Y2syWP#8P6ef0ZJ(x%<=wj)d$^YGFUb; zl*zO1Q^9YV_vcFtKY9}UOMmwHNl!Gle7+qn@G9u#C=M!}v z`W$ijF~8-f2?6$hj=_GQelg!GlAt*Nfe;h>Cc-ISv)7-OOa%ng@FoHK&bhujI&3_N z1?anCCVZmroHuV1Z21uqEuY%;-0eG1FMff5zBt)cd+I!n$?TJh$ZKYg4Ld1ei`k+M z+D!bNylCa3!|l~Q5*u(hLN&MW>yqL*?FR;cM^;w0=}W^LorV~Mk~BMAgPA$=W&)eE z$8RvE&CQQ;yt?lm!Ebsok zF{|kkTqWZ)yT(JQ(Z9rU*~=uav$}{lH@_5nA%%@yS$oAKxdHO9UF3L>REPO{}UhdgYsk&CQ2Svo<>mk*plwi@KDVVp9X~iVyWc22{Oyc z|LCht#a~ZH|EZl(yp+IKbsUYB;P@G*|8^XyX18X!Geg>SGd&R3aS}oi^$LOvm{Jfm zGN`R$T3I!%)^wMIJz-;JKAG>8yDHo&(q4PX!A&5|%UbY2MX~MY=Rbd(6z%My`3+m_ zMyxiRYQGE1Oc$q*HaXsWHRDfnFDD>)G@1ABb&a6owtz26BfteogJM?A0F)_N4W+hz z&xPeW^dC5nGuy!nb^A&W#% zs;FR@-fbuv3SC=@vEX> z!{t|$seCu`C4k7g`uPo=^t@l;Lm;kxnUF^iz?hlWo{J=bZPjxCP_T8o*iI@$7uVGl zs7-(3V!V#sb*P~QL|GJKe<=kRkE^_JzRF~ZgZC~2P)vsZR#0~cv7D{@T^95O?Z|dh zNVuSxHK@h}QDa`Zw=%f=H+tdF89FE}=7CVD=LI&$^0TJ)R8S>TJP{@;Dn5#zzgUXn zZSK<|vt;qd*Ata1eYT3~35*&k1cd~!nCv^<&+NZteOq0P(ROgiQGf-{wO*zJg-OY@ zOTU6Sz$Cu9^d1g8fv?M5(tlM^*`&Ii1;-VSwn(%AF8+jDT#WECF(vaJ zTd&(V15iC__4#R0hrv@u2Lehlu_rS^!om}vHfnewhU-8?kC^A^Eg+xN`g^J6x2^57 z_k4V^+&uaj`OHD%q#PbEzb9<|l6)i{=fJ=uetRx;p@W9w z{<{FV6&H$#eu|$Hp+Io?d;Q`*$dA|eM@FBCtv2g;OzG7JhvsDolxN_Xvd$?nugoBkb7t>o%;h?D{N5SHs;uS*);Zm&3WjL%=* ztQ|Nx920qJRGXabj>ucpU7)qvez74q?{B+g(Mek6aDLByWsA8v@Nx; zVEIXL@ZT~D5qVqj{CxYx$vVGyz#dsu1a-C1iV0q%=U#9lg0XpKVBE|GQ*1b6vim}- zo7%GJq_PBkeNGa-u+E)aWW@OFP#W^6_|g}Bo%`6qfp~&T)xH^w^ns&Rj3L;toiO#B zx5=|>N!*QyB0GoqVq%-3_mAc53rhnLe!I4+ubfmmm1y#IL844`%Hm{kZ>5U89xkX- zN}_)^00GSO(bV_JU2hjiZwI_RaZO#9rw4f8a0LVXzv2>NVpZ~M9VIjR#>0bVQ7xsC z)Yh+stq5s}b`le>Q#yXKy_ovuU@)Ptr{ay2Ssx z;KWW@kbKMgdttuDv+5|8jkf%-;ciF6UM9}&!)0t`A2VO(Gsd9)b5+@GvkOm7PacfINj6giL>J z6XaJ|p9bTeT3@DtNMJ|26d48M1qUGbshX6)T0E08x@~R{gidsHdQhdjrd-|J-%)}e zxkw1@MMdR0WDoj@mS(^6w|)z)Tces4I3k%Xu!aJQd3j7{^D)J0P7`9kMX3QcR!{HJev6Q<-o&q@Sl^=$jFF7+1QX(hadwd=SQe&(S-*1 z>+BC#2Vze8``rc|T%{f7EUGWS-d~C&vq0geMRFG^lEN+&>gzpEIZy}vJRtu0l4E%aqruM6g77)on7jHB(ek@!#I%#jwvmrz3raX^nK8S5UP{*@*jN^u zAmM;J7+kNA_KJWBiE@L2hg`oh?X8 zNIo%hK@AAQZPd)-Kk+sQ=tFXM;;17Lk(M;0;8oPhbh0|JcKRqKFL!oy(i@LcEi597 z$hw8Wp3|QwGBp{fj6d6j$jjKP>u&@TbF_mx3dgyuW$8 zLm_l>+h=c4SSod0oQXs^iF57Hqh5#sQ#rxS>0}WFiRWJm37)Zr`i4LizagXVhMk>F z*lKn8Koujw1LZA4rw`5cvFEMk`~rKOk|h` zY+`NE;dEELS}BcP(8u} zE>)p;QgcU3Rs{BK$2AK9&(loIG%aKiTXbnTIJk^%Z@+A}mK3U~8ZO@7YyEA%EFjzQ z?zzGX7i!R&%hDC5T+t(4=&-oQR-#=KLIuSL@R7%AFPEw7#4&#PVw)l*6(#t$)-lDz zBysZc{GKfs;EED~ZsR9(x|AegNa$-UTcR&}tfIn6xk!irLa~c4wI^146v-UdqcHS2 zYk7G68)hJ1uQDhI3&IJSkd#WzPt>^0K~QcvXC6 z@O%lePW_Yrmv(0V7t1vU;Oxf#V#XE?iN59l_I#=6Df26K0PxXJ(N!*0v=06+iyNTZ literal 0 HcmV?d00001 diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..210c4fe --- /dev/null +++ b/docs/index.md @@ -0,0 +1,404 @@ +--- +layout: default +permalink: index +--- + + +{% include component-rotator-dark-begin.html %} +

+
+
+ +
+ +

+
LINQ To SQL
+
PLUS
+

+ +
+ +
+ *Free monthly trial available +
+ +
+
Download Count:
+
+ +
+
+ +
+ +
+ +
+ +
+

Save
10x to 50x
Faster

+
+ +
+
+ +
+
+
Zero configuration required
+
+{% highlight csharp %} +// Bulk Operations +context.BulkInsert(list); +context.BulkUpdate(list); +context.BulkDelete(list); +context.BulkMerge(list); + +// Batch Operations (Coming Soon) +context.Customers.Where(x => !x.IsActif) + .DeleteFromQuery(); +context.Customers.Where(x => !x.IsActif) + .UpdateFromQuery(x => + new Customer {IsActif = true}); +{% endhighlight %} +
+
+
+ +
+ +
+ +
+

Overcome
LinqToSql
Limitations

+
+ +
+
+ +
+
+
Over 100 customizations available
+
+{% highlight csharp %} +// Use custom key +context.BulkMerge(customers, options => { + options.ColumnPrimaryKeyExpression = + customer => customer.Code; +}); +{% endhighlight %} +
+
+
+
+ +
+ +
+
+
+{% include component-rotator-dark-end.html %} + + + + +
+{% include component-rotator-dark-begin.html %} +
+

Trusted by thousands around the world!

+ +
+
+

More than 2000 satisfied customers spreaded across over 75 countries

+ +
+ +
+

That's really cool! I didn't actually expect you to build a new release in just a day, to be honest, but this is really awesome

+
+ Kimwan Ogot, USA, Minneapolis + +
+
+ +
+

I would absolutely recommend your product. It is simple, cheap, effective.

+ +
+ + +
+
+
+{% include component-rotator-dark-end.html %} +
+ + +
+ +
+ + +
+ + +

Bulk Operations

+
+
+

Add flexibility to your toolbox to cover your scenarios with the best performance.

+
    +
  • Bulk Insert
  • +
  • Bulk Update
  • +
  • Bulk Delete
  • +
  • Bulk Merge
  • +
  • Bulk Synchronize
  • +
+ +
+
+
+
Bulk Operations Examples
+
+{% highlight csharp %} +// Include childs entities +context.BulkMerge(customers, + options => options.IncludeGraph = true); +}); + +// Use custom key +context.BulkMerge(customers, options => { + options.ColumnPrimaryKeyExpression = + customer => customer.Code; +}); +{% endhighlight %} +
+
+
+
+ +
+ + +

Batch Operations

+
+
+

Perform your operations from LINQ Query without loading entities in the context.

+
    +
  • DeleteFromQuery
  • +
  • UpdateFromQuery
  • +
+ +
+
+
+
Batch Operations Examples
+
+{% highlight csharp %} +// DELETE all inactive customers +context.Customers.Where(x => !x.IsActif) + .DeleteFromQuery(); + +// UPDATE all inactive customers +context.Customers.Where(x => !x.IsActif) + .UpdateFromQuery(x => new Customer {IsActif = true}); +{% endhighlight %} +
+
+
+
+ + +
+
+ +
+{% include component-rotator-dark-begin.html %} +
+

About ZZZ Projects

+
+ +

+ Our mission is to add value to the .NET Community by supporting some of the most popular free & open source libraries. +

+

+ Hundreds of thousands of people visit us every month, and we count over 10 million downloads. +

+
+
+
+
+

Summary

+
    +
  • Founded: 2014
  • +
  • Founder: Jonathan Magnan
  • +
  • Customers: 2000+
  • +
  • Countries: 75+
  • +
  • Closed Request: 3000+
  • +
  • Projects: 20+
  • +
+ +
+ +
+ + +
+{% include component-rotator-dark-end.html %} +
\ No newline at end of file diff --git a/docs/pages/api/api.md b/docs/pages/api/api.md new file mode 100644 index 0000000..a9ee45b --- /dev/null +++ b/docs/pages/api/api.md @@ -0,0 +1,69 @@ +--- +permalink: api +--- + +
+ +
+
+

Methods

+
+ +
+ +
+- Bulk Operations + - [Bulk SaveChanges](bulk-savechanges) + - [Bulk Insert](bulk-insert) + - [Bulk Update](bulk-update) + - [Bulk Delete](bulk-delete) + - [Bulk Merge](bulk-merge) + - [Bulk Synchronize](bulk-synchronize) + +- Batch Operations + - [Delete from Query](delete-from-query) + - [Update from Query](update-from-query) + + + +
+ +
+
+ + +
+
+

Options

+
+ +
+ +
+ +- [Audit](audit) +- [Batch](batch) +- [Column](column) +- [Execute Event](execute-event) +- [Identity](identity) +- [Key](key) +- [Logging](logging) +- [Temporary Table](temporary-table) +- [Transient Error](transient-error) +- [SQL Server](sql-server) + +
+ +
+
+
+ + \ No newline at end of file diff --git a/docs/pages/api/bulk-delete.md b/docs/pages/api/bulk-delete.md new file mode 100644 index 0000000..648b49d --- /dev/null +++ b/docs/pages/api/bulk-delete.md @@ -0,0 +1,90 @@ +--- +permalink: bulk-delete +--- + +## Definition +`DELETE` all entities from the database. + +All rows that match the entity key are `DELETED` from the database. + +{% include template-example.html %} +{% highlight csharp %} +// Easy to use +context.BulkDelete(list); + +// Easy to customize +context.BulkDelete(customers, options => options.ColumnPrimaryKeyExpression = customer => customer.Code); +{% endhighlight %} + +## Purpose +`Deleting` entities using a custom key from file importation is a typical scenario. + +Despite the `ChangeTracker` being outstanding to track what's modified, it lacks in term of scalability and flexibility. + +`SaveChanges` requires one database round-trip for every entity to `delete`. So if you need to `delete` 10000 entities, then 10000 database round-trips will be performed which is **INSANELY** slow. + +`BulkDelete` in counterpart offers great customization and requires the minimum database round-trips as possible. + +## Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| BulkDelete | 45 ms | 50 ms | 60 ms | + +{% include section-faq-begin.html %} +## FAQ + +### How can I specify more than one option? +You can specify more than one option using anonymous block. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkDelete(list, options => { + options.BatchSize = 100); + options.ColumnInputExpression = c => new {c.ID, c.Name, c.Description}); +}); +{% endhighlight %} + +### How can I specify the Batch Size? +You can specify a custom batch size using the `BatchSize` option. + +Read more: [BatchSize](/batch-size) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkDelete(list, options => options.BatchSize = 100); +{% endhighlight %} + +### How can I specify custom keys to use? +You can specify custom key using the `ColumnPrimaryKeyExpression` option. + +Read more: [ColumnPrimaryKeyExpression](/column-primary-key-expression) + +{% include template-example.html %} +{% highlight csharp %} +// Single Key +context.BulkDelete(customers, options => options.ColumnPrimaryKeyExpression = customer => customer.Code); + +// Surrogate Key +context.BulkDelete(customers, options => options.ColumnPrimaryKeyExpression = customer => new { customer.Code1, customer.Code2 }); +{% endhighlight %} + +### How can I include child entities (Entity Graph)? +You cannot. Due to the risk of mistakes, we preferred not to offer this option and make sure every entity you wish to `delete` is specified. + +### Why BulkDelete doesn't use the ChangeTracker? +To provide the best performance possible! + +Since using the `ChangeTracker` can greatly reduce performance, we chose to let `BulkSaveChanges` method handle scenarios with `ChangeTracker` and `BulkDelete`, scenarios without it. + +### Why BulkDelete is faster than BulkSaveChanges? +The major difference between both methods is `BulkSaveChanges` uses the `ChangeTracker` but not the `BulkDelete` method. + +By skipping the `ChangeTracker`, some methods like `DetectChanges` are no longer required which greatly helps to improve the performance. +{% include section-faq-end.html %} + +## Related Articles + +- [How to Benchmark?](benchmark) +- [How to use Custom Key?](custom-key) diff --git a/docs/pages/api/bulk-insert.md b/docs/pages/api/bulk-insert.md new file mode 100644 index 0000000..669f4d8 --- /dev/null +++ b/docs/pages/api/bulk-insert.md @@ -0,0 +1,93 @@ +--- +permalink: bulk-insert +--- + +## Definition +`INSERT` all entities in the database. + +All entities are considered as new rows and are `INSERTED` in the database. + +{% include template-example.html %} +{% highlight csharp %} +// Easy to use +context.BulkInsert(list); + +// Easy to customize +context.BulkInsert(list, options => options.BatchSize = 100); +{% endhighlight %} + +## Purpose +`Inserting` thousand of entities for an initial load or a file importation is a typical scenario. + +`SaveChanges` method makes it quite impossible to handle this kind of situation directly from Entity Framework due to the number of database round-trips required. + +`SaveChanges` requires one database round-trip for every entity to `insert`. So if you need to `insert` 10000 entities, then 10000 database round-trips will be performed which is **INSANELY** slow. + +`BulkInsert` in counterpart requires the minimum database round-trips as possible. By example under the hood for SQL Server, a simple`SqlBulkCopy` could be performed. + +## Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| BulkInsert | 6 ms | 10 ms | 15 ms | + +{% include section-faq-begin.html %} +## FAQ + +### How can I specify more than one option? +You can specify more than one option using anonymous block. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkInsert(list, options => { + options.BatchSize = 100); + options.ColumnInputExpression = c => new {c.Name, c.Description}); +}); +{% endhighlight %} + +### How can I specify the Batch Size? +You can specify a custom batch size using the `BatchSize` option. + +Read more: [BatchSize](/batch-size) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkInsert(list, options => options.BatchSize = 100); +{% endhighlight %} + +### How can I specify custom columns to Insert? +You can specify custom columns using the `ColumnInputExpression` option. + +Read more: [ColumnInputExpression](/column-input-expression) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkInsert(list, options => options.ColumnInputExpression = c => new {c.Name, c.Description}); +{% endhighlight %} + +### How can I include child entities (Entity Graph)? +You can include child entities using the `IncludeGraph` option. Make sure to read about the `IncludeGraph` since this option is not as trivial as others. + +Read more: [IncludeGraph](/include-graph) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkInsert(list, options => options.IncludeGraph = true); +{% endhighlight %} + +### Why BulkInsert doesn't use the ChangeTracker? +To provide the best performance possible! + +Since using the `ChangeTracker` can greatly reduce performance, we chose to let `BulkSaveChanges` method handle the scenarios with `ChangeTracker` and `BulkInsert` the scenarios without it. + +### Why BulkInsert is faster than BulkSaveChanges? +The major difference between both methods is `BulkSaveChanges` uses the `ChangeTracker` but not the `BulkInsert` method. + +By skipping the `ChangeTracker`, some methods like `Add`, `AddRange`, `DetectChanges` are no longer required which greatly helps to improve the performance. +{% include section-faq-end.html %} + +## Related Articles + +- [How to Benchmark?](benchmark) +- [How to use Custom Column?](custom-column) diff --git a/docs/pages/api/bulk-merge.md b/docs/pages/api/bulk-merge.md new file mode 100644 index 0000000..8634a4c --- /dev/null +++ b/docs/pages/api/bulk-merge.md @@ -0,0 +1,118 @@ +--- +permalink: bulk-merge +--- + +## Definition +`MERGE` all entities from the database. + +A merge is an `UPSERT` operation. All rows that match the entity key are considered as existing and are `UPDATED`, other rows are considered as new rows and are `INSERTED` in the database. + +{% include template-example.html %} +{% highlight csharp %} +// Easy to use +ctx.BulkMerge(list); + +// Easy to customize +context.BulkMerge(customers, options => options.ColumnPrimaryKeyExpression = customer => customer.Code); +{% endhighlight %} + +## Purpose +`Merging` entities using a custom key from file importation is a typical scenario. + +Despite the `ChangeTracker` being outstanding to track what's modified, it lacks in term of scalability and flexibility. + +`SaveChanges` requires one database round-trip for every entity to `insert` or `update`. So if you need to `insert` or `update` 10000 entities, then 10000 database round-trips will be performed which is **INSANELY** slow. + +`BulkMerge` in counterpart offers great customization and requires the minimum database round-trips as possible. + +## Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| BulkMerge | 65 ms | 80 ms | 110 ms | + +{% include section-faq-begin.html %} +## FAQ + +### How can I specify more than one option? +You can specify more than one option using anonymous block. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => { + options.BatchSize = 100); + options.ColumnInputExpression = c => new {c.ID, c.Name, c.Description}); +}); +{% endhighlight %} + +### How can I specify the Batch Size? +You can specify a custom batch size using the `BatchSize` option. + +Read more: [BatchSize](/batch-size) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => options.BatchSize = 100); +{% endhighlight %} + +### How can I specify custom columns to Merge? +You can specify custom columns using the `ColumnInputExpression` option. + +Read more: [ColumnInputExpression](/column-input-expression) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => options.ColumnInputExpression = c => new {c.Name, c.Description}); +{% endhighlight %} + +### How can I specify custom columns to exclude on insert or update? +You can specify custom columns to exclude using the `IgnoreOnMergeInsertExpression` and `IgnoreOnMergeUpdateExpression` option. + +Read more: [IgnoreOnMergeInsertExpression](/ignore-on-merge-insert-expression) + +Read more: [IgnoreOnMergeUpdateExpression](/ignore-on-merge-update-expression) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => + { + options.IgnoreOnMergeInsertExpression = customer => new { customer.UpdatedDate, customer.UpdatedUser }; + options.IgnoreOnMergeUpdateExpression = customer => customer.Code, customer.Col2; + }); +{% endhighlight %} + +### How can I specify custom keys to use? +You can specify custom keys using the `ColumnPrimaryKeyExpression` option. + +Read more: [ColumnPrimaryKeyExpression](/column-primary-key-expression) + +{% include template-example.html %} +{% highlight csharp %} +// Single Key +context.BulkMerge(customers, options => options.ColumnPrimaryKeyExpression = customer => customer.Code); + +// Surrogate Key +context.BulkMerge(customers, options => options.ColumnPrimaryKeyExpression = customer => new { customer.Code1, customer.Code2 }); +{% endhighlight %} + +### How can I include child entities (Entity Graph)? +You can include child entities using the `IncludeGraph` option. Make sure to read about the `IncludeGraph` since this option is not as trivial as others. + +Read more: [IncludeGraph](/include-graph) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => options.IncludeGraph = true); +{% endhighlight %} + +### Why BulkMerge doesn't use the ChangeTracker? +To provide the best performance possible! + +Since using the `ChangeTracker` can greatly reduce performance, we chose to let `BulkSaveChanges` method handle scenarios with `ChangeTracker` and `BulkMerge`, scenarios without it. +{% include section-faq-end.html %} + +## Related Articles +- [How to Benchmark?](benchmark) +- [How to use Custom Column?](custom-column) +- [How to use Custom Key?](custom-key) diff --git a/docs/pages/api/bulk-savechanges.md b/docs/pages/api/bulk-savechanges.md new file mode 100644 index 0000000..3d1ad7b --- /dev/null +++ b/docs/pages/api/bulk-savechanges.md @@ -0,0 +1,86 @@ +--- +permalink: bulk-savechanges +--- + +## Definition + +BulkSaveChanges method is the upgraded version of `SaveChanges`. + +All changes made in the context are persisted in the database but way faster by reducing the number of database round-trip required! + +BulkSaveChanges supports everything: + +- Association (One to One, One to Many, Many to Many, etc.) +- Complex Type +- Enum +- Inheritance (TPC, TPH, TPT) +- Navigation Property +- Self-Hierarchy +- Etc. + +{% include template-example.html title='BulkSaveChanges Examples' %} +{% highlight csharp %} +context.Customers.AddRange(listToAdd); // add +context.Customers.RemoveRange(listToRemove); // remove +listToModify.ForEach(x => x.DateModified = DateTime.Now); // modify + +// Easy to use +context.BulkSaveChanges(); + +// Easy to customize +context.BulkSaveChanges(bulk => bulk.BatchSize = 100); +{% endhighlight %} + +## Purpose +Using the `ChangeTracker` to detect and persist changes automatically is great! However, it leads very fast to some problems when multiple entities need to be saved. + +`SaveChanges` method makes a database round-trip for every change. So if you need to insert 10000 entities, then 10000 database round-trips will be performed which is INSANELY slow. + +`BulkSaveChanges` works exactly like `SaveChanges` but reduces the number of database round-trips required to greatly help improve the performance. + +## Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| BulkSaveChanges | 90 ms | 150 ms | 350 ms | + +{% include section-faq-begin.html %} +## FAQ + +### How can I specify more than one option? +You can specify more than one option using anonymous block. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => { + options.BatchSize = 100); + options.AllowConcurrency = false; +}); +{% endhighlight %} + +### How can I specify the Batch Size? +You can specify a custom batch size using the `BatchSize` option. + +Read more: [BatchSize](/batch-size) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => options.BatchSize = 100); +{% endhighlight %} + +### How can I turn off Concurrency Check? +You can turn off concurrency check using the `AllowConcurrency` option. + +Read more: [AllowConcurrency](/allow-concurrency) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => options.AllowConcurrency = false); +{% endhighlight %} +{% include section-faq-end.html %} + +## Related Articles + +- [How to Benchmark?](benchmark) +- [How to Improve Bulk SaveChanges Performances?](improve-bulk-savechanges) diff --git a/docs/pages/api/bulk-synchronize.md b/docs/pages/api/bulk-synchronize.md new file mode 100644 index 0000000..55f0848 --- /dev/null +++ b/docs/pages/api/bulk-synchronize.md @@ -0,0 +1,85 @@ +--- +permalink: bulk-synchronize +--- + +## Definition +`SYNCHRONIZE` all entities from the database. + +A synchronize is a mirror operation from the data source to the database. All rows that match the entity key are `UPDATED`, non-matching rows that exist from the source are `INSERTED`, non-matching rows that exist in the database are `DELETED`. + +The database table becomes a mirror of the entity list provided. + +{% include template-example.html %} +{% highlight csharp %} +// Easy to use +ctx.BulkSynchronize(list); + +// Easy to customize +context.BulkSynchronize(customers, options => options.ColumnPrimaryKeyExpression = customer => customer.Code); +{% endhighlight %} + +## Purpose +`Synchronizing` entities with the database is a very rare scenario, but it may happen when two databases need to be synchronized. + +`BulkSynchronize` give you the scalability and flexibility required when if you encounter this situation. + +## Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| BulkSynchronize | 55 ms | 65 ms | 85 ms | + +{% include section-faq-begin.html %} +## FAQ + +### How can I specify more than one option? +You can specify more than one option using anonymous block. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSynchronize(list, options => { + options.BatchSize = 100); + options.ColumnInputExpression = c => new {c.ID, c.Name, c.Description}); +}); +{% endhighlight %} + +### How can I specify the Batch Size? +You can specify a custom batch size using the `BatchSize` option. + +Read more: [BatchSize](/batch-size) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSynchronize(list, options => options.BatchSize = 100); +{% endhighlight %} + +### How can I specify custom columns to Synchronize? +You can specify custom columns using the `ColumnInputExpression` option. + +Read more: [ColumnInputExpression](/column-input-expression) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSynchronize(list, options => options.ColumnInputExpression = c => new {c.Name, c.Description}); +{% endhighlight %} + +### How can I specify custom keys to use? +You can specify custom keys using the `ColumnPrimaryKeyExpression` option. + +Read more: [ColumnPrimaryKeyExpression](/column-primary-key-expression) + +{% include template-example.html %} +{% highlight csharp %} +// Single Key +context.BulkSynchronize(customers, options => options.ColumnPrimaryKeyExpression = customer => customer.Code); + +// Surrogate Key +context.BulkSynchronize(customers, options => options.ColumnPrimaryKeyExpression = customer => new { customer.Code1, customer.Code2 }); +{% endhighlight %} +{% include section-faq-end.html %} + +## Related Articles +- [How to Benchmark?](benchmark) +- [How to use Custom Column?](custom-column) +- [How to use Custom Key?](custom-key) \ No newline at end of file diff --git a/docs/pages/api/bulk-update.md b/docs/pages/api/bulk-update.md new file mode 100644 index 0000000..3307ca6 --- /dev/null +++ b/docs/pages/api/bulk-update.md @@ -0,0 +1,108 @@ +--- +permalink: bulk-update +--- + +## Definition +`UPDATE` all entities in the database. + +All rows that match the entity key are considered as existing and are `UPDATED` in the database. + +{% include template-example.html %} +{% highlight csharp %} +// Easy to use +context.BulkUpdate(list); + +// Easy to customize +context.BulkUpdate(customers, options => options.ColumnPrimaryKeyExpression = customer => customer.Code); +{% endhighlight %} + +## Purpose +`Updating` entities using a custom key from file importation is a typical scenario. + +Despite the `ChangeTracker` being outstanding to track what's modified, it lacks in term of scalability and flexibility. + +`SaveChanges` requires one database round-trip for every entity to `update`. So if you need to `update` 10000 entities, then 10000 database round-trips will be performed which is **INSANELY** slow. + +`BulkUpdate` in counterpart offers great customization and requires the minimum database round-trips possible. + +## Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| BulkUpdate | 50 ms | 55 ms | 65 ms | + +{% include section-faq-begin.html %} +## FAQ + +### How can I specify more than one option? +You can specify more than one option using anonymous block. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkUpdate(list, options => { + options.BatchSize = 100); + options.ColumnInputExpression = c => new {c.ID, c.Name, c.Description}); +}); +{% endhighlight %} + +### How can I specify the Batch Size? +You can specify a custom batch size using the `BatchSize` option. + +Read more: [BatchSize](/batch-size) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkUpdate(list, options => options.BatchSize = 100); +{% endhighlight %} + +### How can I specify custom columns to Update? +You can specify custom columns using the `ColumnInputExpression` option. + +Read more: [ColumnInputExpression](/column-input-expression) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkUpdate(list, options => options.ColumnInputExpression = c => new {c.Name, c.Description}); +{% endhighlight %} + +### How can I specify custom keys to use? +You can specify custom key using the `ColumnPrimaryKeyExpression` option. + +Read more: [ColumnPrimaryKeyExpression](/column-primary-key-expression) + +{% include template-example.html %} +{% highlight csharp %} +// Single Key +context.BulkUpdate(customers, options => options.ColumnPrimaryKeyExpression = customer => customer.Code); + +// Surrogate Key +context.BulkUpdate(customers, options => options.ColumnPrimaryKeyExpression = customer => new { customer.Code1, customer.Code2 }); +{% endhighlight %} + +### How can I include child entities (Entity Graph)? +You can include child entities using the `IncludeGraph` option. Make sure to read about the `IncludeGraph` since this option is not as trivial as others. + +Read more: [IncludeGraph](/include-graph) + +{% include template-example.html %} +{% highlight csharp %} +context.BulkUpdate(list, options => options.IncludeGraph = true); +{% endhighlight %} + +### Why BulkUpdate doesn't use the ChangeTracker? +To provide the best performance possible! + +Since using the `ChangeTracker` can greatly reduce performance, we chose to let `BulkSaveChanges` method handle scenarios with `ChangeTracker` and `BulkUpdate`, scenarios without it. + +### Why BulkUpdate is faster than BulkSaveChanges? +The major difference between both methods is `BulkSaveChanges` uses the `ChangeTracker` but not the `BulkUpdate` method. + +By skipping the `ChangeTracker`, some methods like `DetectChanges` are no longer required which greatly helps to improve the performance. +{% include section-faq-end.html %} + +## Related Articles + +- [How to Benchmark?](benchmark) +- [How to use Custom Column?](custom-column) +- [How to use Custom Key?](custom-key) diff --git a/docs/pages/api/delete-from-query.md b/docs/pages/api/delete-from-query.md new file mode 100644 index 0000000..f8bec60 --- /dev/null +++ b/docs/pages/api/delete-from-query.md @@ -0,0 +1,39 @@ +--- +permalink: delete-from-query +--- + +## Definition +`DELETE` all rows from the database using a LINQ Query without loading entities in the context. + +A `DELETE` statement is built using the LINQ expression and directly executed in the database. + +{% include template-example.html %} +{% highlight csharp %} +// DELETE all customers that are inactive +context.Customers.Where(x => !x.IsActif).DeleteFromQuery(); + +// DELETE customers by id +context.Customers.Where(x => x.ID == userId).DeleteFromQuery(); +{% endhighlight %} + +## Purpose +`Deleting` entities using `SaveChanges` normally requires to load them first in the `ChangeTracker`. These additional round-trips are often not necessary. + +`DeleteFromQuery` gives you access to directly execute a `DELETE` statement in the database and provide a **HUGE** performance improvement. + +## Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| DeleteFromQuery | 1 ms | 1 ms | 1 ms | + +{% include section-faq-begin.html %} +## FAQ + +### Why DeleteFromQuery is faster than SaveChanges, BulkSaveChanges, and BulkDelete? + +`DeleteFromQuery` executes a statement directly in SQL such as `DELETE FROM [TableName] WHERE [Key]`. + +Other operations normally require one or multiple database round-trips which makes the performance slower. +{% include section-faq-end.html %} \ No newline at end of file diff --git a/docs/pages/api/options-summary/include-graph.md b/docs/pages/api/options-summary/include-graph.md new file mode 100644 index 0000000..b7c03d2 --- /dev/null +++ b/docs/pages/api/options-summary/include-graph.md @@ -0,0 +1,76 @@ +--- +permalink: include-graph +--- + +The IncludeGraph options allow to INSERT/UPDATE/MERGE entities by including the child entities graph. +By example, if you use BulkInsert using a list of Invoice with the options IncludeGraph, all invoices items will also be inserted. + +{% include template-example.html %} +{% highlight csharp %} +ctx.BulkInsert(invoices, options => options.IncludeGraph = true); +{% endhighlight %} + +## IncludeGraphOperationBuilder +The IncludeGraphOperationBuilder let you customize the bulk operations by entity type. + +Options are not copied when using IncludeGraph + +{% include template-example.html %} +{% highlight csharp %} +ctx.BulkMerge(users, options => +{ + options.IncludeGraph = true; + options.IncludeGraphOperationBuilder = operation => + { + if (operation is BulkOperation) + { + var bulk = (BulkOperation) operation; + bulk.ColumnPrimaryKeyExpression = x => x.Name; + } + else if (operation is BulkOperation) + { + var bulk = (BulkOperation) operation; + bulk.ColumnPrimaryKeyExpression = x => x.Name; + } + }; +}); +{% endhighlight %} + +### ReadOnly +You can specify that some entities should not be inserted/updated by marked them as ReadOnly. + +{% include template-example.html %} +{% highlight csharp %} +ctx.BulkMerge(users, options => +{ + options.IncludeGraph = true; + options.IncludeGraphOperationBuilder = operation => + { + if (operation is BulkOperation) + { + var bulk = (BulkOperation) operation; + bulk.IsReadOnly = true; + } + }; +}); +{% endhighlight %} + + +{% include section-faq-begin.html %} +## FAQ + +### Why I receive an error that asks me to specify a context factory? +To retrieve the current entities graph, our library requires a working context to use some Entity Framework feature without impacting the current context. +The context factory is optional if your context has a default constructor. + +Read more: [Context Factory](context-factory) + +### Why I received an error that asks me to use unsafe mode? +The unsafe mode is required when some proxy entities are found in the graph. +To retrieve all information, we need to detach temporary proxy type from the current context before re-attaching them. +There is currently no known issue about this technic, but we prefer to force people to understand that some unsafe code is currently done under the hood by our library. + +### Why is IncludeGraph not compatible with BulkDelete? +For security purpose, we prefer to force people to delete their entities. We currently have no plan to support it. + +{% include section-faq-end.html %} \ No newline at end of file diff --git a/docs/pages/api/options-summary/options-audit.md b/docs/pages/api/options-summary/options-audit.md new file mode 100644 index 0000000..ca569cb --- /dev/null +++ b/docs/pages/api/options-summary/options-audit.md @@ -0,0 +1,43 @@ +--- +permalink: audit +--- + +## UseAudit +Gets or sets if `INSERTED` and `DELETED` data from the database should be returned as `AuditEntries`. + +{% include template-example.html %} +{% highlight csharp %} +List auditEntries = new List(); + +context.BulkSaveChanges(options => +{ + options.UseAudit = true; + options.BulkOperationExecuted = bulkOperation => auditEntries.AddRange(bulkOperation.AuditEntries); +}); + +{% endhighlight %} + +--- + +## AuditEntries +Gets `INSERTED` and `DELETED` data when `UseAudit` option is enabled. + +{% include template-example.html %} +{% highlight csharp %} +List auditEntries = new List(); + +context.BulkSaveChanges(options => +{ + options.UseAudit = true; + options.BulkOperationExecuted = bulkOperation => auditEntries.AddRange(bulkOperation.AuditEntries); +}); + +foreach (var entry in auditEntries) +{ + foreach (var value in entry.Values) + { + var oldValue = value.OldValue; + var newValue = value.NewValue; + } +} +{% endhighlight %} \ No newline at end of file diff --git a/docs/pages/api/options-summary/options-batch.md b/docs/pages/api/options-summary/options-batch.md new file mode 100644 index 0000000..7b32c32 --- /dev/null +++ b/docs/pages/api/options-summary/options-batch.md @@ -0,0 +1,31 @@ +--- +permalink: batch +--- + +### BatchSize +Gets or sets the number of records to use in a batch. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => options.BatchSize = 1000); +{% endhighlight %} + +--- + +### BatchTimeout +Gets or sets the maximum of time in seconds to wait for a batch before the command throws a timeout exception. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => options.BatchTimeout = 180); +{% endhighlight %} + +--- + +### BatchDelayInterval +Gets or sets a delay in milliseconds to wait between batch. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkInsert(list, options => options.BatchDelayInterval = 100); +{% endhighlight %} \ No newline at end of file diff --git a/docs/pages/api/options-summary/options-column.md b/docs/pages/api/options-summary/options-column.md new file mode 100644 index 0000000..233386b --- /dev/null +++ b/docs/pages/api/options-summary/options-column.md @@ -0,0 +1,67 @@ +--- +permalink: column +--- + +## Column Input +Gets or sets columns to map with the direction `Input`. + +The key is required for operation such as `BulkUpdate` and `BulkMerge`. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => + options.ColumnInputExpression = entity => new {entity.ID, entity.Code} +); +{% endhighlight %} + +## Column Output +Gets or sets columns to map with the direction `Output`. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => + options.ColumnOutputExpression = entity => new {entity.ModifiedDate, entity.ModifiedUser} +); +{% endhighlight %} + +## Column InputOutput +Gets or sets columns to map with the direction `InputOutput`. + +The key is required for operation such as `BulkUpdate` and `BulkMerge`. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => + options.ColumnInputOutputExpression = entity => new {entity.ID, entity.Code} +); +{% endhighlight %} + +## Column Primary Key +Gets or sets columns to use as the `key` for the operation. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => + options.ColumnPrimaryKeyExpression = entity => new { entity.Code1, entity.Code2 } +); +{% endhighlight %} + +## Ignore On Merge Insert +Gets or sets columns to ignore when the `BulkMerge` method executes the `insert` statement. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => + options.IgnoreOnMergeUpdateExpression = entity => new {entity.ModifiedDate, entity.ModifiedUser} +); +{% endhighlight %} + +## Ignore On Merge Update +Gets or sets columns to ignore when the `BulkMerge` method executes the `update` statement. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => + options.IgnoreOnMergeUpdateExpression = entity => new {entity.CreatedDate, entity.CreatedUser} +); +{% endhighlight %} \ No newline at end of file diff --git a/docs/pages/api/options-summary/options-context-factory.md b/docs/pages/api/options-summary/options-context-factory.md new file mode 100644 index 0000000..3ab5807 --- /dev/null +++ b/docs/pages/api/options-summary/options-context-factory.md @@ -0,0 +1,65 @@ +--- +permalink: context-factory +--- + +The context factory is required to provide a working context to the EFE library. This context will be used by example to retrieve some information by attaching/detaching entities without impacting the current context. +If your context has a default constructor (no parameter), specifying a context factory may be optional unless your context requires some special configuration. + +### EF6/EF5/EF4 +Having a default context constructor or specifying a context factory is only required with the following options: +- IncludeGraph + +### EF Core +Having a default context constructor or specifying a context factory is always required. + +## Context Factory +The context factory is a function `Func` that provide the current DbContext as a parameter and require to return a new DbContext. +The current DbContext is passed in a parameter in case you need to create a working context that depends on the current context configuration or type. + +{% include template-example.html %} +{% highlight csharp %} +// Using the default constructor +EntityFrameworkManager.ContextFactory = context => new CurrentContext(); + +// Using a constructor that requires a connection string +EntityFrameworkManager.ContextFactory = context => new CurrentContext(My.ConnectionString); + +// Using a constructor that requires optionsBuilder (EF Core) +EntityFrameworkManager.ContextFactory = context => +{ + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.UseSqlServer(My.ConnectionString); + return new EntityContext(optionsBuilder.Options); +}; + +// Using a constructor that depends on the current context +EntityFrameworkManager.ContextFactory = context => +{ + if (context is EntityContext) + { + return new EntityContext(); + } + else + { + return new ElseContext(); + } +}; +{% endhighlight %} + +## Default Constructor +If your context has a default constructor, you might now need to specify a context factory. + +{% include template-example.html %} +{% highlight csharp %} +public class EntitiesContext : DbContext +{ + public EntitiesContext() : base("CodeFirstEntities") + { + // I'm a default constructor! + } + + // ...code... +} +{% endhighlight %} + + diff --git a/docs/pages/api/options-summary/options-execute-event.md b/docs/pages/api/options-summary/options-execute-event.md new file mode 100644 index 0000000..37d22a6 --- /dev/null +++ b/docs/pages/api/options-summary/options-execute-event.md @@ -0,0 +1,25 @@ +--- +permalink: execute-event +--- + +## BulkOperationExecuting +Gets or sets an action to execute `before` the bulk operation is executed. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => { + options.BulkOperationExecuting = bulkOperation => { /* configuration */ }; +}); +{% endhighlight %} + +--- + +## BulkOperationExecuted +Gets or sets an action to execute `after` the bulk operation is executed. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => { + options.BulkOperationExecuted = bulkOperation => { /* configuration */ }; +}); +{% endhighlight %} diff --git a/docs/pages/api/options-summary/options-identity.md b/docs/pages/api/options-summary/options-identity.md new file mode 100644 index 0000000..9458564 --- /dev/null +++ b/docs/pages/api/options-summary/options-identity.md @@ -0,0 +1,31 @@ +--- +permalink: identity +--- + +### InsertKeepIdentity +Gets or sets if the source identity value should be preserved on `Insert`. When not specified, identity values are assigned by the destination. + +{% include template-example.html %} +{% highlight csharp %} +context.Insert(options => options.InsertKeepIdentity = true); +{% endhighlight %} + +--- + +### MergeKeepIdentity +Gets or sets if the source identity value should be preserved on `Merge`. When not specified, identity values are assigned by the destination. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(options => options.MergeKeepIdentity = true); +{% endhighlight %} + +--- + +### SynchronizeKeepIdentity +Gets or sets if the source identity value should be preserved on `Synchronize`. When not specified, identity values are assigned by the destination. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSynchronize(options => options.SynchronizeKeepIdentity = true); +{% endhighlight %} \ No newline at end of file diff --git a/docs/pages/api/options-summary/options-key.md b/docs/pages/api/options-summary/options-key.md new file mode 100644 index 0000000..4371526 --- /dev/null +++ b/docs/pages/api/options-summary/options-key.md @@ -0,0 +1,21 @@ +--- +permalink: key +--- + +## AllowDuplicateKeys +Gets or sets if a duplicate key is possible in the source. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => options.AllowDuplicateKeys = true); +{% endhighlight %} + +--- + +## AllowUpdatePrimaryKeys +Gets or sets if the key must also be included in columns to `UPDATE`. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => options.AllowUpdatePrimaryKeys = true); +{% endhighlight %} diff --git a/docs/pages/api/options-summary/options-logging.md b/docs/pages/api/options-summary/options-logging.md new file mode 100644 index 0000000..d749065 --- /dev/null +++ b/docs/pages/api/options-summary/options-logging.md @@ -0,0 +1,48 @@ +--- +permalink: logging +--- + +## Log +Gets or sets an action to `log` all database events as soon as they happen. + +{% include template-example.html %} +{% highlight csharp %} +StringBuilder logger = new StringBuilder(); + +context.BulkSaveChanges(options => +{ + options.Log += s => logger.AppendLine(s); +}); +{% endhighlight %} + +--- + +## UseLogDump +Gets or sets if all `log` related to database event should be stored in a `LogDump` properties. + +{% include template-example.html %} +{% highlight csharp %} +StringBuilder logDump; + +context.BulkSaveChanges(options => +{ + options.UseLogDump = true; + options.BulkOperationExecuted = bulkOperation => logDump = bulkOperation.LogDump; +}); +{% endhighlight %} + +--- + +## LogDump +Gets all `logged` database event when `UseLogDump` is enabled. + +{% include template-example.html %} +{% highlight csharp %} +StringBuilder logDump; + +context.BulkSaveChanges(options => +{ + options.UseLogDump = true; + options.BulkOperationExecuted = bulkOperation => logDump = bulkOperation.LogDump; +}); +{% endhighlight %} diff --git a/docs/pages/api/options-summary/options-sql-server.md b/docs/pages/api/options-summary/options-sql-server.md new file mode 100644 index 0000000..784c2ff --- /dev/null +++ b/docs/pages/api/options-summary/options-sql-server.md @@ -0,0 +1,14 @@ +--- +permalink: sql-server +--- + +## SqlBulkCopyOptions +Gets or sets the SqlBulkCopyOptions to use when `SqlBulkCopy` is used to directly insert in the destination table. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.SqlBulkCopyOptions = SqlBulkCopyOptions.Default | SqlBulkCopyOptions.TableLock; +}); +{% endhighlight %} diff --git a/docs/pages/api/options-summary/options-temporary-table.md b/docs/pages/api/options-summary/options-temporary-table.md new file mode 100644 index 0000000..600ee08 --- /dev/null +++ b/docs/pages/api/options-summary/options-temporary-table.md @@ -0,0 +1,80 @@ +--- +permalink: temporary-table +--- + +## TemporaryTableBatchByTable +Gets or sets the number of batches a temporary table can contain. This option may create multiple temporary tables when the number of batches to execute exceeds the specified limit. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.TemporaryTableBatchByTable = 0; // unlimited +}); +{% endhighlight %} + +--- + +## TemporaryTableInsertBatchSize +Gets or sets the number of records to use in a batch when inserting in a temporary table. This number is recommended to be high. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.TemporaryTableInsertBatchSize = 50000; +}); +{% endhighlight %} + +--- + +## TemporaryTableMinRecord +Gets or sets the minimum number of records to use a temporary table instead of using SQL derived table. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.TemporaryTableMinRecord = 25; +}); +{% endhighlight %} + +--- + +## TemporaryTableSchemaName +Gets or sets the schema name to use for the temporary table. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.TemporaryTableSchemaName = "zzz"; +}); +{% endhighlight %} + +--- + +## TemporaryTableUseTableLock +Gets or sets if the temporary table must be locked when inserting records into it. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.TemporaryTableUseTableLock = true; +}); +{% endhighlight %} + + +--- + +## UsePermanentTable +Gets or sets if the library should `create` and `drop` a permanent table instead of using a temporary table. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.UsePermanentTable = true; +}); +{% endhighlight %} diff --git a/docs/pages/api/options-summary/options-transient-error.md b/docs/pages/api/options-summary/options-transient-error.md new file mode 100644 index 0000000..c78ff56 --- /dev/null +++ b/docs/pages/api/options-summary/options-transient-error.md @@ -0,0 +1,27 @@ +--- +permalink: transient-error +--- + +## RetryCount +Gets or sets the maximum number of operations retry when a transient error occurs. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => { + options.RetryCount = 3; +}); +{% endhighlight %} + +--- + +## RetryInterval +Gets or sets the interval to wait before retrying an operation when a transient error occurs. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => { + options.RetryCount = 3; + options.RetryInterval = new TimeSpan(100); +}); + +{% endhighlight %} diff --git a/docs/pages/api/options-summary/transaction.md b/docs/pages/api/options-summary/transaction.md new file mode 100644 index 0000000..f8a642f --- /dev/null +++ b/docs/pages/api/options-summary/transaction.md @@ -0,0 +1,43 @@ +--- +permalink: transaction +--- + +## BulkSaveChanges +As SaveChanges, BulkSaveChanges already save all entities within an internal transaction. So by default, there is nothing to do. + +However, if you start a transaction within Entity Framework, BulkSaveChanges will honor it and will use this transaction instead of creating an internal transaction. + +{% include template-example.html %} +{% highlight csharp %} +var transaction = context.Database.BeginTransaction(); +try +{ + context.BulkSaveChanges(); + transaction.Commit(); +} +catch +{ + transaction.Rollback(); +} +{% endhighlight %} +--- + +## Bulk Operations +Bulk Operations such as BulkInsert, BulkUpdate, BulkDelete doesn't use a transaction by default. This is your responsibility to handle it. + +If you start a transaction within Entity Framework, Bulk Operations will honor it. + +{% include template-example.html %} +{% highlight csharp %} +var transaction = context.Database.BeginTransaction(); +try +{ + context.BulkInsert(list1); + context.BulkInsert(list2); + transaction.Commit(); +} +catch +{ + transaction.Rollback(); +} +{% endhighlight %} diff --git a/docs/pages/api/options/allow-concurrency.md b/docs/pages/api/options/allow-concurrency.md new file mode 100644 index 0000000..9bec56a --- /dev/null +++ b/docs/pages/api/options/allow-concurrency.md @@ -0,0 +1,5 @@ +--- +permalink: allow-concurrency +--- + +{% include under-construction.html %} \ No newline at end of file diff --git a/docs/pages/api/options/allow-duplicate-keys.md b/docs/pages/api/options/allow-duplicate-keys.md new file mode 100644 index 0000000..3617e33 --- /dev/null +++ b/docs/pages/api/options/allow-duplicate-keys.md @@ -0,0 +1,19 @@ +--- +permalink: allow-duplicate-keys +--- + +## Definition +Gets or sets if a duplicate key is possible in the source. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => options.AllowDuplicateKeys = true); +{% endhighlight %} + +## Purpose +In a rare scenario such as importing a file, a key may be used in multiple rows. + +In some provider such as SQL Server, the statement created by our library (`Merge`) makes it impossible to use with some duplicate keys. + +By enabling this option, only the latest key is used instead. + diff --git a/docs/pages/api/options/allow-update-primary-keys.md b/docs/pages/api/options/allow-update-primary-keys.md new file mode 100644 index 0000000..dd4728f --- /dev/null +++ b/docs/pages/api/options/allow-update-primary-keys.md @@ -0,0 +1,14 @@ +--- +permalink: allow-update-primary-keys +--- + +## Definition +Gets or sets if the key must also be included in columns to `UPDATE`. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => options.AllowUpdatePrimaryKeys = true); +{% endhighlight %} + +## Purpose +This option is rarely used. One scenario example is a custom key with a trigger that requires columns part of the key to also be `UPDATED`. \ No newline at end of file diff --git a/docs/pages/api/options/audit-entries.md b/docs/pages/api/options/audit-entries.md new file mode 100644 index 0000000..723a2a8 --- /dev/null +++ b/docs/pages/api/options/audit-entries.md @@ -0,0 +1,34 @@ +--- +permalink: audit-entries +--- + +## Definition +Get `INSERTED` and `DELETED` data when `UseAudit` option is enabled. + +{% include template-example.html %} +{% highlight csharp %} +List auditEntries = new List(); + +context.BulkSaveChanges(options => +{ + options.UseAudit = true; + options.BulkOperationExecuted = bulkOperation => auditEntries.AddRange(bulkOperation.AuditEntries); +}); + +foreach (var entry in auditEntries) +{ + foreach (var value in entry.Values) + { + var oldValue = value.OldValue; + var newValue = value.NewValue; + } +} +{% endhighlight %} + +## Purpose +Logging old value and new value is often useful to keep a history of changes in the database or file. + +## FAQ + +### Why enabling this option decreases the performance? +Enabling this option will require additional data to be returned from the database. \ No newline at end of file diff --git a/docs/pages/api/options/batch-delay-interval.md b/docs/pages/api/options/batch-delay-interval.md new file mode 100644 index 0000000..7faf201 --- /dev/null +++ b/docs/pages/api/options/batch-delay-interval.md @@ -0,0 +1,27 @@ +--- +permalink: batch-delay-interval +--- + +## Definition +Gets or sets a delay in milliseconds to wait between batch. + +**DO NOT** use this options with transaction. + +{% include template-example.html %} +{% highlight csharp %} +// Instance +context.BulkInsert(list, options => options.BatchDelayInterval = 100); + +// Global +EntityFrameworkManager.BulkOperationBuilder = builder => builder.BatchDelayInterval = 100; +{% endhighlight %} + +## Purpose +Having access to add a delay interval between batches may help to give responsivity to other applications by giving them a chance to insert data during the delay time. + +## FAQ + +### Why should I not use this option with transaction? +You should not because if may often lead to lock and deadlock. + +A transaction must be as short as possible and completed as soon as possible. diff --git a/docs/pages/api/options/batch-size.md b/docs/pages/api/options/batch-size.md new file mode 100644 index 0000000..123b939 --- /dev/null +++ b/docs/pages/api/options/batch-size.md @@ -0,0 +1,38 @@ +--- +permalink: batch-size +--- + +## Definition +Gets or sets the number of records to use in a batch. + +{% include template-example.html %} +{% highlight csharp %} +// Instance +context.BulkSaveChanges(options => options.BatchSize = 1000); + +// Global +EntityFrameworkManager.BulkOperationBuilder = builder => builder.BatchSize = 1000; +{% endhighlight %} + +## Purpose +Having access to modify the `BatchSize` default value may be useful in some occasions where the performance is very affected. + +Don't try to optimize it if your application is not affected by performance problem. + +## FAQ + +### What's the optimized BatchSize? +Not too low, not too high! + +Unfortunately, there is no magic value. + +If you set it too low, the library will perform too many round-trips and it may decreases the overall performance. + +If you set it too high, the library will make fewer round-trips but it could take more time to write on the server which may decrease the overall performance. + +There is no perfect number since there is too many factors such as: +- Column Size +- Index +- Latency +- Trigger +- Etc. \ No newline at end of file diff --git a/docs/pages/api/options/batch-timeout.md b/docs/pages/api/options/batch-timeout.md new file mode 100644 index 0000000..51803c8 --- /dev/null +++ b/docs/pages/api/options/batch-timeout.md @@ -0,0 +1,23 @@ +--- +permalink: batch-timeout +--- + +## Definition +Gets or sets the maximum of time in seconds to wait for a batch before the command throws a timeout exception. + +{% include template-example.html %} +{% highlight csharp %} +// Instance +context.BulkSaveChanges(options => options.BatchTimeout = 180); + +// Global +EntityFrameworkManager.BulkOperationBuilder = builder => builder.BatchTimeout = 180; +{% endhighlight %} + +## Purpose +Having access to change the `BatchTimeout` gives you the flexibility required when some operations are too slow to complete due to several reasons such as: +- Batch Size +- Column Size +- Latency +- Trigger +- Etc. \ No newline at end of file diff --git a/docs/pages/api/options/bulk-operation-executed.md b/docs/pages/api/options/bulk-operation-executed.md new file mode 100644 index 0000000..1ad30cb --- /dev/null +++ b/docs/pages/api/options/bulk-operation-executed.md @@ -0,0 +1,27 @@ +--- +permalink: bulk-operation-executed +--- + +## Definition +Gets or sets an action to execute `after` the bulk operation is executed. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => { + options.BulkOperationExecuted = bulkOperation => { /* configuration */ }; +}); +{% endhighlight %} + +## Purpose +For some options such as `Audit`, values must be taken directly from the `Bulk Operations` after it's executed. This `event` allows you to take this kind of information. + +{% include template-example.html %} +{% highlight csharp %} +List auditEntries = new List(); + +context.BulkSaveChanges(list, options => +{ + options.UseAudit = true; + options.BulkOperationExecuted = bulkOperation => auditEntries.AddRange(bulkOperation.AuditEntries); +}); +{% endhighlight %} \ No newline at end of file diff --git a/docs/pages/api/options/bulk-operation-executing.md b/docs/pages/api/options/bulk-operation-executing.md new file mode 100644 index 0000000..048f60e --- /dev/null +++ b/docs/pages/api/options/bulk-operation-executing.md @@ -0,0 +1,16 @@ +--- +permalink: bulk-operation-executing +--- + +## Definition +Gets or sets an action to execute `before` the bulk operation is executed. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => { + options.BulkOperationExecuting = bulkOperation => { /* configuration */ }; +}); +{% endhighlight %} + +## Purpose +This event allows you to check or change some options that have been automatically added when none is specified such as Batch Size, Column Mapping, Timeout, etc. diff --git a/docs/pages/api/options/column-input-expression.md b/docs/pages/api/options/column-input-expression.md new file mode 100644 index 0000000..1732cdc --- /dev/null +++ b/docs/pages/api/options/column-input-expression.md @@ -0,0 +1,20 @@ +--- +permalink: column-input-expression +--- + +## Definition +Gets or sets columns to map with the direction `Input`. + +The key is required for operations such as `BulkUpdate` and `BulkMerge`. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => + options.ColumnInputExpression = entity => new {entity.ID, entity.Code} +); +{% endhighlight %} + +## Purpose +The `ColumnInputExpression` option lets you choose specific properties in which you want to perform the bulk operations. + +By example, when importing a file, you may not have data on all properties. \ No newline at end of file diff --git a/docs/pages/api/options/column-input-output-expression.md b/docs/pages/api/options/column-input-output-expression.md new file mode 100644 index 0000000..f12cfd3 --- /dev/null +++ b/docs/pages/api/options/column-input-output-expression.md @@ -0,0 +1,20 @@ +--- +permalink: column-input-output-expression +--- + +## Definition +Gets or sets columns to map with the direction `InputOutput`. + +The key is required for operations such as `BulkUpdate` and `BulkMerge`. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => + options.ColumnInputOutputExpression = entity => new {entity.ID, entity.Code} +); +{% endhighlight %} + +## Purpose +The `ColumnInputOutputExpression` option lets you choose specific properties in which you want to perform the bulk operations. + +By example, when importing a file, you may have not data on all properties. \ No newline at end of file diff --git a/docs/pages/api/options/column-output-expression.md b/docs/pages/api/options/column-output-expression.md new file mode 100644 index 0000000..ff19289 --- /dev/null +++ b/docs/pages/api/options/column-output-expression.md @@ -0,0 +1,16 @@ +--- +permalink: column-output-expression +--- + +## Definition +Gets or sets columns to map with the direction `Output`. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => + options.ColumnOutputExpression = entity => new {entity.ModifiedDate, entity.ModifiedUser} +); +{% endhighlight %} + +## Purpose +The `ColumnOutputExpression` option lets you choose specific properties in which you want to retrieve data from the database. \ No newline at end of file diff --git a/docs/pages/api/options/column-primary-key-expression.md b/docs/pages/api/options/column-primary-key-expression.md new file mode 100644 index 0000000..02c4297 --- /dev/null +++ b/docs/pages/api/options/column-primary-key-expression.md @@ -0,0 +1,18 @@ +--- +permalink: column-primary-key-expression +--- + +## Definition +Gets or sets columns to use as the `key` for the operation. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => + options.ColumnPrimaryKeyExpression = entity => new { entity.Code1, entity.Code2 } +); +{% endhighlight %} + +## Purpose +The `ColumnPrimaryKeyExpression` option lets you choose a specific key to use to perform the bulk operations. + +By example, when importing a file, you may not have access to the `ID` but a unique `Code` instead. \ No newline at end of file diff --git a/docs/pages/api/options/ingore-on-merge-insert-expression.md b/docs/pages/api/options/ingore-on-merge-insert-expression.md new file mode 100644 index 0000000..6f0e792 --- /dev/null +++ b/docs/pages/api/options/ingore-on-merge-insert-expression.md @@ -0,0 +1,25 @@ +--- +permalink: ignore-on-merge-insert-expression +--- + +## Definition +Gets or sets columns to ignore when the `BulkMerge` method executes the `insert` statement. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => + options.IgnoreOnMergeUpdateExpression = entity => new {entity.ModifiedDate, entity.ModifiedUser} +); +{% endhighlight %} + +## Purpose +The `IgnoreOnMergeInsertExpression` option lets you ignore some columns that should only be `updated. + +By example, when to `update` the ModifiedData and ModifiedUser but not `insert` value. + +## Limitations +Database Provider Supported: +- SQL Server +- SQL Azure + +_Ask our support team if you need this option for another provider_ \ No newline at end of file diff --git a/docs/pages/api/options/ingore-on-merge-update-expression.md b/docs/pages/api/options/ingore-on-merge-update-expression.md new file mode 100644 index 0000000..0d31fe1 --- /dev/null +++ b/docs/pages/api/options/ingore-on-merge-update-expression.md @@ -0,0 +1,25 @@ +--- +permalink: ignore-on-merge-update-expression +--- + +## Definition +Gets or sets columns to ignore when the `BulkMerge` method executes the `update` statement. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(list, options => + options.IgnoreOnMergeUpdateExpression = entity => new {entity.CreatedDate, entity.CreatedDate} +); +{% endhighlight %} + +## Purpose +The `IgnoreOnMergeUpdateExpression` option lets you ignore some columns that should be only `insert. + +By example, when you need to `insert` the CreatedDate and CreatedDate but not `update` the value. + +## Limitations +Database Provider Supported: +- SQL Server +- SQL Azure + +_Ask our support team if you need this option for another provider_ \ No newline at end of file diff --git a/docs/pages/api/options/insert-keep-identity.md b/docs/pages/api/options/insert-keep-identity.md new file mode 100644 index 0000000..67c9d8f --- /dev/null +++ b/docs/pages/api/options/insert-keep-identity.md @@ -0,0 +1,16 @@ +--- +permalink: insert-keep-identity +--- + +## Definition +Gets or sets if the source identity value should be preserved on `Insert`. When not specified, identity values are assigned by the destination. + +{% include template-example.html %} +{% highlight csharp %} +context.Insert(options => options.InsertKeepIdentity = true); +{% endhighlight %} + +## Purpose +The `InsertKeepIdentity` option let you keep the source identity value when `inserting`. + +By example, when importing a file, you may want to keep the value specified. \ No newline at end of file diff --git a/docs/pages/api/options/log-dump.md b/docs/pages/api/options/log-dump.md new file mode 100644 index 0000000..436e4da --- /dev/null +++ b/docs/pages/api/options/log-dump.md @@ -0,0 +1,21 @@ +--- +permalink: log-dump +--- + +## Definition +Gets all `logged` database event when `UseLogDump` is enabled. + +{% include template-example.html %} +{% highlight csharp %} +StringBuilder logDump; + +context.BulkSaveChanges(options => +{ + options.UseLogDump = true; + options.BulkOperationExecuted = bulkOperation => logDump = bulkOperation.LogDump; +}); +{% endhighlight %} + + +## Purpose +Getting database `log` can often be useful for debugging and see what has been executed under the hood by the library. \ No newline at end of file diff --git a/docs/pages/api/options/log.md b/docs/pages/api/options/log.md new file mode 100644 index 0000000..c59d527 --- /dev/null +++ b/docs/pages/api/options/log.md @@ -0,0 +1,19 @@ +--- +permalink: log +--- + +## Definition +Gets or sets an action to `log` all database events as soon as they happen. + +{% include template-example.html %} +{% highlight csharp %} +StringBuilder logger = new StringBuilder(); + +context.BulkSaveChanges(options => +{ + options.Log += s => logger.AppendLine(s); +}); +{% endhighlight %} + +## Purpose +Getting database `log` can often be useful for debugging and see what has been executed under the hood by the library. \ No newline at end of file diff --git a/docs/pages/api/options/merge-keep-identity.md b/docs/pages/api/options/merge-keep-identity.md new file mode 100644 index 0000000..a42f62e --- /dev/null +++ b/docs/pages/api/options/merge-keep-identity.md @@ -0,0 +1,16 @@ +--- +permalink: merge-keep-identity +--- + +## Definition +Gets or sets if the source identity value should be preserved on `Merge`. When not specified, identity values are assigned by the destination. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkMerge(options => options.MergeKeepIdentity = true); +{% endhighlight %} + +## Purpose +The `MergeKeepIdentity` option lets you keep the source identity value when `merging`. + +By example, when importing a file, you may want to keep the specified value. \ No newline at end of file diff --git a/docs/pages/api/options/retry-count.md b/docs/pages/api/options/retry-count.md new file mode 100644 index 0000000..c39ca7f --- /dev/null +++ b/docs/pages/api/options/retry-count.md @@ -0,0 +1,29 @@ +--- +permalink: retry-count +--- + +## Definition +Gets or sets the maximum number of operations retry when a transient error occurs. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => { + options.RetryCount = 3; +}); +{% endhighlight %} + +## Purpose +A transient error is a temporary error that is likely to disappear soon. That rarely happens but they might occur! + +These options allow to reduce a bulk operations fail by making them retry when a transient error occurs. + +## FAQ + +### What are transient error codes supported? +You can find a list of transient errors here: [Transient fault error codes](https://docs.microsoft.com/en-us/azure/sql-database/sql-database-develop-error-messages#transient-fault-error-codes) + +Which includes the most common errors such as: +- Cannot open database +- The service is currently busy +- Database is not currently available +- Not enough resources to process request \ No newline at end of file diff --git a/docs/pages/api/options/retry-interval.md b/docs/pages/api/options/retry-interval.md new file mode 100644 index 0000000..4c0f78f --- /dev/null +++ b/docs/pages/api/options/retry-interval.md @@ -0,0 +1,31 @@ +--- +permalink: retry-interval +--- + +## Definition +Gets or sets the interval to wait before retrying an operation when a transient error occurs. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => { + options.RetryCount = 3; + options.RetryInterval = new TimeSpan(100); +}); + +{% endhighlight %} + +## Purpose +A transient error is a temporary error that is likely to disappear soon. That rarely happens but they might occur! + +These options allow to reduce a bulk operations fail by making them retry when a transient error occurs. + +## FAQ + +### What are transient error codes supported? +You can find a list of transient errors here: [Transient fault error codes](https://docs.microsoft.com/en-us/azure/sql-database/sql-database-develop-error-messages#transient-fault-error-codes) + +Which includes the most common error such as: +- Cannot open database +- The service is currently busy +- Database is not currently available +- Not enough resources to process request \ No newline at end of file diff --git a/docs/pages/api/options/sql-bulk-copy-options.md b/docs/pages/api/options/sql-bulk-copy-options.md new file mode 100644 index 0000000..d1902d6 --- /dev/null +++ b/docs/pages/api/options/sql-bulk-copy-options.md @@ -0,0 +1,17 @@ +--- +permalink: sql-bulk-copy-options +--- + +## Definition +Gets or sets the SqlBulkCopyOptions to use when `SqlBulkCopy` is used to directly insert in the destination table. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.SqlBulkCopyOptions = SqlBulkCopyOptions.Default | SqlBulkCopyOptions.TableLock; +}); +{% endhighlight %} + +## Purpose +Modifying the SqlBulkCopyOptions to include by example `TableLock` may increase significantly the performance. \ No newline at end of file diff --git a/docs/pages/api/options/synchronize-keep-identity.md b/docs/pages/api/options/synchronize-keep-identity.md new file mode 100644 index 0000000..4f9a39a --- /dev/null +++ b/docs/pages/api/options/synchronize-keep-identity.md @@ -0,0 +1,16 @@ +--- +permalink: synchronize-keep-identity +--- + +## Definition +Gets or sets if the source identity value should be preserved on `Synchronize`. When not specified, identity values are assigned by the destination. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSynchronize(options => options.SynchronizeKeepIdentity = true); +{% endhighlight %} + +## Purpose +The `SynchronizeKeepIdentity` option let you keep the source identity value when `synchronizing`. + +By example, when importing a file, you may want to keep the value specified. \ No newline at end of file diff --git a/docs/pages/api/options/temporary-table-batch-by-table.md b/docs/pages/api/options/temporary-table-batch-by-table.md new file mode 100644 index 0000000..42d9ddc --- /dev/null +++ b/docs/pages/api/options/temporary-table-batch-by-table.md @@ -0,0 +1,17 @@ +--- +permalink: temporary-table-batch-by-table +--- + +## Definition +Gets or sets the number of batches a temporary table can contain. This option may create multiple temporary tables when the number of batches to execute exceeds the limit specified. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.TemporaryTableBatchByTable = 0; // unlimited +}); +{% endhighlight %} + +## Purpose +So far, we have not found any scenario that could require it. But we still support this option! \ No newline at end of file diff --git a/docs/pages/api/options/temporary-table-insert-batch-size.md b/docs/pages/api/options/temporary-table-insert-batch-size.md new file mode 100644 index 0000000..ad54cff --- /dev/null +++ b/docs/pages/api/options/temporary-table-insert-batch-size.md @@ -0,0 +1,17 @@ +--- +permalink: temporary-table-insert-batch-size +--- + +## Definition +Gets or sets the number of records to use in a batch when inserting in a temporary table. This number is recommended to be high. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.TemporaryTableInsertBatchSize = 50000; +}); +{% endhighlight %} + +## Purpose +Increasing the default value may improve the performance. Since the temporary table doesn't contain index and trigger and it's normally locked during the insert, you may use a very high value. \ No newline at end of file diff --git a/docs/pages/api/options/temporary-table-min-record.md b/docs/pages/api/options/temporary-table-min-record.md new file mode 100644 index 0000000..df14925 --- /dev/null +++ b/docs/pages/api/options/temporary-table-min-record.md @@ -0,0 +1,17 @@ +--- +permalink: temporary-table-min-record +--- + +## Definition +Gets or sets the minimum number of records to use a temporary table instead of using SQL derived table. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.TemporaryTableMinRecord = 25; +}); +{% endhighlight %} + +## Purpose +Our library is smart but finding the `META` number is very hard since there is a lot of factors. Increasing the default value may improve the performance. \ No newline at end of file diff --git a/docs/pages/api/options/temporary-table-schema-name.md b/docs/pages/api/options/temporary-table-schema-name.md new file mode 100644 index 0000000..c64b413 --- /dev/null +++ b/docs/pages/api/options/temporary-table-schema-name.md @@ -0,0 +1,17 @@ +--- +permalink: temporary-table-schema-name +--- + +## Definition +Gets or sets the schema name to use for the temporary table. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.TemporaryTableSchemaName = "zzz"; +}); +{% endhighlight %} + +## Purpose +In very rare occasions, you may need to specify a schema name. By example, when also using `UsePermanentTable` option. \ No newline at end of file diff --git a/docs/pages/api/options/temporary-table-use-table-lock.md b/docs/pages/api/options/temporary-table-use-table-lock.md new file mode 100644 index 0000000..c4a586f --- /dev/null +++ b/docs/pages/api/options/temporary-table-use-table-lock.md @@ -0,0 +1,17 @@ +--- +permalink: temporary-table-use-table-lock +--- + +## Definition +Gets or sets if the temporary table must be locked when inserting records into it. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.TemporaryTableUseTableLock = true; +}); +{% endhighlight %} + +## Purpose +Using table lock increases the overall performance when inserting into a temporary table. This option should not be disabled. \ No newline at end of file diff --git a/docs/pages/api/options/use-audit.md b/docs/pages/api/options/use-audit.md new file mode 100644 index 0000000..d9492c2 --- /dev/null +++ b/docs/pages/api/options/use-audit.md @@ -0,0 +1,25 @@ +--- +permalink: use-audit +--- + +## Definition +Gets or sets if `INSERTED` and `DELETED` data from the database should be returned as `AuditEntries`. + +{% include template-example.html %} +{% highlight csharp %} +List auditEntries = new List(); + +context.BulkSaveChanges(options => +{ + options.UseAudit = true; + options.BulkOperationExecuted = bulkOperation => auditEntries.AddRange(bulkOperation.AuditEntries); +}); +{% endhighlight %} + +## Purpose +Logging old values and new values is often useful to keep history of changes in the database or file. + +## FAQ + +### Why enabling this option decreases the performance? +Enabling this option will require additional data to be returned from the database. \ No newline at end of file diff --git a/docs/pages/api/options/use-log-dump.md b/docs/pages/api/options/use-log-dump.md new file mode 100644 index 0000000..2e3ab9f --- /dev/null +++ b/docs/pages/api/options/use-log-dump.md @@ -0,0 +1,20 @@ +--- +permalink: use-log-dump +--- + +## Definition +Gets or sets if all `log` related to database event should be stored in a `LogDump` property. + +{% include template-example.html %} +{% highlight csharp %} +StringBuilder logDump; + +context.BulkSaveChanges(options => +{ + options.UseLogDump = true; + options.BulkOperationExecuted = bulkOperation => logDump = bulkOperation.LogDump; +}); +{% endhighlight %} + +## Purpose +Getting database `log` can often be useful for debugging and see what has been executed under the hood by the library. \ No newline at end of file diff --git a/docs/pages/api/options/use-permanent-table.md b/docs/pages/api/options/use-permanent-table.md new file mode 100644 index 0000000..4b51369 --- /dev/null +++ b/docs/pages/api/options/use-permanent-table.md @@ -0,0 +1,17 @@ +--- +permalink: use-permanent-table +--- + +## Definition +Gets or sets if the library should `create` and `drop` a permanent table instead of using a temporary table. + +{% include template-example.html %} +{% highlight csharp %} +context.BulkSaveChanges(options => +{ + options.UsePermanentTable = true; +}); +{% endhighlight %} + +## Purpose +This option can be useful when for some rare reasons, you don't have access to the `tempdb` database. \ No newline at end of file diff --git a/docs/pages/api/update-from-query.md b/docs/pages/api/update-from-query.md new file mode 100644 index 0000000..81aed23 --- /dev/null +++ b/docs/pages/api/update-from-query.md @@ -0,0 +1,41 @@ +--- +permalink: update-from-query +--- + +## Definition +`UPDATE` all rows from the database using a LINQ Query without loading entities in the context. + +An `UPDATE` statement is built using the LINQ expression and directly executed in the database. + +{% include template-example.html %} +{% highlight csharp %} +// UPDATE all customers that are inactive for more than two years +context.Customers + .Where(x => x.Actif && x.LastLogin < DateTime.Now.AddYears(-2)) + .UpdateFromQuery(x => new Customer {Actif = false}); + +// UPDATE customers by id +context.Customers.Where(x => x.ID == userId).UpdateFromQuery(x => new Customer {Actif = false}); +{% endhighlight %} + +## Purpose +`Updating` entities using `SaveChanges` normally requires to load them first in the `ChangeTracker`. These additional round-trips are often not necessary. + +`UpdateFromQuery` gives you access to directly execute an `UPDATE` statement in the database and provide a **HUGE** performance improvement. + +## Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| UpdateFromQuery | 1 ms | 1 ms | 1 ms | + +{% include section-faq-begin.html %} +## FAQ + +### Why UpdateFromQuery is faster than SaveChanges, BulkSaveChanges, and BulkUpdate? + +`UpdateFromQuery` executes a statement directly in SQL such as `UPDATE [TableName] SET [SetColumnsAndValues] WHERE [Key]`. + +Other operations normally require one or multiple database round-trips which makes the performance slower. +{% include section-faq-end.html %} \ No newline at end of file diff --git a/docs/pages/articles/articles.md b/docs/pages/articles/articles.md new file mode 100644 index 0000000..61e9033 --- /dev/null +++ b/docs/pages/articles/articles.md @@ -0,0 +1,12 @@ +--- +permalink: articles +--- + +You got some articles idea you will want we write? + +Contact us: info@zzzprojects.com + +Tell us about your daily problem or your performance issue. + +We will be happy to help you and share the solution to make developer code better and faster! + diff --git a/docs/pages/articles/benchmark.md b/docs/pages/articles/benchmark.md new file mode 100644 index 0000000..91e4f0d --- /dev/null +++ b/docs/pages/articles/benchmark.md @@ -0,0 +1,132 @@ +--- +permalink: benchmark +--- + +## Problem +You perform benchmark tests for a method like BulkSaveChanges, but you get very bad performance results. + +### Solution +The performance issue may be caused by some common mistakes: + +- Forget to JIT compile the library +- Include method not related to the test + + + +## Forget to JIT compile the library +In C#, the code is compiled into IL by the compiler. Then when needed, the IL is compiled just-in-time (JIT) into the native assembly language of the host machine. + +Additionally, some libraries like Entity Framework require some extra work like creating/reading the model. Some people report the first load taking several seconds! + +Entity Framework Extensions also takes some time to be compiled. It can take around 100ms the first time you use a method! So if you include it this time, your benchmark time is currently way higher than it should. + +### Solution +Invoke the method once before performing the benchmark tests + +## Include method not related to the test +Someone once reported a performance issue and thought our BulkSaveChanges method was slow. We discovered he was including the time to Add every entity to the context. + +The Add method was taking 99,9% of the total time while BulkSaveChanges only 0,1%. + + +| Operations | 100 Entities | 1,000 Entities | 10,000 Entities | +| :--------- | -----------: | -------------: | --------------: | +| Add | 15 ms | 1,050 ms | 105,000 ms | +| BulKSaveChanges | 40 ms | 90ms | 400 ms | + + +The Add method doesn't affect much the performance when adding 100 entities, but if you make your test with 10,000 entities: + - Add: 99.6% + - BulkSaveChanges: 0,4% + +### Solution +Include only the method you want to benchmark. + +## Good Example +Here is an example of how we normally do all our benchmarks tests + +### Example +{% include template-example.html %} +{% highlight csharp %} +public Benchmark() +{ + // BENCHMARK using Stopwatch + var clock1 = new Stopwatch(); + var clock2 = new Stopwatch(); + + var nbRecord = 1000; + var nbTry = 5; + + var list = GenerateData(nbRecord); + + // BENCHMARK: JIT compile library first + Test1(list, null); + Test2(list, null); + + for (var i = 0; i < nbTry; i++) + { + Test1(list, clock1); + Test2(list, clock2); + } + + var r1 = clock1.ElapsedMilliseconds/nbTry; + var r2 = clock2.ElapsedMilliseconds/nbTry; +} + +public void Test1(List lines, Stopwatch clock) +{ + using (var ctx = new CustomerContext()) + { + var customers = new List(); + + foreach (var line in lines) + { + var customer = new Customer(); + // ...code... + customers.Add(customer); + } + + ctx.Customers.AddRange(customers); + + // BENCHMARK: Only method we want to test + clock.Start(); + ctx.BulkSaveChanges(); + clock.Stop(); + } +} + +public void Test2(List lines, Stopwatch clock) +{ + using (var ctx = new CustomerContext()) + { + var customers = new List(); + + foreach (var line in lines) + { + var customer = new Customer(); + // ...code... + customers.Add(customer); + } + + ctx.Customers.AddRange(customers); + + // BENCHMARK: Only method we want to test + clock.Start(); + ctx.SaveChanges(); + clock.Stop(); + } +} + +public List GenerateData(int nbRecord) +{ + var list = new List(); + + for (var i = 0; i < nbRecord; i++) + { + list.Add(i.ToString()); + } + + return list; +} +{% endhighlight %} + diff --git a/docs/pages/articles/bulk-insert-vs-bulk-savechanges.md b/docs/pages/articles/bulk-insert-vs-bulk-savechanges.md new file mode 100644 index 0000000..33ecdf7 --- /dev/null +++ b/docs/pages/articles/bulk-insert-vs-bulk-savechanges.md @@ -0,0 +1,39 @@ +--- +permalink: bulk-insert-vs-bulk-savechanges +--- + +## What’s the difference between BulkInsert and BulkSaveChanges? +BulkInsert will always be a lot faster than BulkSaveChanges. + +BulkSaveChanges work like SaveChanges but faster. It uses the Change Tracker to get the list of entities and check the Entity State to know which operation should be performed. + +In counterpart, Bulk methods such as BulkInsert, BulkUpdate, and BulkDelete doesn’t use at all the Change Tracker to make these methods as efficient as possible. It takes the list of entities from the parameter provided and doesn’t care about the Entity State. + +## Should I always use BulkInsert? +No! Even if BulkInsert is faster. + +BulkSaveChanges even if slower make everything easier. All you need to do is adding “Bulk” before “SaveChanges” and everything work as expected. + +BulkInsert require more time to implement when you have several different lists to insert. You need to create/handle a transaction in your code and specify yourself the right order to save. + +## We normally recommend always to use BulkSaveChanges unless you have some critical section you want to boost even more the performance. +How is transaction handled? + +BulkSaveChanges as SaveChanges create an internal transaction. So, by default, there is nothing to do. + +BulkInsert doesn’t create a transaction by default. If you want to save multiple lists, you will need to handle the transaction in your code. + +{% include template-example.html %} +{% highlight csharp %} +var transaction = context.Database.BeginTransaction(); +try +{ + context.BulkInsert(list1); + context.BulkInsert(list2); + transaction.Commit(); +} +catch +{ + transaction.Rollback(); +} +{% endhighlight %} diff --git a/docs/pages/articles/concurrency.md b/docs/pages/articles/concurrency.md new file mode 100644 index 0000000..7909192 --- /dev/null +++ b/docs/pages/articles/concurrency.md @@ -0,0 +1,208 @@ +--- +permalink: concurrency +--- + +## Problem +Your model have concurrency entity and you must resolve optimistic concurrency using a pattern. + +Concurrency exceptions normally happen on: +- BulkSaveChanges +- BulkUpdate + +## Solution - BulkSaveChanges +When a concurrency error happens, only the first entry in error is returned (exactly like SaveChanges). + +There are three possible scenarios: +- Database Wins (You keep database values) +- Client Wins (You keep current entity values) +- Custom Resolution (You merge properties from database and client entity) + +### Database Wins +You keep database values. + +{% include template-example.html %} +{% highlight csharp %} +public void BulkSaveChanges_DatabaseWins(DbContext ctx) +{ + bool saveFailed; + + do + { + saveFailed = false; + + try + { + ctx.BulkSaveChanges(); + } + catch (DbUpdateConcurrencyException ex) + { + saveFailed = true; + + // Update the values of the entity that failed to save from the store + ex.Entries.Single().Reload(); + } + + } while (saveFailed); +} +{% endhighlight %} + +### Client Wins +You keep current entity values. + +{% include template-example.html %} +{% highlight csharp %} +public void BulkSaveChanges_ClientWins(DbContext ctx) +{ + bool saveFailed; + + do + { + saveFailed = false; + + try + { + ctx.BulkSaveChanges(); + } + catch (DbUpdateConcurrencyException ex) + { + saveFailed = true; + + // Update original values from the database + var entry = ex.Entries.Single(); + entry.OriginalValues.SetValues(entry.GetDatabaseValues()); + } + + } while (saveFailed); +} +{% endhighlight %} + +### Custom Resolution +You merge properties from database and client entity. + +{% include template-example.html %} +{% highlight csharp %} +public void BulkSaveChanges_CustomResolution(CurrentContext ctx) + { +public void BulkSaveChanges_CustomResolution(CurrentContext ctx) +{ + + bool saveFailed; + + do + { + saveFailed = false; + + try + { + ctx.BulkSaveChanges(); + } + catch (DbUpdateConcurrencyException ex) + { + saveFailed = true; + + // Get the current entity values and the values in the database + // as instances of the entity type + var entry = ex.Entries.Single(); + var databaseValues = entry.GetDatabaseValues(); + + if (entry.Entity is EntitySimple_Concurrency) + { + var clientEntity = (EntitySimple_Concurrency) entry.Entity; + var databaseEntity = (EntitySimple_Concurrency) databaseValues.ToObject(); + + // Choose an initial set of resolved values. In this case we + // make the default be the values currently in the database. + var resolvedEntity = (EntitySimple_Concurrency) databaseValues.ToObject(); + + // Have the user choose what the resolved values should be + resolvedEntity.IntColumn = clientEntity.IntColumn + 100; + // ... merge all columns... + + // Update the original values with the database values and + // the current values with whatever the user chooses. + entry.OriginalValues.SetValues(databaseValues); + entry.CurrentValues.SetValues(resolvedEntity); + } + } + + } while (saveFailed); +} +{% endhighlight %} + +## Solution - BulkUpdate +When a concurrency error happens, BulkUpdate returns a **DbBulkOperationConcurrencyException** which contains all entries in error. + +There are three possible scenarios: +- Database Wins (You keep database values) +- Client Wins (You keep current entity values) +- Custom Resolution (You merge properties from database and client entity) + +### Database Wins +You keep database values. + +{% include template-example.html %} +{% highlight csharp %} +public void BulkUpdate_DatabaseWins(CurrentContext ctx, List list) where T : class +{ + try + { + ctx.BulkUpdate(list); + } + catch (DbBulkOperationConcurrencyException ex) + { + // DO nothing (or log), keep database values! + } +} +{% endhighlight %} + +### Client Wins +You keep current entity values. + +{% include template-example.html %} +{% highlight csharp %} +public void BulkUpdate_StoreWins(CurrentContext ctx, List list) where T : class +{ + try + { + ctx.BulkUpdate(list); + } + catch (DbBulkOperationConcurrencyException ex) + { + // FORCE update store entities + ctx.BulkUpdate(list, operation => operation.AllowConcurrency = false); + } +} +{% endhighlight %} + +### Custom Resolution +You merge properties from database and client entity. + +{% include template-example.html %} +{% highlight csharp %} +public void BulkUpdate_CustomResolution(CurrentContext ctx, List list) where T : class +{ + try + { + ctx.BulkUpdate(list); + } + catch (DbBulkOperationConcurrencyException ex) + { + foreach (var entry in ex.Entries) + { + ObjectStateEntry objectEntry; + + if (entry is EntitySimple_Concurrency) + { + var clientEntry = (EntitySimple_Concurrency) entry; + var databaseEntry = ctx.EntitySimple_Concurrencys.Single(x => x.ID == clientEntry.ID); + + // merge properties like you want + clientEntry.IntColumn = databaseEntry.IntColumn; + } + } + + // FORCE update store entities + ctx.BulkUpdate(list, operation => operation.AllowConcurrency = false); + } +} +{% endhighlight %} diff --git a/docs/pages/articles/custom-column.md b/docs/pages/articles/custom-column.md new file mode 100644 index 0000000..3bdbbdf --- /dev/null +++ b/docs/pages/articles/custom-column.md @@ -0,0 +1,42 @@ +--- +permalink: custom-column +--- + +## Problem +You want to perform a Bulk Operations (BulkInsert, BulkUpdate, BulkDelete, or BulkMerge) but only on some specific columns. + +By example, you want to perform a BulkUpdate on a customer list but only UPDATE the name and email property. + +## Solution +You can specify the column on which the operation should be performed with the **ColumnInputExpression** options + +### Example + +{% include template-example.html %} +{% highlight csharp %} +// DON'T add the key if auto-generated +ctx.BulkInsert(customers, operation => operation.ColumnInputExpression = + customer => new {customer.Name, customer.Email}); + +// ALWAYS add the key +ctx.BulkUpdate(customers, operation => operation.ColumnInputExpression = + customer => new { customer.ID, customer.Name, customer.Email }); + +// ALWAYS add the key +ctx.BulkMerge(customers, operation => operation.ColumnInputExpression = + customer => new {customer.ID, customer.Name, customer.Email}); +{% endhighlight %} + +## Troubleshooting + +### INSERT + Destination mapped more than once error +You receive the following error: +> One of your columns has a destination mapped more than once. See the inner exception for details. + +Make sure the key has not been added to the ColumnInputExpression. + +### UPDATE or MERGE + No primary found +You receive the following error: +> An error occurred, no primary could be found or resolved. + +Make sure the key has been added to the ColumnInputExpression. diff --git a/docs/pages/articles/custom-key.md b/docs/pages/articles/custom-key.md new file mode 100644 index 0000000..cb8a209 --- /dev/null +++ b/docs/pages/articles/custom-key.md @@ -0,0 +1,53 @@ +--- +permalink: custom-key +--- + +## Problem +You want to perform a Bulk Operations (BulkUpdate, BulkDelete, or BulkMerge) but using a different key than the one specifyied. + +By example, you want to perform a BulkUpdate on a customer list but using the customer "Code" instead of the "CustomerID" for the key. + +## Solution +You can specify the column to use for the key with the **ColumnPrimaryKeyExpression** options. + +### Example + +{% include template-example.html %} +{% highlight csharp %} +// Single Key +ctx.BulkUpdate(customers, operation => operation.ColumnPrimaryKeyExpression = + customer => customer.Code); + +// Surrogate Key (with anonymous type) +ctx.BulkUpdate(customers, operation => operation.ColumnPrimaryKeyExpression = + customer => new { customer.Code1, customer.Code2, customer.Code3 }); +{% endhighlight %} + +## Troubleshooting + +### Duplicate Key +You receive the following error: +> An error occurred because the primary key specified is not unique, you can set the property 'AllowDuplicateKeys' to true to allow duplicate keys + +This error happens because the key is used in more than one row in the source + +#### Example + +| Code | Name | +| :--- | :---- | +| 001 | Jon | +| 002 | Henri | +| 001 | Jonathan | + +The code "001" is here more than once with a different name. + +You can allow duplicate key with the **AllowDuplicateKeys** options + +{% include template-example.html %} +{% highlight csharp %} +ctx.BulkUpdate(customers, operation => +{ + operation.AllowDuplicateKeys = true; + operation.ColumnPrimaryKeyExpression = customer => customer.Code; +}); +{% endhighlight %} diff --git a/docs/pages/articles/emdx.md b/docs/pages/articles/emdx.md new file mode 100644 index 0000000..683b11e --- /dev/null +++ b/docs/pages/articles/emdx.md @@ -0,0 +1,35 @@ +--- +permalink: edmx +--- + +In a rare occasion, your model might not still compatible yet with our model reader. If that's your case and we ask you for your model, you can use one of the following methods to provide the required information: + +## Code First +Use the `GetModelXDocument` method to generate the Edmx to send. + +{% include template-example.html %} +{% highlight csharp %} +public string GetModelXDocument(DbContext context) +{ + XDocument doc; + using (var memoryStream = new MemoryStream()) + { + using (XmlWriter xmlWriter = XmlWriter.Create(memoryStream, new XmlWriterSettings { Indent = true })) + { + EdmxWriter.WriteEdmx(context, xmlWriter); + } + + memoryStream.Position = 0; + + doc = XDocument.Load(memoryStream); + } + return doc.ToString(); +} + +DbContext context = new EntityContext(); +string edmx = GetModelXDocument(); +{% endhighlight %} + + +## Database First +Provide us the [fileName].edmx directly. diff --git a/docs/pages/articles/fastest-way-to-insert.md b/docs/pages/articles/fastest-way-to-insert.md new file mode 100644 index 0000000..fcf85ed --- /dev/null +++ b/docs/pages/articles/fastest-way-to-insert.md @@ -0,0 +1,172 @@ +--- +permalink: fastest-way-to-insert +--- + +## What’s the FASTEST way to insert in Entity Framework? + +This question keeps getting asked a few times every week on Stack Overflow. +Most common solutions usually involve: + +- Using AddRange over Add method +- Calling SaveChanges every X entities +- Creating a new context every X entities +- Disabling Change Detection +- Disabling Change Validation +- Disabling Proxy + +Some of these solutions are good, some lead to side impacts and none of them fix the main issue: One database round-trip is made for every entity you save! +So if you have 5000 entities to insert, 5000 databases round trips will be executed which is **INSANELY** slow. + +A very common mistake is believing the AddRange method perform a Bulk Insert. Using the AddRange method greatly improve the performance because it calls the DetectChanges method only once after all entities are added to the change tracker. However, the SaveChanges method will still make one database round-trip per entity. + +### Solution +To solve the performance problem, you need to reduce the number of database round-trips, and this is exactly what Entity Framework Extensions made by ZZZ Projects do by providing the BulkInsert method and all other bulk operations: + +- [BulkSaveChanges](#ef-bulksavechanges) +- [BulkInsert](#ef-bulkinsert) +- [BullUpdate](#ef-bulkupdate) +- [BulkDelete](#ef-bulkdelete) +- [BulkMerge](#ef-bulkmerge) + +With this library, only a few database round-trips will now be required when saving 5000 entities which can lead to performance improvement by 50x times and more. + +You can find the library documentation here: [EFE – Tutorials](http://entityframework-extensions.net/tutorials) + +Getting started with this library could not be easier. You download it using [NuGet](https://www.nuget.org/packages/Z.EntityFramework.Extensions/){:target="_blank"}, and all bulk methods are automatically available from your context instance since methods extend the DbContext class. + +Without having to configure anything, all models and scenarios are supported such as Code First, Database First, Inheritances (TPC, TPH, and TPT), Relationship, and everything else! + +## EF BulkSaveChanges +BulkSaveChanges method works like SaveChanges but performs save operations (INSERT, UPDATE, and DELETE) way faster. +There are multiple options available such as: + +- Disable Concurrency Check +- Disable Entity Framework Propagation for better performance +- Update Modified values only + +This method is normally recommended over bulk methoda such as Bulk Insert since it acts like SaveChanges by using the Change Tracker and propagating the value. + +Tutorial: [EFE – Bulk SaveChanges](http://entityframework-extensions.net/bulk-savechanges) + +### Example +```csharp +ctx.BulkSaveChanges(); + +ctx.BulkSaveChanges(useEntityFrameworkPropagation: false); + +ctx.BulkSaveChanges(options => +{ + options.AllowConcurrency = false; + options.ForceUpdateUnmodifiedValues = false; +}); +``` + +## EF BulkInsert +BulkInsert method performs an INSERT operation and outputs the identity value. +There are multiple options available such as: + +- Custom Column +- Disabled output value for better performance +- Insert only entities that don't already exists +- Keep Identity Value + +Bulk Insert is faster than BulkSaveChanges. However, Bulk Insert doesn’t use the Change Tracker so identity value propagation may differ. If you need to perform multiple bulk operations with some relation, it’s recommended to use BulkSaveChanges instead. + +Tutorial: [EFE – Bulk Insert](http://entityframework-extensions.net/bulk-insert) + +### Example +```csharp +ctx.BulkInsert(customers); + +ctx.BulkInsert(customers, options => +{ + options.ColumnInputExpression = x => new {x.Code, x.Email}; + options.AutoMapOutputDirection = false; + options.InsertIfNotExists = true; + options.InsertKeepIdentity = true; +}); +``` + +## EF BulkUpdate +BulkUpdate method performs an UPDATE operation. + +Tutorial: [EFE – Bulk Update](http://entityframework-extensions.net/bulk-update) + +There are multiple options available such: + +- Custom Column +- Custom Key +- Disable Concurrency Check + +### Example +```csharp +ctx.BulkUpdate(customers, options => +{ + options.ColumnInputExpression = x => new { x.Code, x.Email }; + options.ColumnPrimaryKeyExpression = x => new { x.Code }; + options.AllowConcurrency = false; +}); +``` + +## EF BulkDelete +BulkDelete method performs a DELETE operation. + +There are multiple options available such as: + +- Custom Key +- Disable Concurrency Check + +Tutorial: [EFE – Bulk Delete](http://entityframework-extensions.net/bulk-delete) + +### Example +```csharp +ctx.BulkDelete(list); + +ctx.BulkDelete(list, options => +{ + options.ColumnPrimaryKeyExpression = x => new { x.Code }; + options.AllowConcurrency = false; +}); +``` + +## EF BulkMerge +BulkMerge method performs an UPSERT operation and outputs the identity value. Existing entities matching the key are updated, and newly entities are inserted. + +There are multiple options available such as: + +- Custom Column +- Custom Column (Insert Only) +- Custom Column (Update Only) +- Custom Key +- Disabled output value for better performance +- Keep Identity Value + +Tutorial: [EFE – Bulk Merge](http://entityframework-extensions.net/bulk-merge) + +### Example +```csharp +ctx.BulkMerge(list); + +ctx.BulkMerge(list, options => +{ + options.ColumnInputExpression = x => new { x.Code, x.CreatedDate, x.UpdatedDate }; + options.IgnoreOnMergeInsertExpression = x => new { x. UpdatedDate }; + options.IgnoreOnMergeUpdateExpression = x => new { x.ID, x.CreatedDate }; + options.ColumnPrimaryKeyExpression = x => new { x.Code }; + options.AutoMapOutputDirection = false; + options.MergeKeepIdentity = true; +}); +``` + +## Conclusion +Entity Framework Extensions is well tested with over 10k unit tests and currently used by thousands of company all around the world. Without a doubt, it is the ultimate library to improve your performance with Entity Framework. + +On the negative side, this library is not free. + +ZZZ Projects gives back value to the .NET community by supporting some other free libraries, tutorials and sponsoring project such as: + +- [Entity Framework Plus](http://entityframework-plus.net/){:target="_blank"} +- [Html Agility Pack](http://html-agility-pack.net/){:target="_blank"} +- [Extension Methods](https://github.com/zzzprojects/Z.ExtensionMethods){:target="_blank"} +- [Dapper Tutorial](http://dapper-tutorial.net/){:target="_blank"} +- Help partners like [Entity Framework Tutorial](http://www.entityframeworktutorial.net/){:target="_blank"} diff --git a/docs/pages/articles/improve-bulk-savechanges.md b/docs/pages/articles/improve-bulk-savechanges.md new file mode 100644 index 0000000..26e75cd --- /dev/null +++ b/docs/pages/articles/improve-bulk-savechanges.md @@ -0,0 +1,55 @@ +--- +permalink: improve-bulk-savechanges +--- + +## Introduction +BulkSaveChanges is already very fast. But you can make it even faster by simply turning off the "EntityFrameworkPropagation" options. + +While the performance will be significantly increased, this option works with 99,9% of models. Unfortunately, we cannot turn this option on by default for backward compatibility until we make it work with all models + +We are currently working on the next major version which will have even better performances! + +[Learn - Why turning off Entity Framework Propagation is faster](#why-turning-off-entity-framework-propagation-is-faster) + +### Example - Globally +{% include template-example.html %} +{% highlight csharp %} +EntityFrameworkManager.DefaultEntityFrameworkPropagationValue = false; +{% endhighlight %} + +### Example - By Instance +{% include template-example.html %} +{% highlight csharp %} +var ctx = new EntitiesContext(); + +ctx.Customers.AddRange(listToAdd); +ctx.Customers.RemoveRange(listToRemove); +listToModify.ForEach(x => x.DateModified = DateTime.Now); + +// Easy to use +ctx.BulkSaveChanges(false); +{% endhighlight %} + +### Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| BulkSaveChanges() | 90 ms | 150 ms | 350 ms | +| BulkSaveChanges(false) | 60 ms | 70 ms | 140 ms | + +For SQL Server, performance improvement is around 2x faster. + +For some provider like SQLite, performance improvement can be as high as 10x faster. + +### Unsupported Scenario + +- There is too much cross reference table, and the library is not able to create a saving strategy. You will receive an error on the first use. +- An entity uses a temporary generated GUID when adding (not empty), but the GUID is replaced later by the GUID generated in the database. Data will be correctly inserted, but entities may still have the temporary GUID for relation not using navigation property. + +> These limitations will be fixed in the next major version. + +## Why turning off Entity Framework Propagation is faster +Unfortunately, Entity Framework is very slow at generating commands to be executed. For some providers, it takes more time to generate these queries than executing them! + +When turning off, the library does no longer use the methods from Entity Framework but internal methods from our library. diff --git a/docs/pages/articles/soft-delete.md b/docs/pages/articles/soft-delete.md new file mode 100644 index 0000000..d6770b5 --- /dev/null +++ b/docs/pages/articles/soft-delete.md @@ -0,0 +1,111 @@ +--- +permalink: soft-delete +--- + +## Problem +You want to soft delete some entities currently in deleted state with BulkSaveChanges. + +{% include template-example.html %} +{% highlight csharp %} +using (var ctx = new CurrentContext()) +{ + var lastLogin = DateTime.Now.AddYears(-2); + var list = ctx.Customers.Where(x => x.LastLogin < lastLogin).ToList(); + ctx.Customers.RemoveRange(list); + + // HOW to automatically handle soft delete? + ctx.BulkSaveChanges(); +} +{% endhighlight %} + +### Solution +You can use the **EntityFrameworkManager.PreBulkSaveChanges** property to change state & value from entities prior to the BulkSaveChanges execution + +### Example + +{% include template-example.html %} +{% highlight csharp %} +EntityFrameworkManager.PreBulkSaveChanges = context => +{ + foreach (var entry in context.ChangeTracker.Entries()) + { + if (entry.State == EntityState.Deleted && entry.Entity is Customer) + { + entry.State = EntityState.Modified; + ((Customer) entry.Entity).IsDeleted = true; + } + } +}; + +using (var ctx = new CurrentContext()) +{ + var lastLogin = DateTime.Now.AddYears(-2); + var list = ctx.Customers.Where(x => x.LastLogin < lastLogin).ToList(); + ctx.Customers.RemoveRange(list); + ctx.BulkSaveChanges(); +} +{% endhighlight %} + +## Problem +You want to soft delete some entities currently in deleted state with BulkDelete. + +{% include template-example.html %} +{% highlight csharp %} +using (var ctx = new CurrentContext()) +{ + var lastLogin = DateTime.Now.AddYears(-2); + var list = ctx.Customers.Where(x => x.LastLogin < lastLogin).ToList(); + + // HOW to automatically handle soft delete? + ctx.BulkDelete(list); +} +{% endhighlight %} + +### Solution +Unfortunately, there is no way to SoftDelete using BulkDelete. Since BulkDelete doesn't use ChangeTracker for optimization reasons, you will have to implement yourself an extension method to handle this scenario. + +### Example + +{% include template-example.html %} +{% highlight csharp %} +public static class Extensions +{ + public static void BulkHardOrSoftDelete(this DbContext ctx, IEnumerable items) where T : class + { + var hardDelete = new List(); + var softDelete = new List(); + + foreach (var item in items) + { + var customer = item as Customer; + if (customer != null) + { + customer.IsDeleted = true; + softDelete.Add(item); + } + else + { + hardDelete.Add(item); + } + } + + if (hardDelete.Count > 0) + { + ctx.BulkDelete(hardDelete); + } + if (softDelete.Count > 0) + { + ctx.BulkUpdate(softDelete); + } + } +} + +using (var ctx = new CurrentContext()) +{ + var lastLogin = DateTime.Now.AddYears(-2); + var list = ctx.Customers.Where(x => x.LastLogin < lastLogin).ToList(); + + ctx.BulkHardOrSoftDelete(list); +} +{% endhighlight %} + diff --git a/docs/pages/faq/faq-general.md b/docs/pages/faq/faq-general.md new file mode 100644 index 0000000..c59b71d --- /dev/null +++ b/docs/pages/faq/faq-general.md @@ -0,0 +1,20 @@ +--- +permalink: faq-general +--- + +## Which Payment method do you support? +We support the following payment method: + +- PayPal +- Check +- Bank Transfer + +## Can I purchase this product from a Reseller? +Yes, just let him know to contact us. + +## What's your average SLA response and resolution time? +We try to provide an outstanding support service. + +We normally answer very fast, often within one hour. + +Most fixes are resolved within one business day. diff --git a/docs/pages/faq/faq-installation.md b/docs/pages/faq/faq-installation.md new file mode 100644 index 0000000..dd0aff2 --- /dev/null +++ b/docs/pages/faq/faq-installation.md @@ -0,0 +1,12 @@ +--- +permalink: faq-installation +--- + +## How to install your product? +It is simple, you download it from NuGet and add it to your project. + +More Info: [Tutorials - Installing](installing) + +## I have installed your product, but I don't see your extensions method +- Make sure to install it in the right project +- Make sure your project support .NET40 or better diff --git a/docs/pages/faq/faq-license.md b/docs/pages/faq/faq-license.md new file mode 100644 index 0000000..896ab0d --- /dev/null +++ b/docs/pages/faq/faq-license.md @@ -0,0 +1,76 @@ +--- +permalink: faq-license +--- + +## Developer Seat + +### What's a developer seat? +A developer seat is a developer working for your company and developing code directly with our product. + +You don't have to purchase developer seat for front-end developer or back-end developer which doesn't use our product API. + +Since you buy developer seats, you can develop an unlimited amount of projects within your company. + +### What's the cost for additional developer seats? +The cost for additional developer seats is usually extremely low. We want to make sure our library is accessible for small and large company. + +### Are developer seats transferable? +Yes, a developer seat can be transferred to any employee within your company. + +## Perpertual License + +### What's a perpetual license? +A perpetual license allows you to use the licensed product indefinitely. + +### Even when my Support & Upgrade is expired? +Yes. + +## Support & Upgdrade + +### My support & upgrade period is expired! What will happen? +Don't worry. Your product keeps on working forever! + +You can still download and use any version released before the support & upgrade expiration date. + +You will need to renew your license to use version released after the support & upgrade expiration date. + +### How do I renew my License? +We usually start to send renewal mails two months before the support & upgrade expiry date. + +If you didn't receive such email, you could contact us directly: info@zzzprojects.com + +### Can I have a renewal discount? +We provide a 25% discount to early renewal. Anyone renewing before the support & upgrade expiration date automatically gets a renewal discount. + +### I'm too late for early renewal discount! What can I do? +If you are few days late, we still provide early renewal discount. + +However, if you have few months late, you will need to purchase the library again. + +The best way to find out if you still have access to early renewal discount is by contacting us: info@zzzprojects.com + +### Why should I renew? +Renewing your support & upgrade gives the following benefits: + +- Major version releases and new product features +- Fast support by mail +- Protection against price increases during the maintenance term + +## Royalty Free + +### Can I install Entity Framework Extensions on Client Machine? +Yes, the product is royalty free. + +That means, you paid for developer seat, but customers using your product don't have to pay us. + +### Is Entity Framework Extensions Royalty Free? +Yes, the product is royalty free. + +This mean, you can develop a project and install it on thousands of clients. + +You paid for developer seat within your company. + +Some standard royalty free limitations: + +- You can't sell a similar product and claim it's yours. +- If your customer has access to your source code and develops using our API, they will have to purchase a license. diff --git a/docs/pages/faq/faq.md b/docs/pages/faq/faq.md new file mode 100644 index 0000000..3f2e027 --- /dev/null +++ b/docs/pages/faq/faq.md @@ -0,0 +1,8 @@ +--- +permalink: faq +--- + +- [General](faq-general) +- [Installation](faq-installation) +- [Issue Tracker](issue-tracker) +- [License](faq-license) \ No newline at end of file diff --git a/docs/pages/faq/issue-tracker.md b/docs/pages/faq/issue-tracker.md new file mode 100644 index 0000000..9f0602c --- /dev/null +++ b/docs/pages/faq/issue-tracker.md @@ -0,0 +1,13 @@ +--- +permalink: issue-tracker +--- + +## Where is your Issue Tracker? + +While we prefer to be contacted directly: info@zzzprojects.com + +We understand some people prefer to have an online issue tracker to follow and comment their issues. + +You can create an issue here: + +- [Issue Tracker](https://github.com/zzzprojects/EntityFramework-Extensions/issues) diff --git a/docs/pages/problems/dbbulkoperationconcurrency-exception.md b/docs/pages/problems/dbbulkoperationconcurrency-exception.md new file mode 100644 index 0000000..2dec19c --- /dev/null +++ b/docs/pages/problems/dbbulkoperationconcurrency-exception.md @@ -0,0 +1,89 @@ +--- +permalink: dbbulkoperationconcurrency-exception +--- + +## Problem + +You execute a method from the Entity Framework Extensions library, and the following error is thrown: + +- Type: DbBulkOperationConcurrencyException + +{% include template-exception.html message='A concurrency exception has occured. Entities may have been modified or deleted since entities were loaded.' %} + +## Solution + +### Cause + +Another thread already performed the operation. + +### Fix + +There are three possible resolutions: + +- Database Win +- Client Win +- Custom Resolution + +#### Database Win +{% include template-example.html %} +{% highlight csharp %} +public void BulkUpdate_DatabaseWins(CurrentContext ctx, List list) where T : class +{ + try + { + ctx.BulkUpdate(list); + } + catch (DbBulkOperationConcurrencyException ex) + { + // DO nothing (or log), keep database values! + } +} +{% endhighlight %} + +#### Client Win +{% include template-example.html %} +{% highlight csharp %} +public void BulkUpdate_StoreWins(CurrentContext ctx, List list) where T : class +{ + try + { + ctx.BulkUpdate(list); + } + catch (DbBulkOperationConcurrencyException ex) + { + // FORCE update store entities + ctx.BulkUpdate(list, operation => operation.AllowConcurrency = false); + } +} +{% endhighlight %} + +#### Custom Resolution +{% include template-example.html %} +{% highlight csharp %} +public void BulkUpdate_CustomResolution(CurrentContext ctx, List list) where T : class +{ + try + { + ctx.BulkUpdate(list); + } + catch (DbBulkOperationConcurrencyException ex) + { + foreach (var entry in ex.Entries) + { + ObjectStateEntry objectEntry; + + if (entry is EntitySimple_Concurrency) + { + var clientEntry = (EntitySimple_Concurrency) entry; + var databaseEntry = ctx.EntitySimple_Concurrencys.Single(x => x.ID == clientEntry.ID); + + // merge properties like you want + clientEntry.IntColumn = databaseEntry.IntColumn + 303; + } + } + + // FORCE update store entities + ctx.BulkUpdate(list, operation => operation.AllowConcurrency = false); + } +} +{% endhighlight %} diff --git a/docs/pages/problems/dbupdateconcurrency-exception.md b/docs/pages/problems/dbupdateconcurrency-exception.md new file mode 100644 index 0000000..811ea3c --- /dev/null +++ b/docs/pages/problems/dbupdateconcurrency-exception.md @@ -0,0 +1,129 @@ +--- +permalink: dbupdateconcurrency-exception +--- + +## Problem + +You execute a method from the Entity Framework Extensions library, and the following error is thrown: + +- Type: DbUpdateConcurrencyException + +{% include template-exception.html message='Store update, insert, or delete statement affected an unexpected number of rows ([row count]). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.' %} + +## Solution + +### Cause + +Another thread have already performed the operation. + +### Fix + +There are three possible resolutions: + +- Database Win +- Client Win +- Custom Resolution + +#### Database Win +{% include template-example.html %} +{% highlight csharp %} +public void BulkSaveChanges_DatabaseWins(DbContext ctx) +{ + bool saveFailed; + + do + { + saveFailed = false; + + try + { + ctx.BulkSaveChanges(); + } + catch (DbUpdateConcurrencyException ex) + { + saveFailed = true; + + // Update the values of the entity that failed to save from the store + ex.Entries.Single().Reload(); + } + + } while (saveFailed); +} +{% endhighlight %} + +#### Client Win +{% include template-example.html %} +{% highlight csharp %} +public void BulkSaveChanges_ClientWins(DbContext ctx) +{ + bool saveFailed; + + do + { + saveFailed = false; + + try + { + ctx.BulkSaveChanges(); + } + catch (DbUpdateConcurrencyException ex) + { + saveFailed = true; + + // Update original values from the database + var entry = ex.Entries.Single(); + entry.OriginalValues.SetValues(entry.GetDatabaseValues()); + } + + } while (saveFailed); +} +{% endhighlight %} + +#### Custom Resolution +{% include template-example.html %} +{% highlight csharp %} +public void BulkSaveChanges_CustomResolution(CurrentContext ctx) +{ + + bool saveFailed; + + do + { + saveFailed = false; + + try + { + ctx.BulkSaveChanges(); + } + catch (DbUpdateConcurrencyException ex) + { + saveFailed = true; + + // Get the current entity values and the values in the database + // as instances of the entity type + var entry = ex.Entries.Single(); + var databaseValues = entry.GetDatabaseValues(); + + if (entry.Entity is EntitySimple_Concurrency) + { + var clientEntity = (EntitySimple_Concurrency) entry.Entity; + var databaseEntity = (EntitySimple_Concurrency) databaseValues.ToObject(); + + // Choose an initial set of resolved values. In this case we + // make the default be the values currently in the database. + var resolvedEntity = (EntitySimple_Concurrency) databaseValues.ToObject(); + + // Have the user choose what the resolved values should be + resolvedEntity.IntColumn = clientEntity.IntColumn + 100; + // ... merge all columns... + + // Update the original values with the database values and + // the current values with whatever the user chooses. + entry.OriginalValues.SetValues(databaseValues); + entry.CurrentValues.SetValues(resolvedEntity); + } + } + + } while (saveFailed); +} +{% endhighlight %} diff --git a/docs/pages/problems/foreign-key-constraint-autodetectchanges-disabled.md b/docs/pages/problems/foreign-key-constraint-autodetectchanges-disabled.md new file mode 100644 index 0000000..7a01c98 --- /dev/null +++ b/docs/pages/problems/foreign-key-constraint-autodetectchanges-disabled.md @@ -0,0 +1,42 @@ +--- +permalink: foreign-key-constraint-autodetectchanges-disabled +--- + +## Problem + +You execute a method from the Entity Framework Extensions library, and the following error is thrown: + +{% include template-exception.html message='The MERGE statement conflicted with the FOREIGN KEY constraint "[FK_Name]". The conflict occurred in database "[Database_Name]", table "[Table_Name]", column \'[Column_Name]\'.' %} + +And you use a code similar to this: + +{% include template-example.html %} +{% highlight csharp %} +using (var ctx = new MyEntities()) +{ + ctx.Configuration.AutoDetectChangesEnabled = false; + ctx.Categories.AddRange(categories); + ctx.Items.AddRange(items); + ctx.BulkSaveChanges(); +} +{% endhighlight %} + +## Solution + +### Cause + +One cause could be simply a wrong save order provided by either Entity Framework or EFE Library. + +### Cause Source +The main reason that could cause this issue is disabling AutoDetectChanges and not enabling it before the SaveChanges/BulkSaveChanges. + +When the AutoDetectChanges is disabled, there is no check about the relationship, and that could cause sometimes the item to be added before a new Category (Which should be added first)! Leading to the Foreign Key issue. + +In additional, there is no reason why this code should disable DetectChanges. Since the AddRange method is used, the “DetectChanges” method is called only once per AddRange call, so don't suffer from a performance issue. + +### Fix + +1. ADD the line AutoDectectChangesEnabled = true; before BulkSaveChanges +2. CALL ctx.ChangeTracker.DetectChanges(); +3. REMOVE the line AutoDetectChangesEnabled = false; + diff --git a/docs/pages/problems/md5-exception.md b/docs/pages/problems/md5-exception.md new file mode 100644 index 0000000..c9545e7 --- /dev/null +++ b/docs/pages/problems/md5-exception.md @@ -0,0 +1,27 @@ +--- +permalink: md5-exception +--- + +## Problem + +You execute a method from the Entity Framework Extensions library, and the following error is thrown: + +{% include template-exception.html message='This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms.' %} + +## Solution + +### Cause + +The default algorithm to validate the license key & name is not supported with FIPS enabled. + +### Fix + +#### Ask for a compatible key + +Contact us and we will send you a new key supporting FIPS: {% include infozzzprojects-email.html %} + +Why don’t we generated key compatible with FIPS by default? Because it will not be supported for a client machine with Windows XP or below. + +#### Disable FIPS + +Article: [Disable FIPS](http://docs.trendmicro.com/all/ent/sc/v3.0/en-US/cmcolh/t_fips.html){:target="_blank"} diff --git a/docs/pages/problems/out-of-memory.md b/docs/pages/problems/out-of-memory.md new file mode 100644 index 0000000..25c8c6b --- /dev/null +++ b/docs/pages/problems/out-of-memory.md @@ -0,0 +1,36 @@ +--- +permalink: out-of-memory +--- + +## Problem + +You execute a method from the Entity Framework Extensions library, and the following error is thrown: + +{% include template-exception.html message='An exception of type `System.OutOfMemoryException` occured in...' %} + +## Cause +That error is caused when the library consumes too much memory. + +Most of the time, this error is caused by some methods used from `Entity Framework` for command generations that will be used later by our library. + +### Fix +Turning off Entity Framework Propagation + +This solution work with around 99% of model. By turning off this options, our library doesn’t longer use several methods from Entity Framework that consume high memory such as the command generations. + +See: Improve BulkSaveChanges + +### Bulk Operations +In some exceptional scenario, using Bulk Operations such as: + +- BulkInsert +- BulkUpdate +- BulkDelete +- BulkMerge + +might may a better idea. They are faster and consume way less memory than BulkSaveChanges. + +### Reduce the number of entities in the ChangeTracker +Another way is to make sure the ChangeTracker doesn’t contain too many entities. + +The ChangeTracker has not been build to support millions entities. \ No newline at end of file diff --git a/docs/pages/problems/problems.md b/docs/pages/problems/problems.md new file mode 100644 index 0000000..eaf2c32 --- /dev/null +++ b/docs/pages/problems/problems.md @@ -0,0 +1,9 @@ +--- +permalink: problems +--- + +You got a problem or a question you didn’t find an answer here? + +Contact us: info@zzzprojects.com + +We usually answer within the next business day, hour, or minutes! diff --git a/docs/pages/problems/trial-period-expired-exception.md b/docs/pages/problems/trial-period-expired-exception.md new file mode 100644 index 0000000..fcf2c86 --- /dev/null +++ b/docs/pages/problems/trial-period-expired-exception.md @@ -0,0 +1,35 @@ +--- +permalink: trial-period-expired-exception +--- + +## Problem + +You execute a method from the Entity Framework Extensions library, and the following error is thrown: + +{% include template-exception.html message='ERROR_005: The monthly trial period is expired. You can extend your trial by downloading the latest version. You can also purchase a perpetual license on our website. If you already own this license, this error only appears if the license has not been found, you can find additional information on our troubleshooting section (http://entityframework-extensions.net/troubleshooting). Contact our support team for more details: info@zzzprojects.com' %} + +## Solution + +### Cause + +- You are currently evaluating the library and the trial period is expired. +- You have purchased the license but didn't register it correctly. +- You called methods from the library before registering the license. + +### Fix + +#### Trial Period Expired + +You can extend your trial by downloading the latest version: [Upgrading](http://entityframework-extensions.net/upgrading) + +The latest version always contains a trial for the current month to allow companies to evaluate our library for several months. + +#### License Badly Registered + +Make sure to follow all recommendations about how to setup your license: [Licensing](http://entityframework-extensions.net/licensing) + +#### Method called before registering + +Make sure to register your license before calling any other methods from our library. Otherwise, you could enable the trial period instead. + +Make sure to follow all recommendations about how to setup your license: [Licensing](http://entityframework-extensions.net/licensing) diff --git a/docs/pages/problems/type-not-supported-exception.md b/docs/pages/problems/type-not-supported-exception.md new file mode 100644 index 0000000..a473592 --- /dev/null +++ b/docs/pages/problems/type-not-supported-exception.md @@ -0,0 +1,20 @@ +--- +permalink: type-not-supported-exception +--- + +## Problem + +You execute a method from the Entity Framework Extensions library, and the following error is thrown: + +{% include template-exception.html message='Type not supported yet (LazyType): [TypeName]' %} + +## Solution + +### Cause + +For some provider, we may have missed a few types. They are added on demand. + +### Fix +Contact our support team with the provider && type name: info@zzzprojects.com + +We usually fix && test this kind of issue within 24h diff --git a/docs/pages/site/contact-us.md b/docs/pages/site/contact-us.md new file mode 100644 index 0000000..51edcc0 --- /dev/null +++ b/docs/pages/site/contact-us.md @@ -0,0 +1,101 @@ +--- +permalink: contact-us +--- + +
+ + + +
+
+ + + + + + + + + + +{% include section-faq-begin.html %} + +### I have a question! How should I contact you? +{:.show} +Contact us directly: info@zzzprojects.com + +Whether you need more personal help to get started or you just wanted to give us your opinion on the library, we love to hear from you! + +You can also find some answers on: +- [Issues Tracker](https://github.com/zzzprojects/EntityFramework-Extensions/issues){:target="_blank"} +- [Stack Overflow](https://stackoverflow.com/questions/tagged/entity-framework-extensions){:target="_blank"} + +### I think I've found a bug, where should I report it? +The best way to report an issue is using our [Issues Tracker](https://github.com/zzzprojects/EntityFramework-Extensions/issues){:target="_blank"} + +Make sure to include: +- Entity Framework Version +- Entity Framework Extensions Version +- Database Provider + +You can always contact us directly: + +- If you want a more personal answer +- If your question is not suited for the Issue Tracker +- If your message contains private information + +### I need a feature your library is lacking. Can I recommend it? +If your project requests a feature we haven’t thought of, please let us know using our [Issues Tracker](https://github.com/zzzprojects/EntityFramework-Extensions/issues){:target="_blank"} + +We will develop and implement it as soon as possible, sometimes the same day. You could also contact us directly: + +- If you want a more personal answer +- If your question is not suited for the Issue Tracker +- If your message contains private information + +### I'm not fluent in English! How can we communicate? + +We prefer to keep all communications in either: +- English +- French + +But thanks for Google Translate, we can understand each other worldwide: +- Chinese +- Spanish +- Hindi +- Etc. + +We will do our best to accommodate you. + +{% include section-faq-end.html %} + +
+
+
+
+

Contact Info

+
+
+

Question & Support

+ info@zzzprojects.com +

Sales

+ sales@zzzprojects.com +

Issues & Requests

+ Issues Tracker +
+
+

+
+
+
\ No newline at end of file diff --git a/docs/pages/site/download.md b/docs/pages/site/download.md new file mode 100644 index 0000000..26d3e3c --- /dev/null +++ b/docs/pages/site/download.md @@ -0,0 +1,114 @@ +--- +permalink: download +--- + +
+
+ +
+
+
+ +
+ + + NuGet Download + +
Download Count:
+
+ + + +
+
+
+
+
+
+
+
+
+

Contact Us

+
+
+
    +
  • Got a question?
  • +
  • Need help?
  • +
  • Performance not as good as expected?
  • +
+ Make sure to contact us, we are always here to help you. + info@zzzprojects.com +
+
+

+
+
+ +
+
+--- +## FAQ + +### How can I extend my trial? +The latest version always contains a trial that expires at the end of the month. You can extend your trial for several months by downloading the latest version at the begining of every month. + +### Why this library is not free and open source? +`ZZZ Projects` mission is focused on adding value to the `.NET Community` and supporting a lot of `free and open source` libraries. + +However, this mission cannot be successful without being able to pay our developers for the time they pass to support & develop features for free and paid libraries. + +#### Free Librairies + +- [Html Agility Pack](http://html-agility-pack.net/){:target="_blank"} +- [Entity Framework Plus](http://entityframework-plus.net/){:target="_blank"} +- [Entity Framework DynamicFilter](https://github.com/zzzprojects/EntityFramework.DynamicFilters){:target="_blank"} +- [RefactorThis.GraphDiff](https://github.com/zzzprojects/GraphDiff){:target="_blank"} +- [Extension Methods](https://github.com/zzzprojects/Z.ExtensionMethods){:target="_blank"} + +#### Website + +- [.NET Fiddle](https://dotnetfiddle.net/){:target="_blank"} +- [SQL Fiddle](http://sqlfiddle.com/){:target="_blank"} +- [NuGet Must Haves](http://nugetmusthaves.com/){:target="_blank"} +- [Dapper Tutorial](http://dapper-tutorial.net/){:target="_blank"} + +By contributing on paid libraries, you are also helping in keeping other libraries and website FREE. + +
+
+ + \ No newline at end of file diff --git a/docs/pages/site/pricing.md b/docs/pages/site/pricing.md new file mode 100644 index 0000000..ae4cff8 --- /dev/null +++ b/docs/pages/site/pricing.md @@ -0,0 +1,154 @@ +--- +permalink: pricing +--- + + + + + +
+ +
+
+
+ + + + +

Step 1 - Choose License

+
+
+ + +
+ + +
+ +

Step 2 - Purchase

+
+ +
+
+ + +
* Read the FAQ below for alternative payment method.
+
+ +
+ +
+ +
+
+

Not ready yet?

+
+
+

Free trial

+

Download our monthly trial

+

Extend your trial for several months by downloading the latest version at the begining of every month.

+

License

+ The license include: +
    +
  • All bulk extensions methods
  • +
  • Commercial License
  • +
  • Royalty-Free
  • +
  • Perpetual Licenses
  • +
  • Support & Upgrades (1 year)
  • +
+

Question

+

Contact us: {% include mail-sales.html %}

+
+
+
+
+
+ +--- + +
+{% include section-faq-begin.html %} + +## FAQ + +### Which payment alternative methods are accepted? +We accept `PayPal`, `Cheque` and `Wire Transfer`. + +We **DO NOT** accept bitcoins and credit cards. + +Please contact us for more information. + +Email: sales@zzzprojects.com + +### Do you accept resellers? +Yes contact us if you are a reseller or seeking for a reseller. + +Email: sales@zzzprojects.com + +### What 2-4 developer seats mean? +It mean that you can use the license with up to 4 developers inside your team. + +The `5-9` developer seats mean you can use the license with up 9 developers. + +You only pay for developer seats. You can use our library with an unlimited amount of applications, environments, servers, and client machines. + +### I need more than 19 seats, what can I do? +Please contact us with the number of seats required. We offer some additional discounts or enterprise licenses. + +Email: sales@zzzprojects.com + +### Is the license perpetual? +The product comes with one year of support & upgrades but the license is perpetual (indefinitely useable). So you are not obligated to renew every year or renew at all. + +Renewing comes with a lot of benefits such as a 25%/35%/50% discount on purchased price, discounted or free products, etc. + +### Why isn't this library free and open source? +`ZZZ Projects` mission is focused on adding value to the `.NET Community` and supporting a lot of `free and open source` libraries. + +However, this mission cannot be successful without being able to pay our developers for the time they pass to support & develop features for free and paid libraries. + +#### Free Librairies + +- [Html Agility Pack](http://html-agility-pack.net/){:target="_blank"} +- [Entity Framework Plus](http://entityframework-plus.net/){:target="_blank"} +- [Entity Framework DynamicFilter](https://github.com/zzzprojects/EntityFramework.DynamicFilters){:target="_blank"} +- [RefactorThis.GraphDiff](https://github.com/zzzprojects/GraphDiff){:target="_blank"} +- [Extension Methods](https://github.com/zzzprojects/Z.ExtensionMethods){:target="_blank"} + +#### Website + +- [.NET Fiddle](https://dotnetfiddle.net/){:target="_blank"} +- [SQL Fiddle](http://sqlfiddle.com/){:target="_blank"} +- [NuGet Must Haves](http://nugetmusthaves.com/){:target="_blank"} +- [Dapper Tutorial](http://dapper-tutorial.net/){:target="_blank"} + +By contributing on paid libraries, you are also helping in keeping other libraries and website FREE. + +{% include section-faq-end.html %} +
\ No newline at end of file diff --git a/docs/pages/site/trial.md b/docs/pages/site/trial.md new file mode 100644 index 0000000..bf98837 --- /dev/null +++ b/docs/pages/site/trial.md @@ -0,0 +1,20 @@ +--- +permalink: trial +--- + +Oops! Your trial has expired. + +### How can I extend my trial? +You can extend your trial for several months by downloading the latest version at the beginning of every month. + + + + Download + + + +### Where is the free version? +There is no free version. All free features has been moved to a different library: Entity Framework Plus + +### How can I purchase a license? +A perpetual license can be purchased from here: Buy \ No newline at end of file diff --git a/docs/pages/tutorials.md b/docs/pages/tutorials.md new file mode 100644 index 0000000..d7edef2 --- /dev/null +++ b/docs/pages/tutorials.md @@ -0,0 +1,52 @@ +--- +permalink: tutorials +--- + +
+ +
+
+
+

Getting Started

+

Learn the Basics

+
+

Start using Entity Framework Extensions with our quick getting started tutorial.

+

+ Learn more +

+
+
+
+
+

API

+

Application Program Interface

+
+

Start learning the common API of Entity Framework Extensions, and everything around it.

+

+ Learn more +

+
+
+
+
+

FAQ

+

Freqently Answered Question

+
+

Discover Entity Framework Extensions best practices and solution to the common problem you may encounter.

+

+ Learn more +

+
+
+
+
+

Problems

+

Exception & Troubleshooting

+
+

Learn how to fix and handle some exception and common troubleshooting error.

+

+ Learn more +

+
+
+
diff --git a/docs/pages/tutorials/installing.md b/docs/pages/tutorials/installing.md new file mode 100644 index 0000000..86f476e --- /dev/null +++ b/docs/pages/tutorials/installing.md @@ -0,0 +1,51 @@ +--- +permalink: installing +--- + +**LinqToSql Plus** can be installed through NuGet. + +This library is **NOT FREE** + +The latest version always contains a trial that expires at the end of the month. You can extend your trial for several months by downloading the latest version at the begining of every month. + +## Step 1 - NuGet Download + +Go to the download page and choose the right Entity Framework version for your project. + + + + Download + + + +## Step 2 - Done + +**LinqToSql Plus** doesn't require any configuration by default. + +All bulk operations extension methods are automatically added to your DbContext: +- BulkInsert +- BulkUpdate +- BulkDelete +- BulkMerge +- BulkSynchronize + +{% include template-example.html title='Bulk Operations Examples'%} +{% highlight csharp %} +// Bulk Operations +context.BulkInsert(list); +context.BulkUpdate(list); +context.BulkDelete(list); +context.BulkMerge(list); +context.BulkSynchronize(list); +{% endhighlight %} + +All batch operations extension methods are automatically added to your Queryable: +- DeleteFromQuery +- UpdateFromQuery + +{% include template-example.html title='Batch Operations Examples'%} +{% highlight csharp %} +// Batch Operations +context.Customers.Where(x => !x.IsActif).DeleteFromQuery(); +context.Customers.Where(x => !x.IsActif).UpdateFromQuery(x => new Customer {Actif = true}); +{% endhighlight %} diff --git a/docs/pages/tutorials/licensing.md b/docs/pages/tutorials/licensing.md new file mode 100644 index 0000000..e9b2967 --- /dev/null +++ b/docs/pages/tutorials/licensing.md @@ -0,0 +1,53 @@ +--- +permalink: licensing +--- + +## Evaluation Period +- You can evaluate the library for several months before purchasing it. +- The latest version always contains a trial that expires at the **end of the month**. +- You can extend your trial for several months by downloading the latest version at the begining of every month. +- If you want to use the library for personal use or educational purpose, it's possible by downloading the latest version once a month. + +## How can I purchase the library? +- You can purchase the library [here](pricing) +- Upon purchase, you will receive an email with a license name and a license key. +- Make sure to check your **SPAM** folder if you don't receive the license within 24h. + +## Setup License from config file +The license name and key can be added directly in the app.config or web.config file in the appSettings section. + +{% include template-example.html %} +{% highlight csharp %} + + + + +{% endhighlight %} + +## Setup License from code +The license can be added directly in the code of your application. Make sure to follow recommendations about where to add this code. + +{% include template-example.html %} +{% highlight csharp %} +Z.LinqToSql.Plus.LinqToSqlManager.AddLicense([licenseName], [licenseKey]); +{% endhighlight %} + +### Recommendations +- **Web App:** Use Application_Start in global.asax to activate your license. +- **WinForm App:** Use the main thread method to activate your license. +- **Win Service:** Use the OnStart method to activate your license + +> Add the license before the first call to the library. Otherwise, the library will be enabled using the evaluation period. + +## How can I check if my license is valid? +You can use the **ValidateLicense** method to check if the current license is valid or not. + +{% include template-example.html %} +{% highlight csharp %} +// CHECK if the license if valid for the default provider (SQL Server) +string licenseErrorMessage; +if (!Z.LinqToSql.Plus.LinqToSqlManager.ValidateLicense(out licenseErrorMessage)) +{ + throw new Exception(licenseErrorMessage); +} +{% endhighlight %} diff --git a/docs/pages/tutorials/overview.md b/docs/pages/tutorials/overview.md new file mode 100644 index 0000000..33b9360 --- /dev/null +++ b/docs/pages/tutorials/overview.md @@ -0,0 +1,94 @@ +--- +permalink: overview +--- + +## Definition + +**LinqToSql Plus** is a library that dramatically improves LinqToSql performances by using bulk and batch operations. + +People using this library often report performance enhancement by 50x times and more! + +The library is installed through NuGet. Extension methods are added automatically to your DbContext. + +It easy to use, easy to customize. + +{% include template-example.html %} + +{% highlight csharp %} +// Easy to use +context.BulkInsert(list); +context.BulkUpdate(list); +context.BulkDelete(list); +context.BulkMerge(list); + +// Easy to customize +context.BulkMerge(customers, options => + options.ColumnPrimaryKeyExpression = customer => customer.Code); +{% endhighlight %} + + +## Bulk Operations Methods + +Bulk operation methods give you additional flexibility by allowing to customize options such as primary key, columns and more. + +Bulk Operations Available: + +- [BulkInsert](/bulk-insert) +- [BulkUpdate](/bulk-update) +- [BulkDelete](/bulk-delete) +- [BulkMerge](/bulk-merge) (UPSERT operation) +- [BulkSynchronize](/bulk-synchronize) + +{% include template-example.html title='Bulk Operations Examples' %} +{% highlight csharp %} +// Easy to use +context.BulkInsert(list); +context.BulkUpdate(list); +context.BulkDelete(list); +context.BulkMerge(list); + +// Easy to customize +context.BulkMerge(customers, options => + options.ColumnPrimaryKeyExpression = customer => customer.Code; }); +{% endhighlight %} + +### Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| BulkInsert | 6 ms | 10 ms | 15 ms | +| BulkUpdate | 50 ms | 55 ms | 65 ms | +| BulkDelete | 45 ms | 50 ms | 60 ms | +| BulkMerge | 65 ms | 80 ms | 110 ms | + +## Batch Operations Methods + +Batch Operations method allow to perform **UPDATE** or **DELETE** operation directly in the database using a LINQ Query without loading entities in the context. + +Everything is executed on the database side to let you get the best performance available. + +Batch Operations Available: +- [DeleteFromQuery](delete-from-query) +- [UpdateFromQuery](update-from-query) + +{% include template-example.html title='Batch Operations Examples' %} +{% highlight csharp %} +// DELETE all customers that are inactive for more than two years +context.Customers + .Where(x => x.LastLogin < DateTime.Now.AddYears(-2)) + .DeleteFromQuery(); + +// UPDATE all customers that are inactive for more than two years +context.Customers + .Where(x => x.Actif && x.LastLogin < DateTime.Now.AddYears(-2)) + .UpdateFromQuery(x => new Customer {Actif = false}); +{% endhighlight %} + +### Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| DeleteFromQuery | 1 ms | 1 ms | 1 ms | +| UpdateFromQuery | 1 ms | 1 ms | 1 ms | diff --git a/docs/pages/tutorials/requirements.md b/docs/pages/tutorials/requirements.md new file mode 100644 index 0000000..9501711 --- /dev/null +++ b/docs/pages/tutorials/requirements.md @@ -0,0 +1,11 @@ +--- +permalink: requirements +--- + +## LinqToSql +- System.Data.Linq + +## Database Provider + +- SQL Server 2008+ +- SQL Azure \ No newline at end of file diff --git a/docs/pages/tutorials/tutorial-batch-operations.md b/docs/pages/tutorials/tutorial-batch-operations.md new file mode 100644 index 0000000..b0d1240 --- /dev/null +++ b/docs/pages/tutorials/tutorial-batch-operations.md @@ -0,0 +1,40 @@ +--- +permalink: tutorial-batch-operations +--- + +## Definition +Batch Operations method allows to perform `UPDATE` or `DELETE` operations directly in the database using a LINQ Query without loading entities in the context. + +Everything is executed on the database side to let you get the best performance available. + +Batch Operations Available: +- [DeleteFromQuery](delete-from-query) +- [UpdateFromQuery](update-from-query) + +{% include template-example.html title='Batch Operations Examples' %} +{% highlight csharp %} +// DELETE all customers that are inactive for more than two years +context.Customers + .Where(x => x.LastLogin < DateTime.Now.AddYears(-2)) + .DeleteFromQuery(); + +// UPDATE all customers that are inactive for more than two years +context.Customers + .Where(x => x.Actif && x.LastLogin < DateTime.Now.AddYears(-2)) + .UpdateFromQuery(x => new Customer {Actif = false}); +{% endhighlight %} + +## Purpose +Updating or deleting data with SaveChanges requires to load data first which significantly reduces application performance. + +It also becomes kind of weird to have to load an entity after deleting it. + +Batch Operations are executed directly on the database side which provides the best performance available. + +## Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| DeleteFromQuery | 1 ms | 1 ms | 1 ms | +| UpdateFromQuery | 1 ms | 1 ms | 1 ms | \ No newline at end of file diff --git a/docs/pages/tutorials/tutorial-bulk-operations.md b/docs/pages/tutorials/tutorial-bulk-operations.md new file mode 100644 index 0000000..9b9036e --- /dev/null +++ b/docs/pages/tutorials/tutorial-bulk-operations.md @@ -0,0 +1,51 @@ +--- +permalink: tutorial-bulk-operations +--- + +## Definition +Bulk operations method gives you additional flexibility by allowing to customize options such as primary key, columns, include childs entities and more. + +They are also faster than BulkSaveChanges since they don’t use the ChangeTracker and doesn’t call the DetectChanges method. + +Bulk Operations Available: +- [BulkInsert](/bulk-insert) +- [BulkUpdate](/bulk-update) +- [BulkDelete](/bulk-delete) +- [BulkMerge](/bulk-merge) (UPSERT operation) +- [BulkSynchronize](/bulk-synchronize) + +{% include template-example.html title='Bulk Operations Examples' %} +{% highlight csharp %} +// Easy to use +context.BulkInsert(list); +context.BulkUpdate(list); +context.BulkDelete(list); +context.BulkMerge(list); + +// Easy to customize +context.BulkMerge(customers, bulk => bulk.ColumnPrimaryKeyExpression = customer => customer.Code; }); +{% endhighlight %} + +## Purpose +Using the ChangeTracker to detect and persist change automatically is great! However, almost every application has some particular scenario which requires some customization and better performance. + +By example: +- Inserting thousands of hundreds of data with child entities +- Updating only some particular fields +- Merging a list of customers using the code instead of the key + +## Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| BulkInsert | 6 ms | 10 ms | 15 ms | +| BulkUpdate | 50 ms | 55 ms | 65 ms | +| BulkDelete | 45 ms | 50 ms | 60 ms | +| BulkMerge | 65 ms | 80 ms | 110 ms | + +### Related Articles + +- [How to Benchmark?](benchmark) +- [How to use Custom Column?](custom-column) +- [How to use Custom Key?](custom-key) diff --git a/docs/pages/tutorials/tutorial-bulk-savechanges.md b/docs/pages/tutorials/tutorial-bulk-savechanges.md new file mode 100644 index 0000000..047e4db --- /dev/null +++ b/docs/pages/tutorials/tutorial-bulk-savechanges.md @@ -0,0 +1,51 @@ +--- +permalink: tutorial-bulk-savechanges +--- + +## Definition + +[BulkSaveChanges](bulk-savechanges) method is the upgraded version of `SaveChanges`. + +All changes made in the context are persisted in the database but way faster by reducing the number of database round-trip required! + +BulkSaveChanges supports everything: + +- Association (One to One, One to Many, Many to Many, etc.) +- Complex Type +- Enum +- Inheritance (TPC, TPH, TPT) +- Navigation Property +- Self-Hierarchy +- Etc. + +{% include template-example.html title='BulkSaveChanges Examples' %} +{% highlight csharp %} +context.Customers.AddRange(listToAdd); // add +context.Customers.RemoveRange(listToRemove); // remove +listToModify.ForEach(x => x.DateModified = DateTime.Now); // modify + +// Easy to use +context.BulkSaveChanges(); + +// Easy to customize +context.BulkSaveChanges(bulk => bulk.BatchSize = 100); +{% endhighlight %} + +## Purpose +Using the `ChangeTracker` to detect and persist change automatically is great! However, it leads very fast to some problem when multiples entities need to be saved. + +`SaveChanges` method makes a database round-trip for every change. So if you need to insert 10000 entities, then 10000 database round-trip will be performed which is INSANELY slow. + +`BulkSaveChanges` works exactly like `SaveChanges` but reduces the number of database round-trips required to greatly help to improve the performance. + +## Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| BulkSaveChanges | 90 ms | 150 ms | 350 ms | + +## Related Articles + +- [How to Benchmark?](benchmark) +- [How to Improve Bulk SaveChanges Performances?](improve-bulk-savechanges) diff --git a/docs/pages/tutorials/tutorial-introduction.md b/docs/pages/tutorials/tutorial-introduction.md new file mode 100644 index 0000000..f2cbf84 --- /dev/null +++ b/docs/pages/tutorials/tutorial-introduction.md @@ -0,0 +1,107 @@ +--- +permalink: tutorial-introduction +--- + +## Introduction +Entity Framework Extensions allow you to improve dramatically your save operations performance. + +It's easy to use, and easy to customize. + +## Bulk SaveChanges +The BulkSaveChanges works like SaveChanges but way faster. + +BulkSaveChanges use Bulk Operations to save all entities in the Change Tracker efficiently instead of performing a database round-trip for every entity like SaveChanges does. + +BulkSaveChanges support everything: + +- Complex Types +- Inheritance (TPC, TPH, TPT) +- Relationship (One to One, One to Many, Many to Many) + +### Example +{% include template-example.html %} +{% highlight csharp %} +var ctx = new EntitiesContext(); + +ctx.Customers.AddRange(listToAdd); // add +ctx.Customers.RemoveRange(listToRemove); // remove +listToModify.ForEach(x => x.DateModified = DateTime.Now); // modify + +// Easy to use +ctx.BulkSaveChanges(); + +// Easy to customize +context.BulkSaveChanges(bulk => bulk.BatchSize = 100); +{% endhighlight %} +### Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| BulkSaveChanges | 90 ms | 150 ms | 350 ms | + +## Bulk Operations + +Bulk Operations method provide you some flexibility by allowing some customization and performance enhancement. + +All common methods are supported: + +- BulkInsert +- BulkUpdate +- BulkDelete +- BulkMerge (UPSERT operation) +- BulkSynchronize + +### Example + +{% include template-example.html %} +{% highlight csharp %} +var ctx = new EntitiesContext(); + +// Easy to use +ctx.BulkInsert(list); +ctx.BulkUpdate(list); +ctx.BulkDelete(list); +ctx.BulkMerge(list); + +// Easy to customize +context.BulkMerge(customers, + bulk => bulk.ColumnPrimaryKeyExpression = customer => customer.Code; }); +{% endhighlight %} + +### Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| BulkInsert | 6 ms | 10 ms | 15 ms | +| BulkUpdate | 50 ms | 55 ms | 65 ms | +| BulkDelete | 45 ms | 50 ms | 60 ms | +| BulkMerge | 65 ms | 80 ms | 110 ms | + +## FromQuery Operations + +FromQuery method allows you to execute UPDATE or DELETE statements without loading entities in the context. + +### Example + +{% include template-example.html %} +{% highlight csharp %} +// DELETE all customers that are inactive for more than two years +context.Customers + .Where(x => x.LastLogin < DateTime.Now.AddYears(-2)) + .DeleteFromQuery(); + +// UPDATE all customers that are inactive for more than two years +context.Customers + .Where(x => x.Actif && x.LastLogin < DateTime.Now.AddYears(-2)) + .UpdateFromQuery(x => new Customer {Actif = false}); +{% endhighlight %} + +### Performance Comparisons + +| Operations | 1,000 Entities | 2,000 Entities | 5,000 Entities | +| :-------------- | -------------: | -------------: | -------------: | +| SaveChanges | 1,000 ms | 2,000 ms | 5,000 ms | +| DeleteFromQuery | 1 ms | 1 ms | 1 ms | +| UpdateFromQuery | 1 ms | 1 ms | 1 ms | diff --git a/docs/pages/tutorials/upgrading.md b/docs/pages/tutorials/upgrading.md new file mode 100644 index 0000000..9edac1c --- /dev/null +++ b/docs/pages/tutorials/upgrading.md @@ -0,0 +1,15 @@ +--- +permalink: upgrading +--- + +## Step 1 - Before Upgrading +Before upgrading: +- Make sure to read [release notes](https://github.com/zzzprojects/LinqToSql-Plus/releases) + +## Step 2 - NuGet Download + + + + Download + + \ No newline at end of file diff --git a/docs/robots.txt b/docs/robots.txt new file mode 100644 index 0000000..f968e0d --- /dev/null +++ b/docs/robots.txt @@ -0,0 +1,6 @@ +# www.robotstxt.org/ + +# Allow crawling of all content +User-agent: * +Disallow: +Sitemap: http://entityframework-extensions.net/sitemap.xml