DapperTransaction güncellemesi

Hatalar vermeye başladı. Listelerdeki veriler yüklenmeden yeni butonuna basınca hata aldım.
This commit is contained in:
Sedat Öztürk 2025-11-06 23:33:22 +03:00
parent 5e8ca56af1
commit 01db1c6b23
13 changed files with 513 additions and 291 deletions

View file

@ -1,6 +1,6 @@
{
"ConnectionStrings": {
"SqlServer": "Server=sql;Database=Erp;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;Encrypt=False;TrustServerCertificate=True;Connection Timeout=60;MultipleActiveResultSets=true;",
"SqlServer": "Server=sql;Database=Erp;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;Encrypt=False;TrustServerCertificate=True;Connection Timeout=60;",
"PostgreSql": "User ID=sa;Password=NvQp8s@l;Host=postgres;Port=5432;Database=Erp;"
},
"Redis": {

View file

@ -1,6 +1,6 @@
{
"ConnectionStrings": {
"SqlServer": "Server=sql;Database=Erp;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;Encrypt=False;TrustServerCertificate=True;Connection Timeout=60;MultipleActiveResultSets=true;",
"SqlServer": "Server=sql;Database=Erp;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;Encrypt=False;TrustServerCertificate=True;Connection Timeout=60;",
"PostgreSql": "User ID=sa;Password=NvQp8s@l;Host=postgres;Port=5432;Database=Erp;"
},
"Redis": {

View file

@ -1,7 +1,7 @@
{
"Seed": false,
"ConnectionStrings": {
"SqlServer": "Server=localhost;Database=Erp;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;Encrypt=False;TrustServerCertificate=True;Connection Timeout=60;MultipleActiveResultSets=true;",
"SqlServer": "Server=localhost;Database=Erp;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;Encrypt=False;TrustServerCertificate=True;Connection Timeout=60;",
"PostgreSql": "User ID=sa;Password=NvQp8s@l;Host=localhost;Port=5432;Database=Erp;"
},
"Redis": {

View file

@ -1,4 +1,5 @@
using System.Data;
using System;
using System.Data;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
@ -25,43 +26,24 @@ public class DapperTransactionApi : ITransactionApi, ISupportsRollback
public async Task CommitAsync(CancellationToken cancellationToken = default)
{
// Check if transaction is still active
if (_isCompleted)
{
return; // Already completed, nothing to do
return;
}
// Check if connection is still open and transaction is not disposed
if (DbTransaction?.Connection == null || DbTransaction.Connection.State != ConnectionState.Open)
{
_isCompleted = true;
return; // Connection closed or transaction disposed
return;
}
try
{
await DbTransaction.CommitAsync(CancellationTokenProvider.FallbackToProvider(cancellationToken));
_isCompleted = true;
}
catch (System.InvalidOperationException)
catch (InvalidOperationException)
{
// Transaction already completed or disposed
_isCompleted = true;
}
}
public void Dispose()
{
if (!_isCompleted && DbTransaction?.Connection != null)
{
try
{
// If not completed, rollback before disposing
DbTransaction?.Rollback();
}
catch
{
// Ignore rollback errors during disposal
}
finally
{
@ -69,33 +51,51 @@ public class DapperTransactionApi : ITransactionApi, ISupportsRollback
}
}
DbTransaction?.Dispose();
}
public async Task RollbackAsync(CancellationToken cancellationToken)
public async Task RollbackAsync(CancellationToken cancellationToken = default)
{
// Check if transaction is still active
if (_isCompleted)
{
return; // Already completed, nothing to do
return;
}
// Check if connection is still open and transaction is not disposed
if (DbTransaction?.Connection == null || DbTransaction.Connection.State != ConnectionState.Open)
{
_isCompleted = true;
return; // Connection closed or transaction disposed
return;
}
try
{
await DbTransaction.RollbackAsync(CancellationTokenProvider.FallbackToProvider(cancellationToken));
_isCompleted = true;
}
catch (System.InvalidOperationException)
catch (InvalidOperationException)
{
// Transaction already completed or disposed
}
finally
{
_isCompleted = true;
}
}
public void Dispose()
{
try
{
if (!_isCompleted && DbTransaction?.Connection?.State == ConnectionState.Open)
{
// UoW commit/rollback çağırmadıysa, dispose sırasında rollback dene
DbTransaction.Rollback();
}
}
catch
{
// Rollback sırasında hata olursa yut
}
finally
{
_isCompleted = true;
DbTransaction?.Dispose();
}
}
}

View file

@ -15,118 +15,55 @@ namespace Kurs.Platform.Domain.DynamicData;
[ExposeKeyedService<IDynamicDataRepository>("Ms")]
public class MsDynamicDataRepository : IDynamicDataRepository, IScopedDependency, IUnitOfWorkEnabled, IDisposable
{
private readonly IUnitOfWorkManager unitOfWorkManager;
private readonly ICancellationTokenProvider cancellationTokenProvider;
private readonly Dictionary<string, DbTransaction> transactions;
private readonly Dictionary<string, SqlConnection> connections;
private readonly HashSet<string> registeredTransactions; // Track registered transactions
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly ICancellationTokenProvider _cancellationTokenProvider;
private readonly Dictionary<string, DbTransaction> _transactions;
private readonly Dictionary<string, SqlConnection> _connections;
private readonly HashSet<string> _registeredTransactions;
private readonly HashSet<string> _registeredConnections;
private readonly object _lock = new object();
public bool IsDisposed { get; private set; }
public MsDynamicDataRepository(
IUnitOfWorkManager unitOfWorkManager,
ICancellationTokenProvider cancellationTokenProvider)
{
this.unitOfWorkManager = unitOfWorkManager;
this.cancellationTokenProvider = cancellationTokenProvider;
transactions = new Dictionary<string, DbTransaction>();
connections = new Dictionary<string, SqlConnection>();
registeredTransactions = new HashSet<string>();
_unitOfWorkManager = unitOfWorkManager;
_cancellationTokenProvider = cancellationTokenProvider;
_transactions = [];
_connections = [];
_registeredTransactions = [];
_registeredConnections = [];
}
private async Task<DbTransaction> GetOrCreateTransactionAsync(SqlConnection con)
private string BuildKey(string cs)
{
var key = $"Dapper_{con.ConnectionString}";
lock (_lock)
{
// Check if we have a valid transaction for this connection
if (transactions.TryGetValue(key, out var transaction))
{
// Validate transaction is still usable
if (transaction?.Connection != null &&
transaction.Connection == con &&
transaction.Connection.State == ConnectionState.Open)
{
return transaction;
}
// Invalid transaction, remove it
try { transaction?.Dispose(); } catch { }
transactions.Remove(key);
}
}
// Ensure connection is open
if (con.State != ConnectionState.Open)
{
await con.OpenAsync();
}
// Create new transaction
var newTransaction = await con.BeginTransactionAsync();
bool shouldRegister = false;
lock (_lock)
{
transactions[key] = newTransaction;
// Only register with UnitOfWork once per transaction key
if (!registeredTransactions.Contains(key))
{
registeredTransactions.Add(key);
shouldRegister = true;
}
}
// Register with UnitOfWork if available and not already registered
if (shouldRegister && unitOfWorkManager.Current != null)
{
unitOfWorkManager.Current.AddTransactionApi(key, new DapperTransactionApi(newTransaction, cancellationTokenProvider));
unitOfWorkManager.Current.OnCompleted(() =>
{
lock (_lock)
{
transactions.Remove(key);
registeredTransactions.Remove(key);
}
return Task.CompletedTask;
});
}
return newTransaction;
var uowId = _unitOfWorkManager.Current?.GetHashCode() ?? 0;
return $"Dapper_{uowId}_{cs}";
}
private async Task<SqlConnection> GetOrCreateConnectionAsync(string cs)
{
var key = BuildKey(cs);
SqlConnection connection;
var key = $"Dapper_{cs}";
lock (_lock)
{
// Check if we have an existing connection
if (connections.TryGetValue(key, out connection))
if (_connections.TryGetValue(key, out connection))
{
// Connection exists, check its state
if (connection.State == ConnectionState.Open)
{
return connection;
}
// Connection is not open, will handle outside lock
// varsa aynı connection'ı kullan
}
else
{
// Create new connection
connection = new SqlConnection(cs);
connections[key] = connection;
_connections[key] = connection;
}
}
// Handle connection state outside of lock
try
{
// Lock dışında state yönetimi
if (connection.State == ConnectionState.Broken)
{
connection.Close();
@ -134,37 +71,29 @@ public class MsDynamicDataRepository : IDynamicDataRepository, IScopedDependency
if (connection.State == ConnectionState.Closed)
{
await connection.OpenAsync();
}
}
catch
{
// If connection failed, create a new one
lock (_lock)
{
connections.Remove(key);
await connection.OpenAsync(_cancellationTokenProvider.FallbackToProvider(default));
}
connection = new SqlConnection(cs);
// UoW tamamlandığında connection'ı kapatmak için tek seferlik kayıt
if (_unitOfWorkManager.Current != null)
{
lock (_lock)
{
connections[key] = connection;
}
await connection.OpenAsync();
}
// Register cleanup on UnitOfWork completion (only once)
if (unitOfWorkManager.Current != null)
if (!_registeredConnections.Contains(key))
{
unitOfWorkManager.Current.OnCompleted(async () =>
_registeredConnections.Add(key);
_unitOfWorkManager.Current.OnCompleted(async () =>
{
SqlConnection conn = null;
lock (_lock)
{
if (connections.TryGetValue(key, out conn))
if (_connections.TryGetValue(key, out conn))
{
connections.Remove(key);
_connections.Remove(key);
}
_registeredConnections.Remove(key);
}
if (conn != null)
@ -177,27 +106,92 @@ public class MsDynamicDataRepository : IDynamicDataRepository, IScopedDependency
}
conn.Dispose();
}
catch { }
catch
{
// ignore
}
}
});
}
}
}
return connection;
}
private async Task<DbTransaction> GetOrCreateTransactionAsync(SqlConnection con, string cs)
{
var key = BuildKey(cs);
lock (_lock)
{
if (_transactions.TryGetValue(key, out var existing))
{
if (existing?.Connection != null &&
existing.Connection == con &&
existing.Connection.State == ConnectionState.Open)
{
return existing;
}
try { existing?.Dispose(); } catch { }
_transactions.Remove(key);
}
}
var newTransaction = await con.BeginTransactionAsync(_cancellationTokenProvider.FallbackToProvider(default));
bool shouldRegister = false;
lock (_lock)
{
_transactions[key] = newTransaction;
if (!_registeredTransactions.Contains(key))
{
_registeredTransactions.Add(key);
shouldRegister = true;
}
}
if (shouldRegister && _unitOfWorkManager.Current != null)
{
_unitOfWorkManager.Current.AddTransactionApi(
key,
new DapperTransactionApi(newTransaction, _cancellationTokenProvider)
);
_unitOfWorkManager.Current.OnCompleted(() =>
{
lock (_lock)
{
_transactions.Remove(key);
_registeredTransactions.Remove(key);
}
return Task.CompletedTask;
});
}
return newTransaction;
}
// ------------------ Dapper metotları ------------------
public virtual async Task<List<T>> QueryAsync<T>(string sql, string cs, Dictionary<string, object> parameters = null)
{
var param = new DynamicParameters(parameters);
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
return (await dbConnection.QueryAsync<T>(sql, param, transaction)).AsList();
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
var result = await dbConnection.QueryAsync<T>(sql, param, transaction);
return result.AsList(); // buffered => reader kapanır, MARS gerekmez
}
public virtual async Task<IEnumerable<dynamic>> QueryAsync(string sql, string cs, Dictionary<string, object> parameters = null)
{
var param = new DynamicParameters(parameters);
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
return await dbConnection.QueryAsync(sql, param, transaction);
}
@ -205,7 +199,8 @@ public class MsDynamicDataRepository : IDynamicDataRepository, IScopedDependency
{
var param = new DynamicParameters(parameters);
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
return await dbConnection.QuerySingleAsync<T>(sql, param, transaction);
}
@ -213,25 +208,30 @@ public class MsDynamicDataRepository : IDynamicDataRepository, IScopedDependency
{
var param = new DynamicParameters(parameters);
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
return await dbConnection.ExecuteScalarAsync<T>(sql, param, transaction);
}
public virtual async Task<T> GetSingleField<T>(string cs, string tableName, string id, string selectFieldName, string idFieldName = "Id")
{
var param = new { ID = id };
string sql = $"select {selectFieldName} from {tableName} where {idFieldName} = @ID ";
var sql = $"select {selectFieldName} from {tableName} where {idFieldName} = @ID ";
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
return await dbConnection.QueryFirstAsync<T>(sql, param, transaction);
}
public virtual async Task<int> UpdateField(string cs, string tableName, string id, string updateFieldName, string value, string idFieldName = "Id")
{
var param = new { ID = id };
string sql = $"update {tableName} set {updateFieldName} = '{value}' where Id = @ID ";
var sql = $"update {tableName} set {updateFieldName} = '{value}' where {idFieldName} = @ID ";
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
return await dbConnection.ExecuteAsync(sql, param, transaction);
}
@ -239,10 +239,13 @@ public class MsDynamicDataRepository : IDynamicDataRepository, IScopedDependency
{
var param = new DynamicParameters(parameters);
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
return await dbConnection.ExecuteAsync(sql, param, transaction);
}
// ------------------ Dispose ------------------
public void Dispose()
{
Dispose(true);
@ -251,49 +254,42 @@ public class MsDynamicDataRepository : IDynamicDataRepository, IScopedDependency
private void Dispose(bool disposing)
{
if (!IsDisposed)
if (IsDisposed)
{
return;
}
if (disposing)
{
lock (_lock)
{
// Dispose transactions first
foreach (var transaction in transactions.Values)
foreach (var tx in _transactions.Values)
{
try
{
transaction?.Dispose();
try { tx?.Dispose(); } catch { }
}
catch
{
// Ignore disposal errors
}
}
transactions.Clear();
_transactions.Clear();
_registeredTransactions.Clear();
// Then dispose connections
foreach (var connection in connections.Values)
foreach (var conn in _connections.Values)
{
try
{
if (connection != null)
if (conn != null)
{
if (connection.State == ConnectionState.Open)
if (conn.State != ConnectionState.Closed)
{
connection.Close();
conn.Close();
}
connection.Dispose();
conn.Dispose();
}
}
catch
{
// Ignore disposal errors
}
}
connections.Clear();
catch { }
}
_connections.Clear();
_registeredConnections.Clear();
}
}
IsDisposed = true;
}
}
}

View file

@ -15,69 +15,130 @@ namespace Kurs.Platform.Domain.DynamicData;
[ExposeKeyedService<IDynamicDataRepository>("Pg")]
public class PgDynamicDataRepository : IDynamicDataRepository, IScopedDependency, IUnitOfWorkEnabled, IDisposable
{
private readonly IUnitOfWorkManager unitOfWorkManager;
private readonly ICancellationTokenProvider cancellationTokenProvider;
private Dictionary<string, DbTransaction> transactions;
private Dictionary<string, NpgsqlConnection> connections;
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly ICancellationTokenProvider _cancellationTokenProvider;
private readonly Dictionary<string, DbTransaction> _transactions;
private readonly Dictionary<string, NpgsqlConnection> _connections;
public bool IsDisposed { get; private set; }
public PgDynamicDataRepository(
IUnitOfWorkManager unitOfWorkManager,
ICancellationTokenProvider cancellationTokenProvider)
{
this.unitOfWorkManager = unitOfWorkManager;
this.cancellationTokenProvider = cancellationTokenProvider;
transactions = [];
connections = [];
_unitOfWorkManager = unitOfWorkManager;
_cancellationTokenProvider = cancellationTokenProvider;
_transactions = [];
_connections = [];
}
private async Task<DbTransaction> GetOrCreateTransactionAsync(NpgsqlConnection con)
private string BuildKey(string cs)
{
var key = $"Dapper_{con.ConnectionString}";
var transaction = transactions.GetOrDefault(key);
if (transaction == null || transaction.Connection == null)
{
transaction = await con.BeginTransactionAsync();
unitOfWorkManager.Current.AddTransactionApi(key, new DapperTransactionApi(transaction, cancellationTokenProvider));
transactions.Add(key, transaction);
unitOfWorkManager.Current.OnCompleted(() =>
{
transaction = null;
return Task.CompletedTask;
});
}
return transaction;
var uowId = _unitOfWorkManager.Current?.GetHashCode() ?? 0;
return $"Dapper_{uowId}_{cs}";
}
private async Task<NpgsqlConnection> GetOrCreateConnectionAsync(string cs)
{
var key = $"Dapper_{cs}";
var connection = connections.GetOrDefault(key);
if (connection == null)
var key = BuildKey(cs);
if (!_connections.TryGetValue(key, out var connection))
{
connection = new NpgsqlConnection(cs);
connections.Add(key, connection);
_connections[key] = connection;
}
if (connection.State == ConnectionState.Broken)
{
connection.Close();
}
if (connection.State != ConnectionState.Open)
{
await connection.OpenAsync();
await connection.OpenAsync(_cancellationTokenProvider.FallbackToProvider(default));
}
if (_unitOfWorkManager.Current != null)
{
_unitOfWorkManager.Current.OnCompleted(async () =>
{
if (_connections.TryGetValue(key, out var conn))
{
_connections.Remove(key);
try
{
if (conn.State != ConnectionState.Closed)
{
await conn.CloseAsync();
}
conn.Dispose();
}
catch
{
// ignore
}
}
});
}
return connection;
}
private async Task<DbTransaction> GetOrCreateTransactionAsync(NpgsqlConnection con, string cs)
{
var key = BuildKey(cs);
if (_transactions.TryGetValue(key, out var tx))
{
if (tx?.Connection != null &&
tx.Connection == con &&
tx.Connection.State == ConnectionState.Open)
{
return tx;
}
try { tx?.Dispose(); } catch { }
_transactions.Remove(key);
}
var newTx = await con.BeginTransactionAsync(_cancellationTokenProvider.FallbackToProvider(default));
_transactions[key] = newTx;
if (_unitOfWorkManager.Current != null)
{
_unitOfWorkManager.Current.AddTransactionApi(
key,
new DapperTransactionApi(newTx, _cancellationTokenProvider)
);
_unitOfWorkManager.Current.OnCompleted(() =>
{
_transactions.Remove(key);
return Task.CompletedTask;
});
}
return newTx;
}
// ------------------ Dapper metotları ------------------
public virtual async Task<List<T>> QueryAsync<T>(string sql, string cs, Dictionary<string, object> parameters = null)
{
var param = new DynamicParameters(parameters);
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
return (await dbConnection.QueryAsync<T>(sql, param, transaction)).AsList();
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
var result = await dbConnection.QueryAsync<T>(sql, param, transaction);
return result.AsList();
}
public virtual async Task<IEnumerable<dynamic>> QueryAsync(string sql, string cs, Dictionary<string, object> parameters = null)
{
var param = new DynamicParameters(parameters);
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
return await dbConnection.QueryAsync(sql, param, transaction);
}
@ -85,7 +146,8 @@ public class PgDynamicDataRepository : IDynamicDataRepository, IScopedDependency
{
var param = new DynamicParameters(parameters);
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
return await dbConnection.QuerySingleAsync<T>(sql, param, transaction);
}
@ -93,25 +155,30 @@ public class PgDynamicDataRepository : IDynamicDataRepository, IScopedDependency
{
var param = new DynamicParameters(parameters);
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
return await dbConnection.ExecuteScalarAsync<T>(sql, param, transaction);
}
public virtual async Task<T> GetSingleField<T>(string cs, string tableName, string id, string selectFieldName, string idFieldName = "Id")
{
var param = new { ID = id };
string sql = $"select {selectFieldName} from {tableName} where {idFieldName} = @ID ";
var sql = $"select {selectFieldName} from {tableName} where {idFieldName} = @ID ";
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
return await dbConnection.QueryFirstAsync<T>(sql, param, transaction);
}
public virtual async Task<int> UpdateField(string cs, string tableName, string id, string updateFieldName, string value, string idFieldName = "Id")
{
var param = new { ID = id };
string sql = $"update {tableName} set {updateFieldName} = '{value}' where Id = @ID ";
var sql = $"update {tableName} set {updateFieldName} = '{value}' where {idFieldName} = @ID ";
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
return await dbConnection.ExecuteAsync(sql, param, transaction);
}
@ -119,10 +186,13 @@ public class PgDynamicDataRepository : IDynamicDataRepository, IScopedDependency
{
var param = new DynamicParameters(parameters);
var dbConnection = await GetOrCreateConnectionAsync(cs);
var transaction = await GetOrCreateTransactionAsync(dbConnection);
var transaction = await GetOrCreateTransactionAsync(dbConnection, cs);
return await dbConnection.ExecuteAsync(sql, param, transaction);
}
// ------------------ Dispose ------------------
public void Dispose()
{
Dispose(true);
@ -131,23 +201,40 @@ public class PgDynamicDataRepository : IDynamicDataRepository, IScopedDependency
private void Dispose(bool disposing)
{
if (!IsDisposed)
if (IsDisposed)
{
return;
}
if (disposing)
{
foreach (var connection in connections.Values)
foreach (var tx in _transactions.Values)
{
try { tx?.Dispose(); } catch { }
}
_transactions.Clear();
foreach (var connection in _connections.Values)
{
try
{
if (connection != null)
{
if (connection.State == ConnectionState.Open)
if (connection.State != ConnectionState.Closed)
{
connection.Close();
}
connection.Dispose();
}
}
catch
{
// ignore
}
}
_connections.Clear();
}
IsDisposed = true;
}
}
}

View file

@ -100,7 +100,9 @@
"props": null,
"description": null,
"isActive": true,
"dependencies": ["DynamicEntityComponent"]
"dependencies": [
"DynamicEntityComponent"
]
}
],
"ReportCategories": [
@ -2406,7 +2408,12 @@
"minSalary": 80000,
"maxSalary": 120000,
"currencyCode": "USD",
"requiredSkills": ["JavaScript", "TypeScript", "React", "Node.js"],
"requiredSkills": [
"JavaScript",
"TypeScript",
"React",
"Node.js"
],
"responsibilities": [
"Develop frontend and backend applications",
"Write clean and maintainable code",
@ -4101,7 +4108,9 @@
{
"postContent": "CI/CD pipeline güncellememiz tamamlandı! Deployment süremiz %40 azaldı. Otomasyonun gücü 💪",
"type": "video",
"urls": ["https://www.w3schools.com/html/mov_bbb.mp4"]
"urls": [
"https://www.w3schools.com/html/mov_bbb.mp4"
]
}
],
"SocialPollOptions": [
@ -4256,5 +4265,82 @@
"parentGroupCode": "MAMUL",
"isActive": true
}
],
"Materials": [
{
"code": "MT001",
"name": "Yüksek Kaliteli Çelik Levha 10mm",
"barcode": "1234567890123",
"description": "Çelik Levha 2mm",
"materialTypeCode": "RAW",
"materialGroupCode": "METAL",
"uomName": "kg",
"costPrice": 15.5,
"salesPrice": 18.75,
"currencyCode": "TRY",
"isActive": true,
"totalStock": 2500.0,
"trackingType": "Quantity"
},
{
"code": "MT002",
"name": "Alüminyum Profil 40x40",
"barcode": "1234567890124",
"description": "Alüminyum Profil 40x40",
"materialTypeCode": "SEMI",
"materialGroupCode": "METAL",
"uomName": "Adet",
"costPrice": 45.0,
"salesPrice": 55.0,
"currencyCode": "TRY",
"isActive": true,
"totalStock": 1200.0,
"trackingType": "Lot"
},
{
"code": "PR001",
"name": "Montajlı Motor Grubu A-Type",
"barcode": "1234567890125",
"description": "Motor Grubu A-Type",
"materialTypeCode": "FINISHED",
"materialGroupCode": "MOTOR",
"uomName": "Adet",
"costPrice": 850.0,
"salesPrice": 1200.0,
"currencyCode": "TRY",
"isActive": true,
"totalStock": 45.0,
"trackingType": "Lot"
},
{
"code": "SF001",
"name": "Kesme Yağı Premium",
"barcode": "1234567890126",
"description": "Kesme Yağı Premium",
"materialTypeCode": "FINISHED",
"materialGroupCode": "PLASTIK",
"uomName": "Adet",
"costPrice": 25.0,
"salesPrice": 35.0,
"currencyCode": "TRY",
"isActive": true,
"totalStock": 150.0,
"trackingType": "Quantity"
},
{
"code": "PK001",
"name": "Plastik Kapak Komponenti",
"barcode": "1234567890127",
"description": "Plastik Kapak",
"materialTypeCode": "SEMI",
"materialGroupCode": "KIMYA",
"uomName": "Adet",
"costPrice": 8.5,
"salesPrice": 15.0,
"currencyCode": "TRY",
"isActive": true,
"totalStock": 850.0,
"trackingType": "Serial"
}
]
}

View file

@ -94,6 +94,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
private readonly IRepository<SocialLike, Guid> _socialLikeRepository;
private readonly IRepository<MaterialType, Guid> _materialTypeRepository;
private readonly IRepository<MaterialGroup, Guid> _materialGroupRepository;
private readonly IRepository<Material, Guid> _materialRepository;
public TenantDataSeeder(
IClock clock,
@ -170,7 +171,8 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
IRepository<SocialComment, Guid> socialCommentRepository,
IRepository<SocialLike, Guid> socialLikeRepository,
IRepository<MaterialType, Guid> materialTypeRepository,
IRepository<MaterialGroup, Guid> materialGroupRepository
IRepository<MaterialGroup, Guid> materialGroupRepository,
IRepository<Material, Guid> materialRepository
)
{
_clock = clock;
@ -249,6 +251,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
_socialLikeRepository = socialLikeRepository;
_materialTypeRepository = materialTypeRepository;
_materialGroupRepository = materialGroupRepository;
_materialRepository = materialRepository;
}
private static IConfigurationRoot BuildConfiguration()
@ -1641,5 +1644,37 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
}, autoSave: true);
}
}
foreach (var item in items.Materials)
{
if (string.IsNullOrWhiteSpace(item.Code))
continue;
var exists = await _materialRepository.AnyAsync(x => x.Code == item.Code);
if (exists)
continue;
var type = await _materialTypeRepository.FirstOrDefaultAsync(x => x.Code == item.MaterialTypeCode);
var group = await _materialGroupRepository.FirstOrDefaultAsync(x => x.Code == item.MaterialGroupCode);
var currency = await _currencyRepository.FirstOrDefaultAsync(x => x.Code == item.CurrencyCode);
var uom = await _uomRepository.FirstOrDefaultAsync(x => x.Name == item.UomName);
await _materialRepository.InsertAsync(new Material
{
Code = item.Code,
Name = item.Name,
Description = item.Description,
UomId = uom?.Id,
CostPrice = item.CostPrice,
SalesPrice = item.SalesPrice,
CurrencyId = currency?.Id,
IsActive = item.IsActive,
TotalStock = item.TotalStock,
MaterialTypeId = type?.Id,
MaterialGroupId = group?.Id,
Barcode = item.Barcode,
TrackingType = item.TrackingType
}, autoSave: true);
}
}
}

View file

@ -52,10 +52,6 @@ public class TenantSeederDto
public List<InterestingSeedDto> Interesting { get; set; }
public List<ProgramSeedDto> Programs { get; set; }
//Supply Chain
public List<MaterialTypeSeedDto> MaterialTypes { get; set; }
public List<MaterialGroupSeedDto> MaterialGroups { get; set; }
//Hr
public List<EmployeeTypeSeedDto> EmployeeTypes { get; set; }
public List<JobPositionSeedDto> JobPositions { get; set; }
@ -83,6 +79,28 @@ public class TenantSeederDto
public List<SocialPollOptionSeedDto> SocialPollOptions { get; set; }
public List<SocialCommentSeedDto> SocialComments { get; set; }
public List<SocialLikeSeedDto> SocialLikes { get; set; }
//Supply Chain
public List<MaterialTypeSeedDto> MaterialTypes { get; set; }
public List<MaterialGroupSeedDto> MaterialGroups { get; set; }
public List<MaterialSeedDto> Materials { get; set; }
}
public class MaterialSeedDto
{
public string Code { get; set; }
public string Name { get; set; }
public string Barcode { get; set; }
public string Description { get; set; }
public string MaterialTypeCode { get; set; }
public string MaterialGroupCode { get; set; }
public string UomName { get; set; }
public decimal CostPrice { get; set; }
public decimal SalesPrice { get; set; }
public string CurrencyCode { get; set; }
public bool IsActive { get; set; }
public decimal TotalStock { get; set; }
public string TrackingType { get; set; }
}
public class MaterialTypeSeedDto

View file

@ -9,7 +9,7 @@
"BaseDomain": "sozsoft.com"
},
"ConnectionStrings": {
"SqlServer": "Server=sql;Database=Erp;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;Encrypt=False;TrustServerCertificate=True;Connection Timeout=60;MultipleActiveResultSets=true;",
"SqlServer": "Server=sql;Database=Erp;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;Encrypt=False;TrustServerCertificate=True;Connection Timeout=60;",
"PostgreSql": "User ID=sa;Password=NvQp8s@l;Host=postgres;Port=5432;Database=Erp;"
},
"Redis": {

View file

@ -9,7 +9,7 @@
"BaseDomain": "sozsoft.com"
},
"ConnectionStrings": {
"SqlServer": "Server=sql;Database=Erp;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;Encrypt=False;TrustServerCertificate=True;Connection Timeout=60;MultipleActiveResultSets=true;",
"SqlServer": "Server=sql;Database=Erp;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;Encrypt=False;TrustServerCertificate=True;Connection Timeout=60;",
"PostgreSql": "User ID=sa;Password=NvQp8s@l;Host=postgres;Port=5432;Database=Erp;"
},
"Redis": {

View file

@ -9,7 +9,7 @@
"Version": "1.0.1"
},
"ConnectionStrings": {
"SqlServer": "Server=localhost;Database=Erp;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;Encrypt=False;TrustServerCertificate=True;Connection Timeout=60;MultipleActiveResultSets=true;",
"SqlServer": "Server=localhost;Database=Erp;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;Encrypt=False;TrustServerCertificate=True;Connection Timeout=60;",
"PostgreSql": "User ID=sa;Password=NvQp8s@l;Host=localhost;Port=5432;Database=Erp;"
},
"Redis": {

View file

@ -279,7 +279,7 @@ function TenantConnectionString({
'value',
'Server=sql;Database=' +
name +
';User Id=sa;password=@Password;Trusted_Connection=False;TrustServerCertificate=True;Connection Timeout=60;MultipleActiveResultSets=true;',
';User Id=sa;password=@Password;Trusted_Connection=False;TrustServerCertificate=True;Connection Timeout=60;',
)
else if (option?.value == 2)
//MsSql