در توسینسو تدریس کنید

و

با دانش خود درآمد کسب کنید

rohmos

Convert Lambda Expression

با سلام .

فرض کنید دو کلاس با پراپرتی های مشابه هم داریم.

 public class Class1
    {
        public Class1()
        {

        }
        public byte ID { get; set; }
        public string Name { get; set; }
    }

و

 public class Class2
    {
        public Class2()
        {

        }
        public byte ID { get; set; }
        public string Name { get; set; }
    }


که اولی یک DBSet در EF و دومی یک تابع دقیقا مشابه آن در لایه BLL.

حال در لایه BLL یک تایع میخواهم بنویسم که یک Lambda Expression دریافت کند و نتیجه را باتوجه به DBSet کلاس 1 برگرداند. مثل تابع زیر:


 public static Class2 GetData(Expression> input)
        {
            Class2 result =new Class2();
            using (DBDataContext odb=new DBDataContext())
            {
                result=odb.Class1s.Single(input) //Error*****
            }
            return result; 
        }


اما عبارت input بر اساس Class2 میباشد و هنگام اعمال بر Class1 با خطا روبرو میشوم. چطور میتوانم عین همان عبارت وارد شده به تابع را از نوع Class2 به Class1 jfndg کنم و جستجو را بر DBSet انجام دهم؟


در لایه پرزنتیشن هم کدی که وارد میشود چیزی شبیه به این میباشد.

BLL.GetData(c=>c.ID==0);




این سوال 1 پاسخ دارد.
لذت یادگیری با توسینسو
به عنوان شخصی که مدت هاست از سایت توسینسو استفاده می کنم باید بگم که واقعاً یکی از بهترین مرجع ها برای ارتقاء دانش شخصی هست. دوره های سایت، راهکارها و مطالب، همگی عالی هستند.
حسین احمدی

سلام، وقت بخیر

دقیقاً متوجه نشدم قصد انجام چه کاری رو دارید؟ می خواید از روی کلاس اول، کلاس دوم رو با مقادیر مشابه ایجاد کنید؟ یعنی یک کپی از کلاس اول بر اساس کلاس دوم؟

لطفاً سوال خود را در انجمن مطرح کنید، به سوالات در پیام خصوصی پاسخ داده نخواهد شد
rohmos

سلام . ببخشید منظورتون از انجمن کجاست؟ من متوجه نشدم کجا باید سوالمو بپرسم!!

rohmos

ببینید استاد احمدی . اصلا مشکل من اینه.


من یک برنامه چند لایه دارم مینویسم که بانک اطلاعاتی اون بر اساس  entity faramework Code first هستش حالا میخواهم مطلقا هیچ ارتباطی بین لایه presentation و data Access نباشه. برای همین غیر از لایه bussiness logic یک لایه دیگه هم نوشتم که دقیقا کپی کلاسها و پراپرتی های توی لایه data access منه. و منطق من اینه که اطلاعات از لایه presentation توسط لایه چهارم که اسمش را data traslation گذاشتم به لایه bussiness logic منتقل میشه و اونجا بر اساس اطلاعات دریافتی تجزیه و تحلیل و داده مربوط از طریق لایه data access دریافت و مجدد به شکل یه شیی از کلاس data traslation به لایه presentation برگشت داده میشه. تا حدودی هم موفق بودم تا اینکه یک عبارت لامبدا را خواستم در لایه presentation برای یک تابع موجود در لایه presentation بنویسم. حالا مشکل اینجاست که عبارت لامبدای من بر اساس data traslation است و امکان تبدیل عین همان عبارت را در لایه bussiness logic به یک عبارت لامبدا برای لایه data access خود ندارم. ممکن است کمک کنید.


نمیدانم توانستم درست مطلب را منتقل کنم یا نه. اما اگر راه حلی وجود دارد یا منطق دیگری برای لایه بندی که راحتتر باشد وجود دارد ممنون میشوم که کمک کنید.

حسین احمدی

مفهوم لایه بندی و کلاً معماری نرم افزار طوری هست که روش های مختلفی برای پیاده سازی وجود داره. به طور کلی لایه بندی برای نرم افزار متوسط به پایین الزامی نیست و دلیل منطقی هم برای لایه بندی وجود نداره، برای مثال، خیلی ها از Repository Pattern استفاده می کنن، اما من داخل کارهام برای مواردی که میخوام میام یک Extension Method برای DbSet می نویسیم که همون حالت Repository رو برای من شبه سازی کنه.

اما در مورد کاری که شما می خوایید انجام بدید، اگر درست متوجه شده باشم، شما یه لایه Data Access داری و میخوای اطلاعات بین Data Access و Business Object بوسیله خود Entity ها انجام نشه و یک کپی از کلاس ایجاد بشه.

شما باید برای اینکار DTO یا همون Data Transafer Object رو تعریف کنی، یک object خیلی ساده که مبتنی بر entity هست بدون Navigation ها یا مدلی هست که خروجی دیتا بر اساس اون داخل Application استفاده میشه. حالا اگر درست متوجه شده باشم مشکل شما با Expression هایی هست که برای کوئری استفاده می کنی و چون دسترسی مستقیم به entity ها نداری خطا دریافت می کنی. کاری که به نظر من میرسه و می تونی انجام بدی:


فرض کنیم Entity زیر رو داریم:


public class Customer
{
    public long Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection Orders { get; set; }
}


و یک کلاس به صورت زیر برای ارتباط بین لایه ها تعریف کردی:


public class CustomerDTO
{
    public long Id { get; set; }
    public string Name { get; set; }
    public int TotalOrders { get; set; }
}


شما یک Repository تعریف کن به صورت زیر:


public class CustomerRepository : ICustomerRepository
{
    YourDbContext dbContext;
    public CustomerRepository(YourDbContext dbContext)
    {
        this.dbContext = dbContext;
    }
    public IQueryable All
    {
        return dbContext.Customers.Select(c=> new CustomerDTO
        {
            Id = c.Id,
            Name = c.Name,
            Orders = c.Orders.Count
        }).AsQueryable();
    }
}


با کلاس بالا، شما اگر از IoC و DI استفاده کنی، داخل پروژه دسترسی شما به IQueryable~CustomerDTO هست و دیگه دسترسی مستقیم به Entity ها نداری، با این تفاوت که کوئری شما قابلیت گرفتن کوئری مجدد در لایه های پایین تر رو داره (Deffered Query Execution).


امیدوارم درست متوجه شده باشم منظورتون رو

لطفاً سوال خود را در انجمن مطرح کنید، به سوالات در پیام خصوصی پاسخ داده نخواهد شد
  • انتخاب شده به عنوان جواب توسط 1 نفر
rohmos

با عرض سلام و ادب خدمت استاد احمدی عزیز .

این چند روز مشغول گوش دادن به آموزش های شما در مورد رفلکشن و ریپازیتوری بودم.

فکر میکنم که درست نتوانستم منظورم را برسانم برای همین ایندفعه با یک دیاگرام سعی کردم توضیح بدم .


شمای کلی منطق برنامه من این است

 مشکل من نحوه تبدیل lambda expression که برا ساس شیی Data Transfer Object درلایه presentation ایجاد وبه لایه Business Logic ارسال میشود به یک lambda Expression دقیقا مشابه در لایه Data Access می باشد.


مثلا یک تابع در کلاس business داریم که یک عبارت لامبدا بر اساس DTOPerson گرفته و آنرا به یک عبارت لامبدا بر اساس Person تبدیل کرده و اجرا میکند و نتیجه را که یک لیست از person ها می باشد دوباره به یک لیست از DTOPerson ها تبدیل و بازمیگرداند. راه حل تبدیل لیست ها را توسط JSON حل کردم اما راه حلی برای تبدیل عبارات لامبدا پیدا نکردم.


امیدوارم واضح تر توضیح داده باشم.

rohmos

تو این مدت کلی جستجو کردم و متوجه شدم که باید از lambda expression parser ها استفاده کنم. توی اینترنت و nuget هم کلی سرچ کردم و چندتاparser هم پیدا کردم اما همشون خطا میدن. راهی که فکر میکنم باید انجام بدم اینه که عبارت لامبدا ارسال شده از لایه application به لایه business logic را با کمک parser  به string تبدیل  کنم و بعد این استرینگ را باز مجدد به یک عبارت لامبدا تبدیل کنم و ایندفه روی بانک اطلاعاتی اعمال کنم(کوئری بزنم فرضا روی جدول customer) و بعد نتیجه که یه لیست از customer ها هستند را تبدیل کنم به یه لیست از DTOcustomer وبرگردونم به لایه application

حسین احمدی

سلام، وقت بخیر

از کلاس Expression برای ایجاد عبارت های داینامیک استفاده کردید؟

لطفاً سوال خود را در انجمن مطرح کنید، به سوالات در پیام خصوصی پاسخ داده نخواهد شد
rohmos

با عرض سلام و ادب خدمت استاد. و تشکر فراوان بابت صبر و تحمل شما در پاسخ به سوالات .واقعا ممنونم. دقیقا متوجه سوال شما نشدم برای همین یک بار کل توابع را مینویسم تا بتواند راهگشا باشد. (البته با کمک دیاگرامی که قبلا فرستادم)


1- کلاس Customer من در لایه Data Acces layer با نام پروژه DAL

public class Customer
    {
        public Customer()
        {

        }
        public byte ID { get; set; }
        public string Name { get; set; }
    } 

و این هم کلاس DbContext

public class DBDataContext : DbContext
    {
        public DBDataContext()
        {

        }
        public DBDataContext(string nameorConnectionstring) : base(nameorConnectionstring)
        {

        }

        static DBDataContext()
        {
            //System.Data.Entity.Database.SetInitializer
            //    (new DBContextInitializer());
            System.Data.Entity.Database.SetInitializer(new DBContextInitializer());
        }

        public System.Data.Entity.DbSet Customers { get; set; }
  } 

2-کلاس BLLCustomer در لایه Business Logic Layer با نام پروژه BLL



    public class BLLCustomer
    {
        public static DTO.Customer ConvertDALtoDTO(DAL.Customer d)
        {
            string SerializedObj = JsonConvert.SerializeObject(d);
            return JsonConvert.DeserializeObject(SerializedObj);
        }
        public static DAL.Customer ConvertDTOtoDAL(DTO.Customer d)
        {
            string SerializedObj = JsonConvert.SerializeObject(d);
            return JsonConvert.DeserializeObject(SerializedObj);
        }
        public static IList ConvertDALtoDTO(IList d)
        {
            IList result = new List();
            foreach (DAL.Customer item in d)
            {
                string SerializedObj = JsonConvert.SerializeObject(item);
                result.Add(JsonConvert.DeserializeObject(SerializedObj));
            }

            return result;
        }
        public static IList ConvertDTOtoDAL(IList d)
        {
            IList result = new List();
            foreach (DTO.Customer item in d)
            {
                string SerializedObj = JsonConvert.SerializeObject(item);
                result.Add(JsonConvert.DeserializeObject(SerializedObj));
            }

            return result;
        }
        public static IList GetData()
        {
            using (DBDataContext odb = new DBDataContext())
            {
                return ConvertDALtoDTO(odb.Customers.ToList());
            }
        }
        
        public static DTO.Customer GetCustomers(Func person)
        {
            DTO.Customer result =new DTO. Customer();
            using (DBDataContext odb=new DBDataContext())
            {
                //???????????????
            }
            return result; 
        }
        public static DTO.Customer SelectCustomers(Expression<>> input)
        {
            DTO.Customer result = new DTO.Customer ();
            
            using (DBDataContext odb=new DBDataContext())
            {
                result = ConvertDALtoDTO(odb.Customer.Where(input));//ERROR
            }
            
            
            return result;
        }
        
    }  


ویرایش گر متن اشکال دارد و عبارت لامبدا را تایپ نمیکند برای همین من عکس آنرا میگذارم



TOSINSO 

3-کلاس DTOCustomer من با نام پروژه DTO

public class DTOCustomer
    {
        public Customer()
        {

        }
        public byte ID { get; set; }
        public string Name { get; set; }
    } 

4- دریافت اطلاعات از کلاس BLLCustomer در لایه Presentation


من فرضا میتوانم با استفاده از تابع GetData() اطلاعات را دریافت کنم :

dataGridView1.DataSource= BLL.BLLCustomers.GetData(); 

تا اینجا همه چیز درست است اما اگر بخواهم فیلتری روی اطلاعات انجام بدهم مثلا مشتری با ID برابر 1 یا با نام دلخواه را جستجو کنم مشکل ایجاد میشود:

dataGridView1.DataSource= BLL.BLLCustomers.GetData(c=>c.ID==1); 

این روش خطا ست

dataGridViewX1.DataSource= BLL.BLLCustomers.GetData().First(c=>c.ID==1); 

این راه هم هرچند جواب میدهد اما درست نیست چون سربار زیادی دارد بخصوص وقتی تعداد مشتریان زیاد شود. چون اول کل مشتریان دریافت میشود وبعد روی لیست دریافتی عبارت لامبدا اعمال میشود. حالا اگر از تابع SelectCustomers() استفاده کنم که اصولی ترین راه است:

dataGridView1.DataSource= BLL.BLLCustomers. SelectCustomers (c=>c.ID==1); 

اما این تابع چیزی را برنمی گرداند و بدون خطایی از تابع خارج میشود. گاها هم خطا میدهد با این مفهوم که عبارت لامبدا ارسال شده بر اساس DTO.Customer بوده وقابل اعمال روی کلاس DAL.Customer نیست. تمام مشکل من همین است استاد. در کل خوشحال میشوم اگر غیراز حل این مشکل در مورد منطق من در این برنامه اگر جایی ایراد وجود دارد یا جایی از برنامه غیراصولی و مبتدیانه است راهنمایی بفرمایید تا برای دیگر دوستان هم تجربه خوبی باشد. با تشکر

حسین احمدی

سلام مجدد، راهکاری که به ذهن من میرسه تبدیل پارامتر عبارت لامبدا شما به Data Type ای هست که داخل لایه Data Access استفاده میشه. اگه اجازه بدید من نمونه کدش رو بنویسم و اینجا بزارم، شاید یک الی دو روز دیگه کد مبدل رو بزارم شاید راه حلی باشه که دنبالش هستید.

لطفاً سوال خود را در انجمن مطرح کنید، به سوالات در پیام خصوصی پاسخ داده نخواهد شد
rohmos

حتما استاد. این ۲ روز را با اشتیاق فراوان منتظر خواهم بود.

rohmos

سلام استاد احمدی. میدونم که سرتون خیلی شلوغه و مشغله زیادی دارید. برای همین من کماکان منتظر نمونه کد شما هستم.

با تشکر فراوان

حسین احمدی

سلام، عذرخواهی می کنم، این هفته واقعاً درگیر بودم، اما تو Task ها نوشتن کد رو گذاشتم، حتماً کد رو براتون میفرستم.

لطفاً سوال خود را در انجمن مطرح کنید، به سوالات در پیام خصوصی پاسخ داده نخواهد شد
rohmos

ممنونم استاد.

 

یک مشکلی توی سایت وجود داره که وقتی با موبایل وارد سایت میشی قسمت خرید و دانلود درس ها نشان داده نمیشه .


 و اینکه چند مدت پیش توی سایت در مورد یک ORM تولید گروه شما خوندم. میخاستم بدونم توی چه مرحله ای هست و کی ارایه میشه؟


پاسخ شما
برای ارسال پاسخ خود وارد شوید.
از سرتاسر توسینسو
تنظیمات حریم خصوصی
تائید صرفنظر
×

تو می تونی بهترین نتیجه رو تضمینی با بهترین های ایران بدست بیاری ، پس مقایسه کن و بعد خرید کن : فقط توی جشنواره تابستانه می تونی امروز ارزونتر از فردا خرید کنی ....