‫۱ ماه قبل، پنجشنبه ۲۵ مرداد ۱۴۰۳، ساعت ۲۱:۰۲

آنچه که در خصوص global using فرمودید و با توجه به تشابه اسامی کلاسها، باید از Alias استفاده کنم و در زمان استفاده لزوما بجای استفاده از آدرس کامل و طولانی فضای نام، از نام Alias استفاده کنم.

‫۱ ماه قبل، پنجشنبه ۲۵ مرداد ۱۴۰۳، ساعت ۲۰:۵۳

تمام Entityهایی که ساختم دارای Schema هستند و تمامی Modelها نیز در پوشه هایی هم نام با Schema قرار داده شده اند. برای مثال من دو کلاس در مسیرهای زیر دارم (Application = schema):

Models.Output.Application.ActionMethods.ActionMethod();
Domain.Entities.Application.ActionMethods.ActionMethod();

اگر فضای نام را using کنم و بخوام در یک متد از هر دو کلاس نمونه سازی کنم خطای زیر صادر میشه (Ambiguous reference):

using Ces.Caspian.Models.Output.Application.ActionMethods;
using Ces.Caspian.Domain.Entities.Application.ActionMethods;

{
  var a = new ActionMethod();
  var b = new ActionMethod();
}

//'ActionMethod' is an ambiguous reference between 'Ces.Caspian.Domain.Entities.Application.ActionMethods.ActionMethod' and 'Ces.Caspian.Models.Output.Application.ActionMethods.ActionMethod'

مگر آنکه در زمان نمونه سازی از نام کامل استفاده کنم:

var a = new Models.Output.Application.ActionMethods.ActionMethod();
var b = new Domain.Entities.Application.ActionMethods.ActionMethod();

تمامی کلاس هایی که در پروژه Model قرار دارند همان نقش DTO را دارند. چه به عنوان ورود اطلاعات و چه به عنوان خروجی. آیا نامگذاری Modelها اشکال دارند؟ در واقع سعی کردم از افزودن پیشوند و پسوند اضافه به نام Modelها پرهیز کنم.

‫۱ ماه قبل، چهارشنبه ۱۷ مرداد ۱۴۰۳، ساعت ۱۰:۴۴

آنچه که در خصوص کتابخانه های مخصوص اعتبارسنجی فرمودید آیا با ارجاع به بانک اطلاعاتی هم پیاده سازی میشوند؟ چون مفهوم اعتبارسنجی را در سطح کلاس های برنامه بلد هستم. برای سناریوی عنوان شده در پست اولیه، یک لایه اعتبارسنجی توسط FluentValidation پیاده سازی شده و null بودن کلیدها بررسی می شوند ولی وجود چنین شناسه ای به عنوان کلید اصلی در بانک اطلاعاتی چطور باید بررسی شود؟ آیا با همان FluentValidation امکانپذیر است یا اینکه در همان لایه Application باید تمام کلیدها بررسی و پیغام مناسب به کاربر برگردانده شود؟

گویا نیازی به تعریف ستون ها نیست (تازه متوجه شدم) و به روش زیر هم میشه ساده انجام بشه:

public class JoitnProfile : Profile
{
    public JoitnProfile()
    {
        CreateMap<LineJoint, Models.Output.Piping.LineJoints.LineJoint2>();
    }
}

و استفاده از ConfigurationProvider پیش فرض:

var result = await query.ProjectTo<Models.Output.Piping.LineJoints.LineJoint2>(_mapper.ConfigurationProvider).ToListAsync();

پروژه Selector تعطیل و AutoMapper جایگزین میکنم. تشکر جناب نصیری

ضمن تشکر. جهت یادگیری میپرسم. اگرچه که AutoMapper میتونه مشکل را حل کنه ولی تمام ستون های مورد نیازم رو باید در configuration تعریف کنم. آیا اگر خودم بتونم یک Selector مانند نمونه زیر ایجاد کنم بهتر نیست؟ دلیل این کار کاهش وابستگی و راندمان بیشتره. آیا ایجاد Selectorی مانند زیر این دو هدف را برآورده میکنه؟

private static Expression<Func<LineJoint, Models.Output.Piping.LineJoints.LineJoint2>> Selector()
{
    //if (Condition())
    //    return x => new Models.Output.Piping.LineJoints.LineJoint2
    //    {
    //        ....
    //    };

    return x => new Models.Output.Piping.LineJoints.LineJoint2
    {
        Id = x.Id,
        JointNo = x.JointNo
    };
}

در نتیجه میتونم query را بصورت زیر اجرا کنم:

var result = await query.Select(Selector()).ToListAsync();

البته یک نمونه در اینترنت پیدا کردم (البته پاسخ Copilot بوده) که متد را بصورت Generic تعریف کرده بود که برای انجام Dynamic Select روش زیر را بکاربرده بود:

IQueryable<TResult> results = query.SelectMany(x => selectProperties.Select(prop => prop.Compile()(x)));

تا اینجا هیچ مشکلی وجود ندارد ولی به محض آنکه در خط بعدی متد ToList اجرا میشه با پیغام خطا مواجه میشم:

An exception was thrown while attempting to evaluate a LINQ query parameter expression. See the inner exception for more information. To show additional information call 'DbContextOptionsBuilder.EnableSensitiveDataLogging'.

کد کامل Copilot:

public async Task<List<LineJoint2>> GetAsync2(
    Expression<Func<LineJoint, bool>> filter,
    List<Expression<Func<LineJoint, object>>> includes,
    List<Func<IIncludableQueryable<LineJoint, object>, IIncludableQueryable<LineJoint, object>>> thenIncludes,
    Expression<Func<IQueryable<LineJoint>, IOrderedQueryable<LineJoint>>> orderBy,
    int pageSize,
    int pageNumber,
    bool trackChanges = true,
    CancellationToken cancellationToken = default)
{
    var query = context.LineJoints.AsQueryable();

    // Apply filter
    if (filter != null)
        query = query.Where(filter);

    // Include related entities
    foreach (var include in includes)
        query = query.Include(include);

    // Apply thenIncludes
    foreach (var thenInclude in thenIncludes)
        query = thenInclude(query);

    // Project properties dynamically
    var projectedQuery = query.Select(x => new LineJoint2
    {
        Id = x.Id,
        JointNo = x.JointNo
        // Add other properties from LineJoint as needed
    });

    // Apply ordering
    if (orderBy != null)
        projectedQuery = orderBy.Compile()(projectedQuery);

    // Apply pagination
    var pagedQuery = projectedQuery.Skip((pageNumber - 1) * pageSize).Take(pageSize);

    // Execute the query
    return await (trackChanges ? pagedQuery : pagedQuery.AsNoTracking()).ToListAsync(cancellationToken);
}