diff --git a/README.md b/README.md
index b93d2697..bbe0ed0d 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,42 @@
-# KEFCore: the EntityFrameworkCore provider for Apache Kafka
+# KEFCore: Entity Framework Core provider for Apache Kafka
-[![CI_BUILD](https://github.com/masesgroup/KEFCore/actions/workflows/build.yaml/badge.svg)](https://github.com/masesgroup/KEFCore/actions/workflows/build.yaml) [![CI_RELEASE](https://github.com/masesgroup/KEFCore/actions/workflows/release.yaml/badge.svg)](https://github.com/masesgroup/KEFCore/actions/workflows/release.yaml)
+KEFCore is the Entity Framework Core provider for Apache Kafka.
+Based on [KNet](https://github.com/masesgroup/KNet) it allows to use Apache Kafka as a distributed database.
+
+### Libraries and Tools
[![latest version](https://img.shields.io/nuget/v/MASES.EntityFrameworkCore.KNet)](https://www.nuget.org/packages/MASES.EntityFrameworkCore.KNet) [![downloads](https://img.shields.io/nuget/dt/MASES.EntityFrameworkCore.KNet)](https://www.nuget.org/packages/MASES.EntityFrameworkCore.KNet)
-KEFCore is the EntityFrameworkCore provider for Apache Kafka.
-Based on [KNet](https://github.com/masesgroup/KNet) it allows to use Apache Kafka as a distributed database.
+### Pipelines
-This project adheres to the Contributor [Covenant code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to coc_reporting@masesgroup.com.
+[![CI_BUILD](https://github.com/masesgroup/KEFCore/actions/workflows/build.yaml/badge.svg)](https://github.com/masesgroup/KEFCore/actions/workflows/build.yaml)
+[![CI_RELEASE](https://github.com/masesgroup/KEFCore/actions/workflows/release.yaml/badge.svg)](https://github.com/masesgroup/KEFCore/actions/workflows/release.yaml)
+
+---
## Scope of the project
This project aims to create a provider to access the information stored within an Apache Kafka cluster using the paradigm behind Entity Framework.
The project is based on available information within the official [EntityFrameworkCore repository](https://github.com/dotnet/efcore), many classes was copied from there as reported in the official documentation within the Microsoft website at https://docs.microsoft.com/en-us/ef/core/providers/writing-a-provider.
+### Community and Contribution
+
+Do you like the project?
+- Request your free [community subscription](https://www.jcobridge.com/pricing-25/).
+
+Do you want to help us?
+- put a :star: on this project
+- open [issues](https://github.com/masesgroup/KEFCore/issues) to request features or report bugs :bug:
+- improves the project with Pull Requests
+
+This project adheres to the Contributor [Covenant code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to coc_reporting@masesgroup.com.
+
+## Summary
+
+* [Roadmap](src/documentation/articles/roadmap.md)
+* [Actual state](src/documentation/articles/actualstate.md)
+* [KEFCore usage](src/documentation/articles/usage.md)
+
## Runtime engine
KEFCore uses [KNet](https://github.com/masesgroup/KNet), and indeed [JCOBridge](https://www.jcobridge.com) with its [features](https://www.jcobridge.com/features/), to obtain many benefits:
@@ -36,13 +59,6 @@ Have a look at the following JCOBridge resources:
- [Commercial Edition](https://www.jcobridge.com/pricing-25/)
- Latest release: [![JCOBridge nuget](https://img.shields.io/nuget/v/MASES.JCOBridge)](https://www.nuget.org/packages/MASES.JCOBridge)
----
-## Summary
-
-* [Roadmap](src/documentation/articles/roadmap.md)
-* [Actual state](src/documentation/articles/actualstate.md)
-* [KEFCore usage](src/documentation/articles/usage.md)
-
---
KAFKA is a registered trademark of The Apache Software Foundation. KEFCore has no affiliation with and is not endorsed by The Apache Software Foundation.
diff --git a/src/documentation/articles/intro.md b/src/documentation/articles/intro.md
index 941f20f2..bcb98275 100644
--- a/src/documentation/articles/intro.md
+++ b/src/documentation/articles/intro.md
@@ -1,6 +1,6 @@
# Welcome to KEFCore
-KEFCore is the EntityFrameworkCore provider for Apache Kafka.
+KEFCore is the Entity Framework Core provider for Apache Kafka.
Based on [KNet](https://github.com/masesgroup/KNet) it allows to use Apache Kafka as a distributed database.
This project adheres to the Contributor [Covenant code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to coc_reporting@masesgroup.com.
diff --git a/src/documentation/articles/roadmap.md b/src/documentation/articles/roadmap.md
index 20028ec0..c67c227e 100644
--- a/src/documentation/articles/roadmap.md
+++ b/src/documentation/articles/roadmap.md
@@ -4,3 +4,4 @@ The roadmap can be synthetized in the following points:
* Create a first working provider based on InMemory provider
* Extends the first provider with new features able to create Apache Kafka Streams topology to retrieve information
+* Use KNetCompactedReplicator beside Apache Kafka Streams
diff --git a/src/documentation/articles/usage.md b/src/documentation/articles/usage.md
index a352a11e..2009dfc5 100644
--- a/src/documentation/articles/usage.md
+++ b/src/documentation/articles/usage.md
@@ -4,7 +4,7 @@
### Installation
-EF Core for Apache Kafka is available on [NuGet](https://www.nuget.org/packages/MASES.EntityFrameworkCore.KNet):
+Entity Framework Core provider for Apache Kafka is available on [NuGet](https://www.nuget.org/packages/MASES.EntityFrameworkCore.KNet):
```sh
dotnet add package MASES.EntityFrameworkCore.KNet
@@ -12,7 +12,7 @@ dotnet add package MASES.EntityFrameworkCore.KNet
### Basic usage
-The following code demonstrates basic usage of EF Core for Apache Kafka.
+The following code demonstrates basic usage of Entity Framework Core provider for Apache Kafka.
For a full tutorial configuring the `KafkaDbContext`, defining the model, and creating the database, see [KafkaDbContext](kafkadbcontext.md) in the docs.
```cs
diff --git a/src/documentation/index.md b/src/documentation/index.md
index c2de054f..08394643 100644
--- a/src/documentation/index.md
+++ b/src/documentation/index.md
@@ -1,8 +1,8 @@
-# KEFCore: the EntityFrameworkCore provider for Apache Kafka
+# KEFCore: Entity Framework Core provider for Apache Kafka
[![CI_BUILD](https://github.com/masesgroup/KEFCore/actions/workflows/build.yaml/badge.svg)](https://github.com/masesgroup/KEFCore/actions/workflows/build.yaml) [![CI_RELEASE](https://github.com/masesgroup/KEFCore/actions/workflows/release.yaml/badge.svg)](https://github.com/masesgroup/KEFCore/actions/workflows/release.yaml)
-KEFCore is the EntityFrameworkCore provider for Apache Kafka.
+KEFCore is the Entity Framework Core provider for Apache Kafka.
Based on [KNet](https://github.com/masesgroup/KNet) it allows to use Apache Kafka as a distributed database.
This project adheres to the Contributor [Covenant code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to coc_reporting@masesgroup.com.
diff --git a/src/net/Common/Common.props b/src/net/Common/Common.props
index 927d080a..f061bd4a 100644
--- a/src/net/Common/Common.props
+++ b/src/net/Common/Common.props
@@ -4,7 +4,7 @@
MASES s.r.l.MASES s.r.l.MASES s.r.l.
- 0.7.2.0
+ 0.8.0.0net6.0latesttrue
diff --git a/src/net/KEFCore/Infrastructure/Internal/IKafkaSingletonOptions.cs b/src/net/KEFCore/Infrastructure/Internal/IKafkaSingletonOptions.cs
index 33b56157..d10ac5b8 100644
--- a/src/net/KEFCore/Infrastructure/Internal/IKafkaSingletonOptions.cs
+++ b/src/net/KEFCore/Infrastructure/Internal/IKafkaSingletonOptions.cs
@@ -34,7 +34,7 @@ public interface IKafkaSingletonOptions : ISingletonOptions
string? BootstrapServers { get; }
- bool ProducerByEntity { get; }
+ //bool ProducerByEntity { get; }
bool UseCompactedReplicator { get; }
diff --git a/src/net/KEFCore/Infrastructure/Internal/KafkaOptionsExtension.cs b/src/net/KEFCore/Infrastructure/Internal/KafkaOptionsExtension.cs
index ca3ece5a..5d0d9e31 100644
--- a/src/net/KEFCore/Infrastructure/Internal/KafkaOptionsExtension.cs
+++ b/src/net/KEFCore/Infrastructure/Internal/KafkaOptionsExtension.cs
@@ -36,7 +36,7 @@ public class KafkaOptionsExtension : IDbContextOptionsExtension
private string? _databaseName;
private string? _applicationId;
private string? _bootstrapServers;
- private bool _producerByEntity = false;
+ //private bool _producerByEntity = false;
private bool _useCompactedReplicator = false;
private bool _usePersistentStorage = false;
private int _defaultNumPartitions = 1;
@@ -60,7 +60,7 @@ protected KafkaOptionsExtension(KafkaOptionsExtension copyFrom)
_databaseName = copyFrom._databaseName;
_applicationId = copyFrom._applicationId;
_bootstrapServers = copyFrom._bootstrapServers;
- _producerByEntity = copyFrom._producerByEntity;
+ //_producerByEntity = copyFrom._producerByEntity;
_useCompactedReplicator = copyFrom._useCompactedReplicator;
_usePersistentStorage = copyFrom._usePersistentStorage;
_defaultNumPartitions = copyFrom._defaultNumPartitions;
@@ -85,7 +85,7 @@ protected KafkaOptionsExtension(KafkaOptionsExtension copyFrom)
public virtual string BootstrapServers => _bootstrapServers!;
- public virtual bool ProducerByEntity => _producerByEntity;
+ //public virtual bool ProducerByEntity => _producerByEntity;
public virtual bool UseCompactedReplicator => _useCompactedReplicator;
@@ -139,14 +139,14 @@ public virtual KafkaOptionsExtension WithBootstrapServers(string bootstrapServer
return clone;
}
- public virtual KafkaOptionsExtension WithProducerByEntity(bool producerByEntity = false)
- {
- var clone = Clone();
+ //public virtual KafkaOptionsExtension WithProducerByEntity(bool producerByEntity = false)
+ //{
+ // var clone = Clone();
- clone._producerByEntity = producerByEntity;
+ // clone._producerByEntity = producerByEntity;
- return clone;
- }
+ // return clone;
+ //}
public virtual KafkaOptionsExtension WithCompactedReplicator(bool useCompactedReplicator = false)
{
@@ -242,7 +242,7 @@ public virtual Properties StreamsOptions(string applicationId)
{
props.Remove(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG);
}
- props.Put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Class.ForName("org.apache.kafka.common.serialization.Serdes$StringSerde", true, SystemClassLoader));
+ props.Put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Class.ForName("org.apache.kafka.common.serialization.Serdes$ByteArraySerde", true, SystemClassLoader));
if (props.ContainsKey(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG))
{
props.Remove(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG);
@@ -277,16 +277,16 @@ public virtual Properties ProducerOptions()
{
props.Put(ProducerConfig.LINGER_MS_CONFIG, 1);
}
- if (props.ContainsKey(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG))
- {
- props.Remove(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG);
- }
- props.Put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, Class.ForName("org.apache.kafka.common.serialization.StringSerializer", true, SystemClassLoader));
- if (props.ContainsKey(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG))
- {
- props.Remove(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG);
- }
- props.Put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, Class.ForName("org.apache.kafka.common.serialization.StringSerializer", true, SystemClassLoader));
+ //if (props.ContainsKey(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG))
+ //{
+ // props.Remove(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG);
+ //}
+ //props.Put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, Class.ForName("org.apache.kafka.common.serialization.StringSerializer", true, SystemClassLoader));
+ //if (props.ContainsKey(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG))
+ //{
+ // props.Remove(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG);
+ //}
+ //props.Put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, Class.ForName("org.apache.kafka.common.serialization.StringSerializer", true, SystemClassLoader));
return props;
}
diff --git a/src/net/KEFCore/Infrastructure/Internal/KafkaSingletonOptions.cs b/src/net/KEFCore/Infrastructure/Internal/KafkaSingletonOptions.cs
index ced2c8b6..ffae2fd6 100644
--- a/src/net/KEFCore/Infrastructure/Internal/KafkaSingletonOptions.cs
+++ b/src/net/KEFCore/Infrastructure/Internal/KafkaSingletonOptions.cs
@@ -34,7 +34,7 @@ public virtual void Initialize(IDbContextOptions options)
DatabaseName = kafkaOptions.DatabaseName;
ApplicationId = kafkaOptions.ApplicationId;
BootstrapServers = kafkaOptions.BootstrapServers;
- ProducerByEntity = kafkaOptions.ProducerByEntity;
+ //ProducerByEntity = kafkaOptions.ProducerByEntity;
UseCompactedReplicator = kafkaOptions.UseCompactedReplicator;
UsePersistentStorage = kafkaOptions.UsePersistentStorage;
DefaultNumPartitions = kafkaOptions.DefaultNumPartitions;
diff --git a/src/net/KEFCore/Infrastructure/KafkaDbContext.cs b/src/net/KEFCore/Infrastructure/KafkaDbContext.cs
index 7972863d..cdfd20d9 100644
--- a/src/net/KEFCore/Infrastructure/KafkaDbContext.cs
+++ b/src/net/KEFCore/Infrastructure/KafkaDbContext.cs
@@ -70,10 +70,10 @@ public KafkaDbContext(DbContextOptions options) : base(options)
/// Use persistent storage
///
public virtual bool UsePersistentStorage { get; set; } = false;
- ///
- /// Use a producer for each Entity
- ///
- public bool UseProducerByEntity { get; set; } = false;
+ /////
+ ///// Use a producer for each Entity
+ /////
+ //public bool UseProducerByEntity { get; set; } = false;
///
/// Use instead of Apache Kafka Streams
///
@@ -104,7 +104,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
o.StreamsConfig(StreamsConfigBuilder ?? o.EmptyStreamsConfigBuilder).WithDefaultNumPartitions(DefaultNumPartitions);
o.WithUsePersistentStorage(UsePersistentStorage);
- o.WithProducerByEntity(UseProducerByEntity);
+ //o.WithProducerByEntity(UseProducerByEntity);
o.WithCompactedReplicator(UseCompactedReplicator);
o.WithDefaultReplicationFactor(DefaultReplicationFactor);
});
diff --git a/src/net/KEFCore/Infrastructure/KafkaDbContextOptionsBuilder.cs b/src/net/KEFCore/Infrastructure/KafkaDbContextOptionsBuilder.cs
index 7271b5a3..0b43f008 100644
--- a/src/net/KEFCore/Infrastructure/KafkaDbContextOptionsBuilder.cs
+++ b/src/net/KEFCore/Infrastructure/KafkaDbContextOptionsBuilder.cs
@@ -93,26 +93,26 @@ public virtual KafkaDbContextOptionsBuilder WithUseNameMatching(bool useNameMatc
return this;
}
- ///
- /// Enables creation of producer for each
- ///
- ///
- /// See Using DbContextOptions, and
- /// The EF Core Kafka database provider for more information and examples.
- ///
- /// If , then each entity will have its own .
- /// The same builder instance so that multiple calls can be chained.
- public virtual KafkaDbContextOptionsBuilder WithProducerByEntity(bool producerByEntity = false)
- {
- var extension = OptionsBuilder.Options.FindExtension()
- ?? new KafkaOptionsExtension();
-
- extension = extension.WithProducerByEntity(producerByEntity);
-
- ((IDbContextOptionsBuilderInfrastructure)OptionsBuilder).AddOrUpdateExtension(extension);
-
- return this;
- }
+ /////
+ ///// Enables creation of producer for each
+ /////
+ /////
+ ///// See Using DbContextOptions, and
+ ///// The EF Core Kafka database provider for more information and examples.
+ /////
+ ///// If , then each entity will have its own .
+ ///// The same builder instance so that multiple calls can be chained.
+ //public virtual KafkaDbContextOptionsBuilder WithProducerByEntity(bool producerByEntity = false)
+ //{
+ // var extension = OptionsBuilder.Options.FindExtension()
+ // ?? new KafkaOptionsExtension();
+
+ // extension = extension.WithProducerByEntity(producerByEntity);
+
+ // ((IDbContextOptionsBuilderInfrastructure)OptionsBuilder).AddOrUpdateExtension(extension);
+
+ // return this;
+ //}
///
/// Enables use of
diff --git a/src/net/KEFCore/KEFCore.csproj b/src/net/KEFCore/KEFCore.csproj
index ce0f6f01..ff1d0029 100644
--- a/src/net/KEFCore/KEFCore.csproj
+++ b/src/net/KEFCore/KEFCore.csproj
@@ -70,6 +70,7 @@
AllNone
+
diff --git a/src/net/KEFCore/Storage/Internal/EntityTypeProducer.cs b/src/net/KEFCore/Storage/Internal/EntityTypeProducer.cs
new file mode 100644
index 00000000..2b8a84bc
--- /dev/null
+++ b/src/net/KEFCore/Storage/Internal/EntityTypeProducer.cs
@@ -0,0 +1,284 @@
+/*
+* Copyright 2022 MASES s.r.l.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* Refer to LICENSE for more information.
+*/
+
+#nullable enable
+
+using Java.Util.Concurrent;
+using MASES.EntityFrameworkCore.KNet.Serdes.Internal;
+using MASES.KNet.Producer;
+using MASES.KNet.Replicator;
+using MASES.KNet.Serialization;
+using System.Collections.Concurrent;
+using System.Text.Json.Serialization;
+using MASES.KNet.Serialization.Json;
+using Org.Apache.Kafka.Clients.Producer;
+using System.Text.Json;
+using Javax.Xml.Crypto;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace MASES.EntityFrameworkCore.KNet.Storage.Internal;
+
+public class EntityTypeProducers
+{
+ static IEntityTypeProducer? _globalProducer = null;
+ static readonly ConcurrentDictionary _producers = new ConcurrentDictionary();
+
+ public static IEntityTypeProducer Create(IEntityType entityType, IKafkaCluster cluster) where TKey : notnull
+ {
+ //if (!cluster.Options.ProducerByEntity)
+ //{
+ // lock (_producers)
+ // {
+ // if (_globalProducer == null) _globalProducer = CreateProducerLocal(entityType, cluster);
+ // return _globalProducer;
+ // }
+ //}
+ //else
+ //{
+ return _producers.GetOrAdd(entityType, _ => CreateProducerLocal(entityType, cluster));
+ //}
+ }
+
+ static IEntityTypeProducer CreateProducerLocal(IEntityType entityType, IKafkaCluster cluster) where TKey : notnull => new EntityTypeProducer(entityType, cluster);
+}
+
+[JsonSerializable(typeof(ObjectType))]
+public class ObjectType : IJsonOnDeserialized
+{
+ public ObjectType()
+ {
+
+ }
+
+ public ObjectType(IProperty typeName, object value)
+ {
+ TypeName = typeName.ClrType?.FullName;
+ Value = value;
+ }
+
+ public void OnDeserialized()
+ {
+ if (Value is JsonElement elem)
+ {
+ switch (elem.ValueKind)
+ {
+ case JsonValueKind.Undefined:
+ break;
+ case JsonValueKind.Object:
+ break;
+ case JsonValueKind.Array:
+ break;
+ case JsonValueKind.String:
+ Value = elem.GetString()!;
+ break;
+ case JsonValueKind.Number:
+ var tmp = elem.GetInt64();
+ Value = Convert.ChangeType(tmp, Type.GetType(TypeName!)!);
+ break;
+ case JsonValueKind.True:
+ Value = true;
+ break;
+ case JsonValueKind.False:
+ Value = false;
+ break;
+ case JsonValueKind.Null:
+ Value = null;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ Value = Convert.ChangeType(Value, Type.GetType(TypeName!)!);
+ }
+ }
+
+ public string? TypeName { get; set; }
+
+ public object Value { get; set; }
+}
+
+[JsonSerializable(typeof(KNetEntityTypeData<>))]
+public class KNetEntityTypeData
+{
+ public KNetEntityTypeData() { }
+
+ public KNetEntityTypeData(IEntityType tName, IProperty[] properties, object[] rData)
+ {
+ TypeName = tName.Name;
+ Data = new Dictionary();
+ for (int i = 0; i < properties.Length; i++)
+ {
+ Data.Add(properties[i].GetIndex(), new ObjectType(properties[i], rData[i]));
+ }
+ }
+
+ public string TypeName { get; set; }
+ // [JsonConverter(typeof(ListStringObjectTupleConverter))]
+ public Dictionary Data { get; set; }
+
+ public object[] GetData(IEntityType tName)
+ {
+ if (Data == null) return null;
+
+ var array = Data.Select((o) => o.Value.Value).ToArray();
+
+ return array;
+
+ var _properties = tName.GetProperties().ToArray();
+ List