-
نوشتن کوئری با مقادیر رابطه های چند به چند
با سلام
من یک موجودیت فروشگاه دارم به شکل زیر :
public class Shop : BaseContactInfo
{
public string Sevices { get; set; }
public short CityId { get; set; }
public City City { get; set; }
public List<ShopCategory> ShopCategories { get; set; }
}
با توجه به کلاس فروشگاه من می تونه داخل چندین Category قراربگیره و همینطور برعکس ( رابطه چند به چند ) و من در Fluent api به این شکل رابطه دیتابیس رو ایجاد کردم :
HasMany(x => x.ShopCategories).WithMany()
.Map(x => x.ToTable("Tbl_ShopsCategories")
.MapLeftKey("ShopId")
.MapRightKey("CategoryId"));
دیتابس و روابط کاملا درست هست . الان مشکل من این هستش که کوئری می خوام بزنم تمامی فروشگاه ها رو بیاره اما نمی دونم باید چیکار کنم از Include هم استفاده کردم اما هیچ مقداری رو نمی آره .
خواستم در این رابطه راهنمایی کنید چطور لیستی برگردونم که هر موجودیت فروشگاه شامل لیست Category ها هم باشه .
با تشکر
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
میتونید از SelcectMany استفاده کنید
var list = dbo.Shops
.SelectMany(e => e.ShopCategories,
(sh, cat) => new YourViewModel
{
a = sh.field1,
b = cat.field2,
c = cat.field3
});
بدینصورت هم میشود عمل کرد
public class vm
{
1-فیلد از مدل فروشگاه
2-فیلد از مدل فروشگاه
3 لیست جنریک از نوع category
}
کوئری هم بدنیصورت بنویسید
var list = Shops.SelectMany(e => e.ShopCategories).Select(x=> new YourViewModel
{
فیلد مدل فروشگاه=x.,
categorys= x.categorys//لیست جنریک
});
فقط یک سوال نحوه نمایش شما در ویو به چ صورت هست؟ نمایش منوی کشویی هست یا به صورت دیگر؟
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
سلام
مرسی بابت توضیحات خوبتون
من می خوام این لیست رو داخل یک اکشن در Web API به صورت JSON برگردونم .
کوئری اول درست کار می کرد ولی اینکه نام فروشگاه با هر کدام از Category ها رو به صورت یک Object جدا برمی گردوند .
مد نظر من کوئری دوم شما هست که متاسفانه من vm رو ساختم کوئری رو نوشتم اونجایی که باید فیلد های vm رو مقدار دهی کنیم داخل select وقتی x رو می زدم فقط به فیلد های Category دسترسی داشتم و فیلد های خود Shop نبودند .
مد نظر من یک خروجی به شکل زیر هست :
ShopName : فروشگاه تهرانی
Categories : فروش پوشاک , فروش مبلمان,فروش لوازم خانگی
در حقیقت فیلد Categories من می خوام شامل رشته ای باشه که گروه های فروشگاهی من با , از هم جدا شده باشند
View Model هم که ایجاد کردم به شکل زیر :
public class ShopViewModel
{
public string ShopName { get; set; }
public List<ShopCategory> Categories { get; set; }
}
ممنون می شم راهنمایی کنید بتونم به اون خروجی برسم
تشکر از شما
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
شما میتونیداز Automapper کمک بگیرید
ابتدا ویومدلتون را اصلاح کنید چون شما می خواهید رشته ها را با کاما بهم بچسبانید باید فیلد از نوع رشته تعریف کنید
public class ShopViewModel
{
public string ShopName { get; set; }
public string Categories { get; set; }
}
چون ef از توابع سی شارپ در بدنه خود پشتیبانی نمی کند باید از automapper بهره بریم
لیست زیر به راحتی اون چیزی را که میخواین بهتون میده
var li= _mapper.Map<List<ShopViewModel>>(Shops.Include(x=> x.ShopCategories));
کلاس کانفیگ autommaper هم یادتون نره
configuration.CreateMap<shop, ShopViewModel>()
.ForMember(dest => dest.ShopName , opt => opt.MapFrom(src => src.ShopName ))
.ForMember(dest => dest.Categories , mo => mo.MapFrom(src =>
src.ShopCategories!= null
? string.Join(",", src.ShopCategories.Select(x => x.CatName).ToList())
: ""));
اگر از Automapper نمی خواید استفاده کنید باید ابتدا لیست زیر واکشی کنید
var list=Shops.Include(x=> x.ShopCategories).tolist();
var return=list.select(x=> new ShopViewModel{ShopName =x.shopname,
Categories =
string.Join(",", src.ShopCategories.Select(x => x.CatName)
و سپش projection بزنید که این روش سربار داره و کند تر هست به دلیل اینکه یکبار داده از دیتابیس خوانده شده و سپس حلقه یا select مجدد روی آن اجرا میشود
-
2 ضمیمه
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
سلام
ممنون از راهنمایی های شما و عذر خواهی بابت سوالات متداول .
من Autommaper رو نصب کردم و یک کلاس Configuration براش درست کردم که داخل فایل Globax هم Register می کنم ( طبق روندی که از قبل داشتم )
public static class AutoMapperServiceManager
{
public static void Configure()
{
}
}
اما مشکل اینجاست که کد شما رو که می زارم CreateMap رو نمی شناسه و خطا می ده
و اینکه کدی که برای برگردوندن لیست فرموده بودید من گذاشتم ولی زمانی که shops.Include رو می نویسم و x. رو می زنم هیچ مقداری نمی آره یعنی ShopCategories رو نمی شناسه . من کد زیر رو نوشتم :
var shops = db.Shops;
var li = Mapper.Map<List<ShopViewModel>>(shops.Include(x => x.ShopCategories));
من تصویر هر دو موضوع رو هم ضمیمه کردم
ممنون می شم بررسی کنید
ممنون بابت وقتی که می زارید .
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
این خطای عدم شناسایی ShopCategories ربطی به Automapper نداره
این در واقع یک لیست هست که بصورت پارامتر به automapper ارسال میشه
شما میتونید این قسمت داخل پرانتر رو بیاریدش بیرون و بریزید توی متغیر دیگه و سپس ارسال کنید به mapper
var shops = db.Shops.Include(x => x.ShopCategories
var li = Mapper.Map<List<ShopViewModel>>(shops));
چک کنید ببینید در این حالت ShopCategories شناسایی میشه؟اگر نشد که به نظر من همینطوره
مشکل کار جای دیگست
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
سلام و احترام
چک کردم اما در این حالت هم ShopCategories رو نمی آره . به نظر شما مدل من ایرادی نداره ؟ یا اینکه نیاز نیست مثل روابط یک به چند سمت ShopCategory یک ICollection از Shop بزارم ؟
برای فایل Config قسمت AutoMapper چیکار کنم که CreateMap رو نمی شناسه ؟ امکان داره Pakage درستی رو نصب نکرده باشم ؟ من پکیجی که اسمش دقیقا AutoMapper بود با لوگو قرمز رنگ نصب کردم
تشکر از لطف شما من خیلی با روابط چند به چند کار نکردم و توی پروژه واقعی تقریبا اولین بار هست به همین دلیل سیستم فکریم ریخته بهم
ممنون از شما
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
در روابط چند به چند دوسر رابطه حتما باید کالکشن متناظر داشته باشند و در ضورت نیاز با fluent یک تنظیماتی مثل خودتون میشه انجام داد
this.HasMany(x => x.Shops)
.WithMany(x => x.Categories)
.Map(map =>
{
map.MapLeftKey("ShopId");
map.MapRightKey("CatgoryId");
map.ToTable("ShopCategories ");
});
تنظیمات Automapper شما صحیح نیست این مثالی که من پست قبلی زدم جهت بادآوری شما بود
برای کار با automapper چند روش هست
ساده ترینش کلاسهای پروفایل هست
ابتدا یک کلاس پروفایل میسازیم
public class ShopProfile : Profile
{
protected override void Configure()
{
this.CreateMap<source, dest>();
// .ForMember(user => ......);
کدهایی که قبلا فرستادم اینجا قرار بدید
}
public override string ProfileName
{
get { return this.GetType().Name; }
}
}
باید automapper را رجیستر کرد
در فایل استارت اپ قرار بدید
Mapper.Initialize(cfg => ()
{
cfg.AddProfile<ShopProfile>();
});
Mapper.AssertConfigurationIsValid();
-
1 ضمیمه
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
سلام و احترام
مرسی بابت پاسخ های زیادی که دادید . من از راه دومی که فرمودید تونستم خروجی بگیریم ولی به گفته خودتون و تستی که کردم کند هستش . من کل چیزی رو که پیاده سازی کردم برای استفاده از AutoMapper اینجا می زارم ممنون می شم بررسی کنید :
۱ - کلاس Shop من :
public Shop()
{
this.ShopCategories = new List<ShopCategory>();
this.Stones = new List<Stone>();
}
public string Sevices { get; set; }
public short CityId { get; set; }
public City City { get; set; }
public virtual ICollection<ShopCategory> ShopCategories { get; set; }
public virtual ICollection<Stone> Stones { get; set; }
2 - کلاس ShopCategory
public class ShopCategory : BaseEntity<byte>
{
public ShopCategory()
{
this.Shops = new List<Shop>();
}
public string Name { get; set; }
public virtual ICollection<Shop> Shops { get; set; }
}
3 - کلاس Stone
public Stone()
{
this.Shops= new List<Shop>();
}
public string Name { get; set; }
public string Details { get; set; }
public string Colors { get; set; }
public string Resource { get; set; }
public string Usage { get; set; }
public string PriceStatus { get; set; }
public virtual ICollection<StoneGallery> StoneGalleries { get; set; }
public virtual ICollection<Shop> Shops { get; set; }
* این موجودیت Stone جدید اضافه کردم دقیقا این مورد هم رابطه چند به چند داره با فروشگاه های که لیست سنگ های قابل ارائه رو مشخص می کنه
4 - تنظیمات Fluent من
ToTable("tbl_Shops");
Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGenerated Option.Identity);
Property(x => x.Sevices).HasMaxLength(2000).IsUnicode();
HasRequired(x => x.City).WithMany(x=>x.Shops)
.HasForeignKey(x => x.CityId)
.WillCascadeOnDelete(false);
HasMany(x => x.Stones).WithMany(x=>x.Shops)
.Map(x => x.ToTable("tbl_ShopsStones")
.MapLeftKey("ShopId")
.MapRightKey("StoneId"));
HasMany(x => x.ShopCategories).WithMany(x=>x.Shops)
.Map(x => x.ToTable("Tbl_ShopsCategories")
.MapLeftKey("ShopId")
.MapRightKey("CategoryId"));
5 - تنظیمات Autommaper که فرمودید :
public class ShopProfile : Profile
{
protected void Configure()
{
this.CreateMap<Shop, ShopDemoViewModel>()
.ForMember(dest => dest.ShopName, opt => opt.MapFrom(src => src.Title))
.ForMember(dest => dest.Categories, mo => mo.MapFrom(src =>
src.ShopCategories != null
? string.Join(",", src.ShopCategories.Select(x => x.Name).ToList())
: ""));
}
public override string ProfileName
{
get { return this.GetType().Name; }
}
}
6 - ریجیستر کردن تنظیمات در Globax و متد Application_Start
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Registe r);
FilterConfig.RegisterGlobalFilters(GlobalFilters.F ilters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
GlobalConfiguration.Configuration.Formatters.JsonF ormatter.MediaTypeMappings
.Add(new System.Net.Http.Formatting.RequestHeaderMapping("A ccept",
"text/html",
StringComparison.InvariantCultureIgnoreCase,
true,
"application/json"));
Mapper.Initialize(cfg =>
{
cfg.AddProfile<ShopProfile>();
});
Mapper.AssertConfigurationIsValid();
}
7 - فایل ShopDemoViewModel
public class ShopDemoViewModel
{
public string ShopName { get; set; }
public string Categories { get; set; }
}
8 - کد نوشته شده در کنترلر webapi
public List<ShopDemoViewModel> Get()
{
var db = new ApplicationDbContext();
var shops = db.Shops.Include("ShopCategories").Include("Stones ").ToList();
var li = Mapper.Map<List<ShopDemoViewModel>>(shops).ToList( );
return li;
}
=> اولین مشکل این هست که Navigation برای من کار نمی کنه و حتما Include ها رو باید String اون رابطه رو بدم تا خروجی بده این خیلی مهم هست اگر می شه لطفا این رو بررسی بکنید من کجای کار اشتباه کردم کل دو سر رابطه ها و تنظیمات رو تصحیح کردم
=> دومین مشکل هم که خطای ضمیمه شده هستش که هیچ خروجی نمی ده
تشکر بابت وقتی که می زارید .
[COLOR=inherit !important]
[/COLOR]
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
خطای automapper بابت این هست که شما در سمت مدل فیلدها و یا فیلدهای ناوبری دارید که در قسمت ویومدل ندارید و مپ نشده
در ورژن های قدیم تر automapper این مپ نشدن نادیده گرفته میشد و خطایی نمی داد ولی اگر اشتباه نکنم شما باید جدیدترین ورژن داشته باشید
در ورژن 6 باید یک تنظیم اضافه کنید تا این خطا بر طرف شود
Mapper.Initialize(cfg => {
cfg.IgnoreUnmapped();
});
و اگر شما ناوبری را بصورت لامبدا در دسترس ندارید شاید مشکل ef باشد یکبار از طریق nuget به روز رسانی کنید
تمام فولدر های bin و obj را از پروژه هاتون حذف کنید و دوباره بیلد کنید
در ضمن در کلاسهای مدل نیازی به سازنده ندارید و این وهله سازی کالکشن ها را هم حذف کنید
یک مورد دیگر Tolist هم از این حذف کنید نیازی نیست
db.Shops.Include("ShopCategories").Include("Stones ").ToList();
-
1 ضمیمه
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
سلام
تشکر از شما .
بله من آخرین ورژن داخل nuget رو نصب کردم که 7 هستش . من کد تنظیم AutoMapper رو داخل Global گذاشتم متاسفانه هر کار کردم IgnoreUnmapped رو نمی شناسه و قرمزش می کنه . سرچ هم کردم توضیحی نداده بودن . تصویرش رو ضمیمه کردم .
فکر کنم باید از گفته شما استفاده کنم چون روش دوم واقعا کند هستش و احساس می کنم یک loop شدید می خوره و وقفه زیادی داره به عنوان یک کوئری که ۱۵ تا رکورد داره بر می گردونه ممنون می شم در این رابطه راهنمایی کنید.
برای Navigation هم طبق گفته شما ef رو update کردم به آخرین ورژن و فودر های bin و obj رو هم حذف کردم ولی متاسفانه زمانی دو مرتبه Include نوشته می شه و لامبادا می نویسم مجدد هیچ عکس العملی از خودش نشون نمی ده
در کلاس های مدل فرمودید نیاز به سازنده نیست یعنی کد زیر رو حذف کنم از ساختار مدل هام درسته ؟
public Shop()
{
this.ShopCategories = new List<ShopCategory>();
this.Stones = new List<Stone>();
}
عذر خواهی می کنم این مشکل من به درازا کشیده
ممنون از شما
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
این کلاس Extenssion را استفاده کتید
public static class MapperExtensions
{
private static void IgnoreUnmappedProperties(TypeMap map, IMappingExpression expr)
{
foreach (string propName in map.GetUnmappedPropertyNames())
{
if (map.SourceType.GetProperty(propName) != null)
{
expr.ForSourceMember(propName, opt => opt.Ignore());
}
if (map.DestinationType.GetProperty(propName) != null)
{
expr.ForMember(propName, opt => opt.Ignore());
}
}
}
public static void IgnoreUnmapped(this IProfileExpression profile)
{
profile.ForAllMaps(IgnoreUnmappedProperties);
}
public static void IgnoreUnmapped(this IProfileExpression profile, Func<TypeMap, bool> filter)
{
profile.ForAllMaps((map, expr) =>
{
if (filter(map))
{
IgnoreUnmappedProperties(map, expr);
}
});
}
public static void IgnoreUnmapped(this IProfileExpression profile, Type src, Type dest)
{
profile.IgnoreUnmapped((TypeMap map) => map.SourceType == src && map.DestinationType == dest);
}
public static void IgnoreUnmapped<TSrc, TDest>(this IProfileExpression profile)
{
profile.IgnoreUnmapped(typeof(TSrc), typeof(TDest));
}
}
کانفیگ Automapper هست و بار ورژن 7.1.1
Mapper.Initialize(cfg => {
cfg.CreateMap<Personnel, PersonnelViewModel>();
cfg.IgnoreUnmapped();
});
برای اعمال lazy loading خودکار وقتی کالکشن های کلاس poco بصورت virtual هستند نیازی به سازنده ی کلاس ها ندارید
متدinclude در فضای نام System.Data.Entity هست و اگر رفرنس داده باشید نباید خطا بدهد
-
1 ضمیمه
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
سلام
وقت بخیر
طبق گفته های شما الان هیچ خطایی نیست و Include هم با اضافه کردن System.Data.Entity حل شد و با اضافه کردم Extenssion هم IgnoreUnmapped حل شد . الان کد من به شکل زیر شده :
public List<ShopDemoViewModel> Get()
{
var db = new ApplicationDbContext();
var li = Mapper.Map<List<ShopDemoViewModel>>(db.Shops.Inclu de(x => x.ShopCategories));
return li;
}
الان کد هیچ خطایی نداره و ۵ تا رکورد هم بر می گردونه که به تعداد رکورد های Shop در دیتابیس هستند اما مقدار ها null هستند و خروجی مثل تصویر ضمیمه شده هست . هر چی بالا و پایین کردم مشکل حل نشد .
ممنون می شم راهنمایی کنید
تشکر
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
مشکل از کانفیگ در استارت آپ هست
تنظیمات به صورت زیر انجام بدید
Mapper.Initialize(cfg => {
cfg.IgnoreUnmapped();
cfg.AddProfile<ShopProfile>();
});
Mapper.AssertConfigurationIsValid();
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
سلام و احترام
الان تنظیمان در Globax من دقیقا به این شکل هست :
Mapper.Initialize(cfg => {
cfg.IgnoreUnmapped();
cfg.AddProfile<ShopProfile>();
});
Mapper.AssertConfigurationIsValid();
ولی همچنان مقادیر داخلی رو null بر می گردونه . کلا توی این پیاده سازی من خوردم به موارد عجیب .
ممنون می شم اگر نکته ای برای تصحیح هست بفرمایید انجام بدم
تشکر
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
سلام
مشکل از عدم مپ شدن فیلدها هست
به این دلیل هم میتونه باشه:
کلاس های ویومدل شما در پروژه دیگری باشند
و کلاسهای مدل در یک پروژه ی دیگر
کلاس پروفایل را حذف کنید و کانفیگ زیر در استارت اپ قرار بدید مپ شدن ها را در اینجا قرار بدید
Mapper.Initialize(cfg => {
cfg.CreateMap<model, ShopDemoViewModel>();
cfg.IgnoreUnmapped();
});
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
سلام
تشکر از شما برای این پاسخ های زیادی که وقت گذاشتید و دادید . بله Model من در یک Class library جداگانه بود . و تنظیمات رو داخل Globax گذاشتم حل شد و الان نتیجه کاملا درسته .
فقط برای اینکه ذهنم روشن تر بشه سه سوال روندی دارم خدمتتون :
۱ - سریعترین کوئری که برای یک موجودیت با دو رابطه چند به چند می شه نوشت همین هست ؟ چون وب سرویس هست خیلی سرعت کوئری برام مهمه . هیچ بهینه سازی می تونم بکنم ؟
۲ - راه دیگه ای وجود نداره که تنظیمان Map رو که الان اوردم داخل globax بشه داخل یک کلاس مثل همون Profile انجام داد ؟ چون اگه موارد زیاد بشن یکم شلوغ می شه این فایل
۳ - هر نکته ای در رابطه با بهینه سازی و سرعت و همچنین کیفیت یک سناریو این مدلی هست ممنون می شم بهم بگید
با تشکر و احترام
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
یک پروفایلر بکار ببرید و چند روش کوئری چند به چند که در اول تاپیک گفتم تست بزنید بینید کوئری تون چقدر کارایی دارد
بهترینش همین هست
var shops = db.Shops.Include("ShopCategories").ToList();
در ضمن وقتی در کوئری چند به چند بر روی مثلا db.shops کوئر ی میزنید دیگر نیاز به Include("Stones") نیست
چون شما به خود مدل دسترسی مستقیم دارید
جهت بکارگیری کلاس پروفایل میتونید کلاس های پروفایل را انتقال بدید به پروژه ای که استارت اپ هست و مشکل حل خواهد شد
میتونید از قابلیت scan ابزاری مثل Structuremap هم برای کانفیگ Automapper استفاده کنید تا کل سولوشن شما اسکن شده و مشکل اینکه مدل هاتون در یک پروژه و ویومدل ها در پروژه ی دیگه هست حل بشه
روش های دیگری هم برای استفاده از Automapper هست مثلا بکارگیری IMapperConfigurationExpression که خودش بحث جدا دارد و خیلی بهتر از کلاسهای پروفایل هست
بکارگیری automapper در تمام کوئری هاتون حتمن فراموش نکنید در کارایی و سرعت تاثیر دارد
البته میتونید کوئری هایی که سرعت بالاتری نیاز دارید بضورت استورد پراسیجر در دیتابیس اسکیول سرور تعریف کنید و در ef صدا بزنید
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
ممنون از راهنماییتون .
کوئری نهایی که نوشتم و صفحه بندی هم داره به این شکل هست که به درستی اجرا می شه :
var shopMainQuery =
db.Shops.Include(x=>x.ShopCategories).Include(x=>x .Stones)
.OrderByDescending(x => x.Id)
.ThenBy(x => x.Rate).ToList();
var storeList = Mapper.Map<List<ShopDataListViewModel>>(shopMainQu ery.Skip(skip).Take(numberPerPage));
نظرتون رو می فرمایید ؟ درست انجامش دادم ؟ متغییر های paging رو نذاشتم که شلوغ نشه .
فقط یک مشکلی هم هست من یک CityName دارم که با کد زیر Map کردم که بین Shop و City هم Navigaton هست ولی نام شهر رو بر نمی گردونه توی حالت لیست که از همین ساختار استفاده می کنم مشکلی نیست . اگر در این رابطه هم بفرمایید چیکار باید بکنم ممنون می شم .
.ForMember(dest => dest.CityName, opt => opt.MapFrom(src => src.City.Name))
یک رابطه یک به چند هست که با Icollection بحث Navigation رو دادم و Fluent هم طبق اصول و با Navigation هست . نمی دونم چرا نمی آره اسم شهر رو .
تشکر از شما
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
سلام مجدد
این مشکل آخر که نام شهر نمی اومد رو من .Include(x=>x.City) گذاشتم مشکل حل شد و نام شهر رو هم می آره .
سوالم اینه که برای رابطه های یک به چند هم باید Include انجام بشه ؟ چون قبلا برای نمایش لیست ها اطلاعات رو روی Navigation می اورد و مشکلی نبود
تشکر
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
جسارتا من الان خواستم نمایش یک فروشگاه رو هم پیاده کنم مجبور شدم برای برگرداندن نام شهر به شکل زیر عمل کنم :
var shopQuery = db.Shops.Include(x => x.City).FirstOrDefault(x=>x.Id==id);
var storeList = Mapper.Map<ShopDataListViewModel>(shopQuery);
مقادیر categories و stone رو اتوماتیک می آره و Map می کنه با نام شهر مشکل داره
با تشکر
[COLOR=inherit !important]
[/COLOR]
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
به دو صورت به فیلدهای ناوبری دسترسی داریم یکی lazy loading یا واکشی با تاخیر که همون روش قبلی شماست و دیگری eager loading که با include انجام میشه
lazy loading : فرض کنید در سایت کاربر بر روی یک کالا کلیک کرده و مشخصات جدول parent باید به او نشان داده شود در این جور کوئری ها که بصورتlazy یا با تاخیر هست شما به ظاهر یک دستور ساده دارید ولی در واقع به محض کلیک کاربر برای نمایش جدول parent یا فیلدهای ناوبری مجددا یک کوئری دیگر صادر میشود
این جور دستورات در هنگام کار با کالکشن مانند یک بمب افکن هست که کوئری به سمت دیتابیس صادر میشود
مثلا فرض کنید یک جدول کالا دارید و هر کالا یک فیلد ناوبری از جدول category دارد و مد نظر شماست که یک گالری بسازید وقتی یک کوئری صادر میکنید و بدون include هست این کوئری باید تمام کالا ها همراه با cat مربوطه را در یک جدول نشان دهد گالری شما نشان داده میشود ولی : کافی است کمی به پس زمینه نگاه کنید به ازای هر رکورد navigation یک کوئری صادر میشود و این یک فاجعه هست
برای حل این مشل از eager loading استفاده میشود و مشهور است به کوئری در لحظه
و فقط یک کوئری همراه با جوین های مربوطه گالری شما نشون داده میشود
الان هم تا زود هست کوئری های نیازمند به eager loading را پیدا کنید
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
Automapper متدی دارد بنام ProjectTo جهت LinqToObject هست و اگر شما در کوئری هاتون Include هم بکار نبرید بصورت هوشمند Include یا همون eager loading های مورد نیاز را برقرار میکند
ولی وقتی از ProjectTo بهره نمیبریم مانند مثالهای قبلی شما , باید صراحتا تمام include ها را برقرار کرد
در اینجا include stone یا include cityهم اضافه کنید تا lazy loading نشود
در ضمن کلید خارجی مانند cityId را از نوع short بکار نبرید همون int استفاده کنید سازگارتر هست
-
نقل قول: نوشتن کوئری با مقادیر رابطه های چند به چند
سلام
بی نهایت از توضیحات شما ممنونم . الان روشن شدم که داستان چی هستش .
خیلی خیلی ممنون که این همه وقت گذاشتید در طی این چند روز گذشته .
تشکر و احترام