عدم سازگاری با EF
اهمیت: خیلی مهم نوع: درخواست راهنمایی شماره نگارش: 1
با سلام و احترام
وقتی دیتا سورس از جنس اینتیتی تعریف می‌کنم بحتی هیچ ستونی هم اد نمی‌کنم بدون اینکه خطایی دریافت کنم فایل پی دی اف، read only  می‌مونه و حجم فایل 0kb باقی می‌مونه
 public static IPdfReportData CreatePdfReport(Order order, int languageId)
        {
            if (order == null)
                throw new ArgumentNullException("order");



            Language lang = IoC.Resolve<ILanguageService>().GetLanguageById(languageId);

            if (lang == null)
                throw new NopException("Language could not be loaded");

            var localizationManager = IoC.Resolve<ILocalizationManager>();
            var orderProductVariants = order.OrderProductVariants;
            return new PdfReport().DocumentPreferences(doc =>
            {
                doc.RunDirection(PdfRunDirection.LeftToRight);
                doc.Orientation(PageOrientation.Portrait);
                doc.PageSize(PdfPageSize.A4);
                doc.DocumentMetadata(new DocumentMetadata { Author = "coponet", Application = "coponet eshop", Keywords = "Factor", Subject = "Factor", Title = "Factor" });
                doc.Compression(new CompressionSettings
                {
                    EnableCompression = true,
                    EnableFullCompression = true
                });
                doc.PrintingPreferences(new PrintingPreferences
                {
                    ShowPrintDialogAutomatically = false
                });
            })
            .DefaultFonts(fonts =>
            {
                fonts.Path(Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\arial.ttf",
                                  Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\verdana.ttf");
            })
            .PagesFooter(footer =>
            {
                footer.DefaultFooter(CalenderHelper.dateTimeParseToString("yyyy/MM/dd", order.CreatedOn, CalenderEnum.PersianCalender));
            })
            .PagesHeader(header =>
            {
                header.DefaultHeader(defaultHeader =>
                {
                    defaultHeader.RunDirection(PdfRunDirection.LeftToRight);
                    //defaultHeader.ImagePath(AppPath.ApplicationPath + "\\Images\\01.png");
                    defaultHeader.Message("Our new rpt.");
                });
            })
            .MainTableTemplate(template =>
            {
                template.BasicTemplate(BasicTemplate.ClassicTemplate);
            })
            .MainTablePreferences(table =>
            {
                table.ColumnsWidthsType(TableColumnWidthType.Relative);
                table.NumberOfDataRowsPerPage(1);
            })
            .MainTableDataSource(dataSource =>
            {
                //var listOfRows = new List<User>();
                //for (int i = 0; i < 40; i++)
                //{
                //    listOfRows.Add(new User {Id = i});
                //}
                //dataSource.StronglyTypedList(listOfRows);
                dataSource.StronglyTypedList(orderProductVariants);
            })
            )
            .MainTableEvents(events =>
            {
                events.DataSourceIsEmpty(message: "There is no data available to display.");
            })
           ).Generate(data => data.AsPdfFile(string.Format("{0}\\documents\\Temp\\Factor-{1}.pdf", HttpRuntime.AppDomainAppPath, order.OrderId)));
        }

این نمونه کدی که استفاده کردم

  • #
    ‫۱۱ سال و ۸ ماه قبل، یکشنبه ۲۹ بهمن ۱۳۹۱، ساعت ۱۶:۴۶
    - اکثر پرسش و پاسخ‌های مطرح شده در این قسمت مبتنی بر کار با EF است.
    - اطلاعاتی نداره این دیتا سورس؟ ساختارش چی هست؟ رکوردی داره؟
    روی سطر 15 مطابق کد فوق (return new) یک breakpoint قرار بدید و بررسی کنید که آیا orderProductVariants حاوی اطلاعاتی هست یا خیر.
    - اگر برنامه وب است، می‌تونید از data.FlushInBrowser هم استفاده کنید بجای data.AsPdfFile. شاید روی مسیر documents\\Temp دسترسی رایت ندارید.
    • #
      ‫۱۱ سال و ۸ ماه قبل، یکشنبه ۲۹ بهمن ۱۳۹۱، ساعت ۱۷:۲۵

      با سلام و احترام

      ممنون از پاسخ شما

      این تست کرده بودم می‌تونید خالی نبودن متغیر فوق ببینید اینم فیلد‌های اصلی این کلاس

       #region Properties
      
              /// <summary>
              /// Gets or sets the product variant identifier
              /// </summary>
              public int ProductVariantId { get; set; }
      
              /// <summary>
              /// Gets or sets the product identifier
              /// </summary>
              public int ProductId { get; set; }
      
              /// <summary>
              /// Gets or sets the name
              /// </summary>
              public string Name { get; set; }
      
              /// <summary>
              /// Gets or sets the SKU
              /// </summary>
              public string SKU { get; set; }
      
              /// <summary>
              /// Gets or sets the description
              /// </summary>
              public string Description { get; set; }
      
              /// <summary>
              /// Gets or sets the admin comment
              /// </summary>
              public string AdminComment { get; set; }
      
              /// <summary>
              /// Gets or sets the manufacturer part number
              /// </summary>
              public string ManufacturerPartNumber { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether the product variant is gift card
              /// </summary>
              public bool IsGiftCard { get; set; }
      
              /// <summary>
              /// Gets or sets the gift card type
              /// </summary>
              public int GiftCardType { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether the product variant is download
              /// </summary>
              public bool IsDownload { get; set; }
      
              /// <summary>
              /// Gets or sets the download identifier
              /// </summary>
              public int DownloadId { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether this downloadable product can be downloaded unlimited number of times
              /// </summary>
              public bool UnlimitedDownloads { get; set; }
      
              /// <summary>
              /// Gets or sets the maximum number of downloads
              /// </summary>
              public int MaxNumberOfDownloads { get; set; }
      
              /// <summary>
              /// Gets or sets the number of days during customers keeps access to the file.
              /// </summary>
              public int? DownloadExpirationDays { get; set; }
      
              /// <summary>
              /// Gets or sets the download activation type
              /// </summary>
              public int DownloadActivationType { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether the product variant has a sample download file
              /// </summary>
              public bool HasSampleDownload { get; set; }
      
              /// <summary>
              /// Gets or sets the sample download identifier
              /// </summary>
              public int SampleDownloadId { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether the product has user agreement
              /// </summary>
              public bool HasUserAgreement { get; set; }
      
              /// <summary>
              /// Gets or sets the text of license agreement
              /// </summary>
              public string UserAgreementText { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether the product variant is recurring
              /// </summary>
              public bool IsRecurring { get; set; }
      
              /// <summary>
              /// Gets or sets the cycle length
              /// </summary>
              public int CycleLength { get; set; }
      
              /// <summary>
              /// Gets or sets the cycle period
              /// </summary>
              public int CyclePeriod { get; set; }
      
              /// <summary>
              /// Gets or sets the total cycles
              /// </summary>
              public int TotalCycles { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether the entity is ship enabled
              /// </summary>
              public bool IsShipEnabled { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether the entity is free shipping
              /// </summary>
              public bool IsFreeShipping { get; set; }
      
              /// <summary>
              /// Gets or sets the additional shipping charge
              /// </summary>
              public decimal AdditionalShippingCharge { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether the product variant is marked as tax exempt
              /// </summary>
              public bool IsTaxExempt { get; set; }
      
              /// <summary>
              /// Gets or sets the tax category identifier
              /// </summary>
              public int TaxCategoryId { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating how to manage inventory
              /// </summary>
              public int ManageInventory { get; set; }
      
              /// <summary>
              /// Gets or sets the stock quantity
              /// </summary>
              public int StockQuantity { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether to display stock availability
              /// </summary>
              public bool DisplayStockAvailability { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether to display stock quantity
              /// </summary>
              public bool DisplayStockQuantity { get; set; }
      
              /// <summary>
              /// Gets or sets the minimum stock quantity
              /// </summary>
              public int MinStockQuantity { get; set; }
      
              /// <summary>
              /// Gets or sets the low stock activity identifier
              /// </summary>
              public int LowStockActivityId { get; set; }
      
              /// <summary>
              /// Gets or sets the quantity when admin should be notified
              /// </summary>
              public int NotifyAdminForQuantityBelow { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether to allow orders when out of stock
              /// </summary>
              public int Backorders { get; set; }
      
              /// <summary>
              /// Gets or sets the order minimum quantity
              /// </summary>
              public int OrderMinimumQuantity { get; set; }
      
              /// <summary>
              /// Gets or sets the order maximum quantity
              /// </summary>
              public int OrderMaximumQuantity { get; set; }
      
              /// <summary>
              /// Gets or sets the warehouse identifier
              /// </summary>
              public int WarehouseId { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether to disable buy button
              /// </summary>
              public bool DisableBuyButton { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether to show "Call for Pricing" or "Call for quote" instead of price
              /// </summary>
              public bool CallForPrice { get; set; }
      
              /// <summary>
              /// Gets or sets the price
              /// </summary>
              public decimal Price { get; set; }
      
              /// <summary>
              /// Gets or sets the old price
              /// </summary>
              public decimal OldPrice { get; set; }
      
              /// <summary>
              /// Gets or sets the product cost
              /// </summary>
              public decimal ProductCost { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether a customer enters price
              /// </summary>
              public bool CustomerEntersPrice { get; set; }
      
              /// <summary>
              /// Gets or sets the minimum price entered by a customer
              /// </summary>
              public decimal MinimumCustomerEnteredPrice { get; set; }
      
              /// <summary>
              /// Gets or sets the maximum price entered by a customer
              /// </summary>
              public decimal MaximumCustomerEnteredPrice { get; set; }
      
              /// <summary>
              /// Gets or sets the weight
              /// </summary>
              public decimal Weight { get; set; }
      
              /// <summary>
              /// Gets or sets the length
              /// </summary>
              public decimal Length { get; set; }
      
              /// <summary>
              /// Gets or sets the width
              /// </summary>
              public decimal Width { get; set; }
      
              /// <summary>
              /// Gets or sets the height
              /// </summary>
              public decimal Height { get; set; }
      
              /// <summary>
              /// Gets or sets the picture identifier
              /// </summary>
              public int PictureId { get; set; }
      
              /// <summary>
              /// Gets or sets the available start date and time
              /// </summary>
              public DateTime? AvailableStartDateTime { get; set; }
      
              /// <summary>
              /// Gets or sets the shipped end date and time
              /// </summary>
              public DateTime? AvailableEndDateTime { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether the entity is published
              /// </summary>
              public bool Published { get; set; }
      
              /// <summary>
              /// Gets or sets a value indicating whether the entity has been deleted
              /// </summary>
              public bool Deleted { get; set; }
      
              /// <summary>
              /// Gets or sets the display order
              /// </summary>
              public int DisplayOrder { get; set; }
      
              /// <summary>
              /// Gets or sets the date and time of instance creation
              /// </summary>
              public DateTime CreatedOn { get; set; }
      
              /// <summary>
              /// Gets or sets the date and time of instance update
              /// </summary>
              public DateTime UpdatedOn { get; set; }
              /// <summary>
              /// Gets or sets CouponCreated
              /// </summary>
              public bool? CouponetCreated { get; set; }
              /// <summary>
              /// Gets or sets the date and time of CouponCreated
              /// </summary>
              public DateTime? CouponetCreatedOn { get; set; }
              #endregion

      • #
        ‫۱۱ سال و ۸ ماه قبل، یکشنبه ۲۹ بهمن ۱۳۹۱، ساعت ۱۷:۴۱
        مطابق شکل lazy loading فعال است در حین کار با روابط (order.OrderProductVariants) تعیین شده (این DynamicProxies که قابل مشاهده است).
        - می‌تونید این lazy loading رو با تنظیم DbContext.Configuration.ProxyCreationEnabled = false غیرفعال کنید (کلا و سراسری).
        - یا می‌تونید زمانیکه کوئری تهیه می‌کنید، از متد AsNoTracking استفاده کنید (()from p in context.Products.AsNoTracking).
        + همچنین زمانیکه کوئری تهیه می‌شود می‌تونید از متد Include برای eager loading بجای lazy loading استفاده کنید. (روش استاندارد و متداول برای تهیه گزارشات؛ از این جهت که eager loading، رفت و برگشت به بانک اطلاعاتی را کاهش می‌دهد و همچنین ذکر AsNoTracking مصرف حافظه برنامه را در حین تهیه گزارشات فقط خواندنی، کم می‌کند)
        context.Customers.Include(c => c.Orders).AsNoTracking()
        • #
          ‫۱۱ سال و ۸ ماه قبل، یکشنبه ۲۹ بهمن ۱۳۹۱، ساعت ۱۷:۴۸
          من از هیچ کدوم از navigation properties برای هیچ ستونی استفاده نکردم یعنی mapper اضافه شده در کتابخانه شما هر property مپ می‌کنه؟ این روی سرعت تاثیر منفی نداره؟
          • #
            ‫۱۱ سال و ۸ ماه قبل، یکشنبه ۲۹ بهمن ۱۳۹۱، ساعت ۱۷:۵۲
            - بررسی کلاس نهایی OrderProductVariants به تنهایی مهم نیست.
            زمانیکه entity1.entity2 دارید یعنی استفاده از خواص راهبری و عموما به صورت lazy loading است؛ خصوصا مطابق تصویری که ارسال کردید (order.OrderProductVariants).
            - دریافت اطلاعات OrderProductVariants به همراه entity دربرگیرنده آن به یکباره انجام نشده، بلکه lazy loading در اینجا صورت گرفته (توسط EF؛ نه کتابخانه گزارش ساز).
            راه حل: از متد Include استفاده کنید به همراه AsNoTracking که توضیح دادم.
            - این‌ها هم باید در لایه سرویس شما انجام شوند و نه اینجا. لایه سرویس شما فقط باید یک List را بازگشت دهد.
            • #
              ‫۱۱ سال و ۸ ماه قبل، یکشنبه ۲۹ بهمن ۱۳۹۱، ساعت ۱۸:۱۵
              آقای نصیری
              لایه سرویس همه این کارها رو انجام می‌ده
              شیی Order به متد فوق ارسال می‌شه سپس OrderProductVarients که به عنوان یک Custome property تعریف شده پشت صحنه یک linq query اجرا می‌کنه و اگر لازم باشه مکانیزم کش هم انجام می‌شه توی تصویر هم این شی یک لیست از شی OrderProductVarient نه چیز دیگه ای و یک رکورد داره.
              من متوجه نمی‌شم دیتا سورس من یک Ilist با یک رکورد این چه تناقضی با Lazy loading توکار لایه بیزنس داره

              جالب اینجاست با تعریف یک کلاس مدل مشکل حل می‌شه!
              public class OrderProductVarientModel
                  {
                     public int OrderProductVarientId
                      {
                          get;
                          set;
                      }
                  }

              حالا ازین کد استفاده کردم
                .MainTableDataSource(dataSource =>
                          {
                              var listOfRows = new List<OrderProductVarientModel>();
                              for (int i = 0; i < orderProductVariants.Count; i++)
                              {
                                  listOfRows.Add(new OrderProductVarientModel { OrderProductVarientId = orderProductVariants[i].OrderProductVariantId });
                              }
                              dataSource.StronglyTypedList(listOfRows);
                              //dataSource.StronglyTypedList(orderProductVariants);
                          })

              به نظر من یک جایی از متد StronglyTypedList داره همه property‌های شی جنریک مپ می‌کنه!
              • #
                ‫۱۱ سال و ۸ ماه قبل، یکشنبه ۲۹ بهمن ۱۳۹۱، ساعت ۱۸:۲۲
                - مطابق مستندات کتابخانه PdfReport، شما زمانیکه تعاریف ستون‌ها رو حذف می‌کنید، PDFReport تمام خواص عمومی کلاس OrderProductVariants را در گزارش ظاهر خواهد کرد، مگر اینکه با استفاده از data annotations مواردی را که نیاز نیستند، حذف کنید.
                - همچنین اگر واقعا نیاز به یک خاصیت در گزارش نهایی دارید، در حین Projection نهایی کوئری LINQ تهیه شده (با نوشتن select ایی که فقط یک خاصیت را بر می‌گرداند)، تنها این یک خاصیت را بازگشت دهید. اگر گزارش شما یک شیء کامل را بر می‌گرداند، کار اضافی در سمت تهیه دیتاسورس شما انجام شده نه در سمت کتابخانه‌ای که قرار است از این نتیجه استفاده کند.
                - بحث lazy loading ، eager loading و تشکیل dynamicProxies را در اینجا مطالعه کنید.
                - همچنین اهمیت استفاده از AsNoTracking را هم در اینجا مطالعه کنید.
  • #
    ‫۱۱ سال و ۸ ماه قبل، دوشنبه ۳۰ بهمن ۱۳۹۱، ساعت ۰۲:۰۳
    - یک مثال جدید Entity framework که در آن lazy loading و dynamic proxies فعال است به مجموعه مثال‌های PdfReport اضافه کردم: (^)
    - همچنین برای اینکه dynamic proxies سبب بروز stack overflow exception نشود نحوه استخراج خواص تو در تو توسط پارامتر dumpLevel محدود شد. به این ترتیب وجود dynamic proxies سبب نخواهد شد تا کلاس‌هایی که به یکدیگر ارجاع دارند n میلیون بار توسط EF وهله سازی شوند!
    این تغییرات فعلا در SVN موجود هستند.