‫۱۱ ماه قبل، پنجشنبه ۲۷ مهر ۱۴۰۲، ساعت ۰۲:۱۰
با استفاده از Gridify شما میتونید query خودتون رو تولید کنید ولی امکان ارسال نام جدول وجود ندارد. ,ولی حدودا 70 درصد از چیزی که نیاز دارید رو در اختیارتون میگذاره.
یک نکته که شاید کار رو براتون آسون‌تر کنه اینکه: کلاس `GridifyQuery` یک متد به نام `GetFilteringExpression` داره که query رو در اختیارتون قرار میده. فقط به دلیل اینکه generic هست باید در runtime ایجادش کنید. (همینطور کلاس QueryBuilder )

اگر بخوام یک مثال بزنم, فرض کنید شما قصد تولید چنین کدی در runtime برای  ("TableName= "Users ) دارید
var result = _db.Users.Where(filteringExpression).ToList();
با استفاده از Gridify میتونید filteringExpression رو تولید کنید. 
-----
راه حل دومی که بنظرم میرسه اینکه یک Dictionary بین نام جداول و Gridify.QueryBuilder تولید کنید و بسته به نام جدول درخواست شده توسط کاربر از QueryBuilder از پیش تعریف شده برای اعمال آن استفاده کنید.
‫۱۱ ماه قبل، سه‌شنبه ۲۵ مهر ۱۴۰۲، ساعت ۱۷:۵۳
من قصد پیاده سازی یک صفحه برای جستجوی پیشرفته بین همه جداول رو دارم. برای این کار یک کلاس تعریف کردم و در ورودی تابع یک لیست از این نوع را بهش پاس میدم. این کلاس اینطور تعریف شده:
public class SearchDTO
{
    public string TableName { get; set; }
    public string ColumnName { get; set; }
    public string searchPhrase { get; set; } = string.Empty;
    public DateTimeOffset? searchDateFrom { get; set; }
    public DateTimeOffset? searchDateTo { get; set; }
    public int Include { get; set; } = 1;
}
کاربر اسم جدول و اون ستونی که میخواد شرط رو براش اعمال کنه رو انتخاب میکنه و بعدش عبارت یا محدوده تاریخ رو وارد میکنه. این که شامل بشه یا نشه رو هم با Include میتونه مشخص کنه. 
من هر چی داکومنت رو خوندم توی همشون اسم جدول رو نمیشد به صورت string وارد کرد. اگه اشتباه میکنم لطفا اصلاح کنید.
رویه ای که مدنظرم هست اینه که داخل یه حلقه for یا foreach یک کوئری بنویسم که همه‌ی جداولی که کاربر انتخاب کرده رو با هم join کنه. بعدش توی یه حلقه دیگه شرط‌ها رو روی ستون هایی که انتخاب کرده اعمال کنم.
در نهایت ستون‌های نتیحه نهایی رو Select کنم تا اون ستون هایی که مجاز هستند به سمت کلاینت برگشت داده بشه. اسامی این ستون‌ها رو توی یه فایل .resx ذخیره کردم.
یعنی یه چیزی شبیه به این کد:(ولی این کد درست و قابل اجرا نیست)
// Join the tables dynamically based on the table names
for (int i = 1; i < filterList.Count; i++)
{
    var joinEntityType = entityTypes.FirstOrDefault(t => t.ClrType.Name == filterList[0].TableName)?.ClrType;
    if (entityType == null)
    {
        return (null, 0, 0);
    }
    var joinEntityQuery = (IQueryable<object>)Activator.CreateInstance(typeof(DbSet<>).MakeGenericType(joinEntityType), _dbContext);
    query = query.Join(joinEntityQuery.ToList(),
                                    x => x.GetType().GetProperty($"{filterList[i - 1].TableName}.{filterList[i - 1].TableName}Id").GetValue(x),
                                    y => y.GetType().GetProperty($"{filterList[i].TableName}.{filterList[i].TableName}Id").GetValue(y),
                                    (x, y) => x);
}

// Apply the conditions dynamically based on the column names and conditions
for (int i = 0; i < filterList.Count; i++)
{
    if (!string.IsNullOrEmpty(filterList[i].searchPhrase))
    {
        var parameter = Expression.Parameter(entityType, "x");
        var condition = Expression.Call(
            typeof(string).GetMethod("Contains", new[] { typeof(string) }),
            Expression.PropertyOrField(parameter, filterList[i].ColumnName),
            Expression.Constant(filterList[i].searchPhrase)
        );
        var lambda = Expression.Lambda<Func<object, bool>>(condition, parameter);

        query = query.Where(lambda);
    }
    if (filterList[i].searchDateFrom.HasValue)
    {
       //must write expression for date constraint
    }
}

// Select the specified columns dynamically
ResourceManager resourceManager = new ResourceManager(typeof(TablePropertiesResources));
var columnNames = resourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true)
    .OfType<DictionaryEntry>()
    .Select(entry => entry.Key.ToString())
    .ToList();
var selectColumns = columnNames.ToArray();
var selectedData = query
    .Select(x => new
    {
        // Dynamically select the desired properties
        Result = selectColumns.ToDictionary(column => column, column => x.GetType().GetProperty(column).GetValue(x))
    })
    .ToList();
آیا اینکار با gridify امکان پذیر می‌باشد؟
‫۱۱ ماه قبل، چهارشنبه ۱۹ مهر ۱۴۰۲، ساعت ۲۲:۰۱
- بسته به اینکه context را چگونه مدیریت می‌کنید، می‌توانند باشند یا خیر. اگر برای مثال از متد ExecuteTransactionAsync استفاده می‌کنید، بله، هستند و اگر SaveChanges آن در تراکنش دیگری اجرا می‌شود، مدیریت استثناءهای آن‌را باید خودتان انجام دهید. برای مثال یک flag را در جائی برای اطلاع از وقوع استثناء ثبت و بررسی کنید.
- البته اگر من امروز بخواهم این راه‌حل را بازنویسی کنم، از یک SaveChangesInterceptor استفاده می‌کنم و نه از روش override کردن متد SaveChanges.
‫۱۱ ماه قبل، پنجشنبه ۱۳ مهر ۱۴۰۲، ساعت ۲۰:۵۱
پشتیبانی از انواع داده‌ایی DateOnly, TimeOnly در EF8 اضافه شده است (برای پروایدر SQL Server):
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;


await using var context = new MyDbContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

context.Users.Add(new User
{
    Name = "John Doe",
    Birthday = new(1980, 1, 20),
    ShiftStart = new (8, 0),
    ShiftLength = TimeSpan.FromHours(8)
});
await context.SaveChangesAsync();

public class MyDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"...")
            .LogTo(Console.WriteLine, LogLevel.Information)
            .EnableSensitiveDataLogging();
    }
    public DbSet<User> Users { get; set; }
}

public class User
{
    public int Id { get; set; }
    public required string Name { get; set; }
    public DateOnly Birthday { get; set; }
    public TimeOnly ShiftStart { get; set; }
    public TimeSpan ShiftLength { get; set; }
}
با این DDL:
CREATE TABLE [Users] (
    [Id] int NOT NULL IDENTITY,
    [Name] nvarchar(max) NULL,
    [Birthday] date NOT NULL,
    [ShiftStart] time NOT NULL,
    [ShiftLength] time NOT NULL,
    CONSTRAINT [PK_Users] PRIMARY KEY ([Id])
);

‫۱۱ ماه قبل، سه‌شنبه ۱۱ مهر ۱۴۰۲، ساعت ۰۸:۲۶
یکی از معماری‌های پیاده سازی شده در این زمینه سیستم Multi Tenant مربوط به فریم ورک ABP هست.
به این صورت که یک دیتابیس پیش فرض و اصلی برای مدیریت تننت اصلی ساخته می‌شه و بعد از اون شما می‌تونید تننت‌های دیگه رو روی دیتابیس مجزا یا روی دیتابیس اصلی بسازید.همچنین می‌تونید مشخصات بیشتری هم از تننت داشته باشید و کاستوم شده برای بیزینس خودتون استفاده کنید.
‫۱۱ ماه قبل، سه‌شنبه ۱۱ مهر ۱۴۰۲، ساعت ۰۰:۴۹
جدای از استراتژی‌های مختلفی که برای شناسایی هر مستاجر در اینگونه وب اپلیکیشن‌ها اعمال میشود، سوال اینجاست که: برای سیستم‌های چند مستاجری Saas (با دیتابیس‌های جداگانه)، طبیعتاً  ما یک سایت جداگانه هم روی هاستی جداگانه برای بخش نمایش و فروش پلن‌های مختلف به مستاجران خواهیم داشت که مستاجر جدید ابتدا باید مشخصات شرکت/موسسه خود را در فیلدها درج کرده و سپس به مرحله‌ی نهایی و آخر که (پرداخت هزینه‌ی پلن مورد نظر خود میباشد) هدایت شود.  حال با فرض اینکه تمام مراحل تا اتمام پرداخت هزینه‌ی مربوطه درست انجام شود، آیا اطلاعات ثبت نامی و سوابق پرداختی و عملکرد مستاجران باید در دیتابیسی جداگانه مدیریت و ذخیره شوند؟؟ چرا که هدف از این پرسش، داشتن مجموعه اطلاعات جامعی از مشخصات ریز و درشت کلیه مستاجران جهت ارائه‌ی داشبوردی جامع به توسعه دهندگان آن در پس زمینه میباشد.