mtanneryd / ef-bulk-operations Goto Github PK
View Code? Open in Web Editor NEWBulk operations for Entity Framework 6
License: Apache License 2.0
Bulk operations for Entity Framework 6
License: Apache License 2.0
If a table has an int primary key and has a large number of rows (e.g. > 100 million) then the SELECT COUNT(*) has a negative impact on performance because of the scan on the table. For me it's adding in 4-5 seconds per bulk insert.
Looking at the code it looks like the count is only used to see if there's any records in the table for setting the nextId. You could change from a "SELECT COUNT(*) FROM ...." to a "SELECT TOP 1 1 FROM ..." and then handle the null as a zero if the table doesn't have any records.
Hi @mtanneryd, thank you for the effort you put into this library. I tried the latest beta version but I could not get it work.
The relevant position of code looks like this: I'm opening a new transaction and trying to recursively insert a list of employeesTestData.
using (var transaction = employeeContext.Database.BeginTransaction()) { var insertRequest = new BulkInsertRequest<Employee> { Recursive = true, Entities = employeesTestData, Transaction = (SqlTransaction)transaction.UnderlyingTransaction }; employeeContext.BulkInsertAll(insertRequest); transaction.Commit(); }
Method call BulkInsertAll(...) throws the following 'Sequence contains no matching element' and one line later, the Commit(...) raises the 'There is already an open DataReader' exception. What am I doing wrong? I forked your code and could fix it to make it work. But I rather think I'm doing something wrong here. Thanks for your help, Thomas.
System.InvalidOperationException HResult=0x80131509 Message=Sequence contains no matching element Source=System.Core StackTrace: at System.Linq.Enumerable.Single[TSource](IEnumerable
1 source, Func2 predicate) at Tanneryd.BulkOperations.EF6.DbContextExtensions.GetMappings(DbContext ctx, Type t) at Tanneryd.BulkOperations.EF6.DbContextExtensions.DoBulkInsertAll(DbContext ctx, IList
1 entities, SqlTransaction transaction, Boolean recursive, Boolean allowNotNullSelfReferences, Dictionary2 savedEntities, BulkInsertResponse response) at Tanneryd.BulkOperations.EF6.DbContextExtensions.BulkInsertAll[T](DbContext ctx, BulkInsertRequest
1 request)
at EntityFramework.Toolkit.Tests.PerformanceTests.AddEntitiesPerformanceTest_BulkInsert(Int32 count) in C:\src\github\thomasgalliker\EntityFramework.Toolkit\ EntityFramework.Toolkit.Tests\PerformanceTests.cs:line 147
System.InvalidOperationException
HResult=0x80131509
Message=There is already an open DataReader associated with this Command which must be closed first.
Source=System.Data
StackTrace:
at System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command)
at System.Data.SqlClient.SqlInternalTransaction.Rollback()
at System.Data.SqlClient.SqlTransaction.Dispose(Boolean disposing)
at System.Data.Entity.Infrastructure.Interception.InternalDispatcher1.Dispatch[TTarget,TInterceptionContext](TTarget target, Action
2 operation, TInterceptionContext interceptionContext, Action3 executing, Action
3 executed)
at System.Data.Entity.Infrastructure.Interception.DbTransactionDispatcher.Dispose(DbTransaction transaction, DbInterceptionContext interceptionContext)
at System.Data.Entity.Core.EntityClient.EntityTransaction.Dispose(Boolean disposing)
at System.Data.Entity.DbContextTransaction.Dispose(Boolean disposing)
at System.Data.Entity.DbContextTransaction.Dispose()
at EntityFramework.Toolkit.Tests.PerformanceTests.AddEntitiesPerformanceTest_BulkInsert(Int32 count) in C:\src\github\thomasgalliker\EntityFramework.Toolkit\ EntityFramework.Toolkit.Tests\PerformanceTests.cs:line 150
`
[Timestamp]
public byte[] RowVersion { get; set; }
First of all, I like your library which seems to solve one of the major issues that exist with Entity Framework. Thanks for the effort !
I have an entity DataEntry which has a collection of DataEntryProperty entities. When I try to bulk insert the DataEntry it will indeed persist the DataEntry and corresponding DataEntryProperty entities, however the column 'DataEntry_Identifier', which is added automatically by EntityFramework, containing the FK relation from the DataEntryProperty to the DataEntry is not stored.
I tried different ways of using the BulkInsert. Also tried attaching the resulted entities within the EF context, but this did not make any difference. When debugging the implementation I was unable to see any reference to the 'DataEntry_Identifier' column being used.
When performing bulk inserts, default BulkOptions are used. For instance CheckConstraints default value is to not check.
This may result in invalid database state, for instance, by inserting invalid foreign keys.
This can be avoided by exposing an an option to disable default CheckConstraints behavihour.
Hi, I'm trying to use your library, but BulkInsertAll gives me an SqlException: Invalid syntax near ','.
I tracked the problem down to this line: https://github.com/mtanneryd/ef6-bulk-operations/blob/7ca96c682037bad9c40de83c0041abe3f8ee5005/Tanneryd.BulkOperations.EF6/Tanneryd.BulkOperations.EF6/DbContextExtensions.cs#L1769
The issue is that 1 of my tables only has a primay key. It means that columnNames is an empty string, and it generates an sql statement like this:
MERGE [dbo].[TraitTargets]
USING
(SELECT , rowno
FROM tempdb..#9ada186c0c524a4aa88daa44962c87a4) t (, rowno)
ON 1 = 0
WHEN NOT MATCHED THEN
INSERT ()
VALUES ()
OUTPUT t.rowno,
inserted.[TraitTargetId];
which is indeed invalid sql. You should probably check if nonPrimaryKeyColumnMappings
has any values.
Any chance for a quick fix?
When the select items have different property names from the entity in question it fails. The key property mapping created incorrectly uses table columns instead of entity properties.
Basically when running a Sql Profiler I saw SQL that was inserting into my UnitAmenities over and over. The main entity I am trying to insert is called Units. I also have a join table called Units_UnitAmenities. Primary keys are all Guids.
Here is the SQL that was running over and over. I was hoping the recursion would insert them all at once (bulk) like it normally does on Units without recursion.
INSERT INTO [dbo].[UnitAmenities] ([UnitAmenityId],[Name]) SELECT [UnitAmenityId],[Name] FROM tempdb..#b249e294eb5e413e8561a4faf2a3cd9f AS [t0] WHERE NOT EXISTS ( SELECT [UnitAmenityId] FROM [dbo].[UnitAmenities] AS [t1] WHERE [t0].[UnitAmenityId] = [t1].[UnitAmenityId] )
Hello,
Thank you for the great work. These helpers that you put together are really helpful.
Any plans to support database generated Guid as Primary Keys?
Or any suggestions on how to do it?
Thank you :)
Hi, thank you for your work on this project,
I built it from sources and discovered an issue.
Here in this place in DbContextExtensions.cs on line 2319 the typeMapping.EntityType is null and throws a null reference exception.
Hi @mtanneryd.
I'm get entities from entity fremwork, modify and BulkUpdateAll(). I have exception in runtime. The problem is that entity fremwork returns a collection of proxy types.
Solution: add stringin DbContextExtensions in GetMappings method on 1794 row
"t = ObjectContext.GetObjectType(t);"
Since there is no way of knowing in which order identity column values are generated when doing a bulk insert using SqlBulkCopy incorrect primary keys have been set on the entities, in memory, after insert in some situations. When doing a recursive bulk insert this also means that the foreign key relationsships will be incorrectly set in the database. In release 1.1.0-beta5 this has hopefully been fixed using a combination of temp tables and bulk copy.
Any chance of adding a .net standard target for this project (would need to change to the EF6.3 package)?
I would like to continue to use this library as we migrate to .net core 3.
More info here:
https://devblogs.microsoft.com/dotnet/announcing-ef-core-3-0-and-ef-6-3-general-availability/#what-s-new-in-ef-6-3
Figuring out a table's clustered index columns does not take the table schema into consideration so it fails if there are two tables with the same name but in different schemas.
With the release of Entity Framework 6.5, the Microsoft.Data.SqlClient provider can be through the Microsoft.EntityFramework.SqlServer package. However, wrapping EF6.5 to use the better supported SQL provider makes it incompatible with the existing Tanneryd.BulkOperations.EF6.
After completing the migration described by the Microsoft.EntityFramework.SqlServer README, Tanneryd.BulkOperations.EF6 began throwing this exception:
Message: Unable to cast object of type 'Microsoft.Data.SqlClient.SqlConnection' to type 'System.Data.SqlClient.SqlConnection'.
TARGETSITE: System.Data.SqlClient.SqlConnection GetSqlConnection(System.Data.Entity.DbContext)
STACKTRACE: at Tanneryd.BulkOperations.EF6.DbContextExtensions.GetSqlConnection(DbContext ctx)
at Tanneryd.BulkOperations.EF6.DbContextExtensions.GetClusteredIndexColumns(DbContext ctx, String schema, String tableName, SqlTransaction sqlTransaction, Mappings mappings)
at Tanneryd.BulkOperations.EF6.DbContextExtensions.BulkInsertAll[T](DbContext ctx, BulkInsertRequest`1 request)
at Tanneryd.BulkOperations.EF6.DbContextExtensions.BulkInsertAll[T](DbContext ctx, IList`1 entities, SqlTransaction transaction, Boolean recursive)
When compiling my solution I get the following error as the assembly is not signed.
CSC : error CS8002: Referenced assembly 'Tanneryd.BulkOperations.EF6, Version=1.2.3.0, Culture=neutral, PublicKeyToken=null' does not have a strong name.
Hi.
Thank you for Tanneryd.BulkOperations.EF6.
I'd like to request the ability to bulk delete records from the database.
Is this documented?
Thank you!
null values in a BulkSelectRequest will incorrectly match column default values zero and Guid.
Hello!
Thank you for a great and fast library!
Unfortunately, I have run into an issue, when using the BulkUpdate() method, it does not enforce the optimistic concurrency check.
When having the 'RowVersion' column, and in concurrent scenarios, BulkUpdate() just overwrites the changes, ignoring the fact that the same version of data was already modified by different source.
Could you help with that please?
Hello.
We are using this library for bulk insert operations in our .NET 4.7 application. We noticed that, when multiple users. So, I typed out a little application which inserts million of entries in a chunks of 4000 items, you can find it in this repo https://github.com/Hugibeer/TannerydSample
I was shocked to see how slow it is when executing bulk insert operation on multiple threads, in https://github.com/Hugibeer/TannerydSample/tree/master/Measurements you can see that, when executing this operaiton in 10 threads, execution per thread is slowed down to 235 seconds, or so. It seems there is something seriously throttling these operations.
I ran 1000 iterations on SQLBulkCopy and SQL procedur inserts, measurements with rudimentary analysis can be read here https://github.com/Hugibeer/TannerydSample/tree/master/AutomatedMeasurements
I am currently running 10 iterations of only ef6 bulk operations and will add those files to the AutomatedMeasurements folder in the repo.
Just to make things clear, this isn't "hate post", I only want to raise an attention to you to these details.
Thank you
I'm getting errors when attempting to insert into a table that contains computed columns. In this case, Shift
is a computed column.
Is there a way to 'ignore' these columns for the purpose of the insert?
Unhandled Exception: System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'Shift', table 'tempdb.dbo.#8e9dd922f00c4719b21059e9c4042ccf___________________________________________________________________________________000000000009'; column does not allow nulls. INSERT fails.
The statement has been terminated.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlBulkCopy.RunParser(BulkCopySimpleResultSet bulkCopyHandler)
at System.Data.SqlClient.SqlBulkCopy.CopyBatchesAsyncContinuedOnSuccess(BulkCopySimpleResultSet internalResults, String updateBulkCommandText, CancellationToken cts, TaskCompletionSource`1 source)
at System.Data.SqlClient.SqlBulkCopy.CopyBatchesAsyncContinued(BulkCopySimpleResultSet internalResults, String updateBulkCommandText, CancellationToken cts, TaskCompletionSource`1 source)
at System.Data.SqlClient.SqlBulkCopy.CopyBatchesAsync(BulkCopySimpleResultSet internalResults, String updateBulkCommandText, CancellationToken cts, TaskCompletionSource`1 source)
at System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalRestContinuedAsync(BulkCopySimpleResultSet internalResults, CancellationToken cts, TaskCompletionSource`1 source)
at System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalRestAsync(CancellationToken cts, TaskCompletionSource`1 source)
at System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalAsync(CancellationToken ctoken)
at System.Data.SqlClient.SqlBulkCopy.WriteRowSourceToServerAsync(Int32 columnCount, CancellationToken ctoken)
at System.Data.SqlClient.SqlBulkCopy.WriteToServer(IDataReader reader)
at Tanneryd.BulkOperations.EF6.DbContextExtensions.DoBulkCopy(DbContext ctx, IList entities, Type t, Mappings mappings, SqlTransaction transaction, Boolean allowNotNullSelfReferences, TimeSpan commandTimeout, BulkInsertResponse response)
at Tanneryd.BulkOperations.EF6.DbContextExtensions.DoBulkInsertAll(DbContext ctx, IList`1 entities, SqlTransaction transaction, Boolean recursive, Boolean allowNotNullSelfReferences, TimeSpan commandTimeout, Dictionary`2 savedEntities, BulkInsertResponse response)
at Tanneryd.BulkOperations.EF6.DbContextExtensions.BulkInsertAll[T](DbContext ctx, BulkInsertRequest`1 request)
at Tanneryd.BulkOperations.EF6.DbContextExtensions.BulkInsertAll[T](DbContext ctx, IList`1 entities, SqlTransaction transaction, Boolean recursive)
at DataMigrator.Main.Migrate() in D:\Dev\DataMigrator\Modules\Main.vb:line 47
at DataMigrator.Main.Main() in D:\Dev\DataMigrator\Modules\Main.vb:line 5
Helloy, @mtanneryd.
If I execute many BulkInsert in one table in many threads (parrallel executing BulkInsert), I have Exception("More id values generated than we had entities. Something went wrong, try again.").
It happens because the increment of the primary key (user integer) and the number of inserted records are compared, but they may differ when the insertion is parallel.
(Reference for Temporal Tables: https://docs.microsoft.com/en-us/sql/relational-databases/tables/creating-a-system-versioned-temporal-table?view=sql-server-ver15)
I utilize SQL Server Temporal Tables and my time columns have unique names different than the default SysStartTime and SysEndTime.
The error occurs when trying to update or insert to these columns which is not allowed.
I believe the solution would be to support configuring column names that need to be ignored in the "BulkUpdateAll" and "BulkInsertAll" methods.
I've been utilizing the solution below to support SQL Server Temporal Tables in EF for years.
https://stackoverflow.com/questions/40742142/entity-framework-not-working-with-temporal-table
The following Regex that you are using gives empty string:
var regex = new Regex(@"FROM (?<table>[\[\w@$#_\. \]]+) AS \[\w+\]$")
and this error is not handled.
The SQL statement generated from my code is:
SELECT [Extent1].[Id] AS [Id], [Extent1].[Identifier] AS [Identifier], [Extent1].[Name] AS [Name], [Extent1].[Latitude] AS [Latitude], [Extent1].[Longitude] AS [Longitude], [Extent1].[FIR] AS [FIR], [Extent1].[UIR] AS [UIR], [Extent1].[ICAO] AS [ICAO], [Extent1].[MagneticVariation] AS [MagneticVariation], [Extent1].[Frequency] AS [Frequency], [Extent1].[CountryName] AS [CountryName], [Extent1].[CountryId] AS [CountryId], [Extent1].[StateId] AS [StateId], [Extent1].[CityId] AS [CityId], [Extent1].[IsActive] AS [IsActive] FROM [dbo].[Points] AS [Extent1] WHERE ([Extent1].[IsActive] = @DynamicFilterParam_000001) OR (@DynamicFilterParam_000002 IS NOT NULL)
Ill generate a pull request fixing this issue and added additional exception handling, please be kind enough to merge this and release on nuget. Thanks.
File: DbContextExtensions.cs
LIne: 2201
Would it be possible to implement a method that inserts a new records if it doesn't exist based on a specified key. Essentially something like:
_context.BulkUpdateAll(new BulkUpdateRequest
{
Entities = new[] {new User {UserName = "someUserName}},
InsertIfNew = true,
KeyPropertyNames = new[] {"UserName"},
UpdatedColumnNames = new[] {"UserName"},
Transaction = null
});
Except that doesn't work, since all UpdatedColumnNames that also exist in KeyPropertyNames are filtered out. Update isn't even needed here, for every entity in the list we would only need:
IF NOT EXISTS(SELECT 1 FROM Users x where x.UserName = 'someUserName')
INSERT INTO Users(UserName) VALUES ('someUserName');
Hi,
I'm currently using BulkUpdateAll to update view with an instead of trigger.
I'm aware that this is somehow a strange usage but there's no easy workaround.
The BulkUpdateAll will try to do UPDATE t0 SET {properties} FROM to JOIN {temp table}, but due to SQLServer limitations this is not permitted for Views with instead of triggers, and throws the following error:
UPDATE is not allowed because the statement updates view "" which participates in a join and has an INSTEAD OF UPDATE trigger.
One way to solve this problem would be using a MERGE statement instead of the JOIN and maybe even enable the insertion of new elements in case of the flag InsertIfNew is enabled.
Is this something that could be done, or are there advantages in the usage of the UPDATE statement in terms of performance?
Hi,
Have you considered adding async/await support?
This line could be replaced by await bulkCopy.WriteToServerAsync(...)
?
Ran into this error using BulkSelectExisting with Tanneryd.BulkOperations.EF6/1.2.3-beta3. The table I am searching has a Guid for a Primary Key. Also I am using Database First EF6. I feel bad for finding holes in this awesome project.
System.Data.SqlClient.SqlException: Operand type clash: int is incompatible with uniqueidentifier
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
at System.Data.SqlClient.SqlDataReader.get_MetaData()
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader()
at Tanneryd.BulkOperations.EF6.DbContextExtensions.DoBulkSelectExisting[T1,T2](DbContext ctx, BulkSelectRequest`1 request)
at Tanneryd.BulkOperations.EF6.DbContextExtensions.BulkSelectExisting[T1,T2](DbContext ctx, BulkSelectRequest`1 request)
Hello!
I think I've discovered a bug when the extension is parsing out table names.. For my model, when Entity Framework builds the SQL output that the Regex parses in the GetTableName method, for some reason EF is adding an extra space in the FROM clause (between the FROM keyword and the table name), e.g:
FROM [dbo].[StagingTransactions] AS [Extent1]
When GetTableName parses this, it parses it out as " dbo.StagingTransactions" (with a leading space) and thus returns:
Schema = " dbo"
TableName = "StagingTransactions"
When this is then returned as a TableName object and parsed back into SQL, it's outputting it as [ dbo].[StagingTransactions] which then causes the Temp Table code to fail.
Currently support for this is implemented by setting the nocheck constraint on the target table, before inserting data, It would be better to handle self-referencing specifically instead. Disabling constraints is not the proper way to go but it will have to do for now.
Hi @mtanneryd, thank you for the effort you put into this library. I was importing chemical analysis in a Datawaharehouse having column name like "As" and "In" that throw error when they are not between []. There's missing [] in some function of DbContextExtensions that involve ColumnName.
Here's a version of DbContextExtensions that fixes the problem but did it very quick and didn't do many many test with it. Next time I will take the time to do a pullrequest to ease the merge job.
Hi,
Thanks for the tool. We are heavily using this as we are processing lots of data. We allow user to upload file and process 1000's of records and this tool really help us from performance wise.
While adding new table to support bulk operation, we are stumbled on below error on one of the table, which has 2 columns of datetime2(7) datatype not null. The same operation works for other table which has 3 columns of datetime2(7) data type but 2 of them are nullable.
BulkInsertAll is working fine for the table.
I have tried to re-create EDMX file but still same error.
Operand type clash: datetime2 is incompatible with int\r\nDatabase name 'tempdb' ignored, referencing object in
tempdb.\r\nDatabase name 'tempdb' ignored, referencing object in tempdb.
Getting this issue on one other table
Implicit conversion from data type datetime to int is not allowed. Use the CONVERT function to run this query.\r\nDatabase name 'tempdb' ignored, referencing object in tempdb.\r\nDatabase name 'tempdb' ignored, referencing object in tempdb.
Can you please check if this is issue or i am doing something wrong.
BulkUpdateRequest sbur = new BulkUpdateRequest();
sbur.KeyPropertyNames = keyPropertyNames;
sbur.UpdatedPropertyNames = updatePropertyNames;
sbur.InsertIfNew = true;
sbur.Entities = entities;
var sburesponse = _saasDB.BulkUpdateAll(sbur);
Thanks
Balwinder
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.