- تعریف جدول بصورت id, title (که مثلا id دقیقا مقدار متناظر با چیزی که سمت کلاینت برای enum در نظر گرفتیم باشه) و سپس سمت ef CF مثل یک جدول معمولی باهاش کار بشه؟
- تعریف اعداد در یک جدول و map کردن با مقدار متناظر enum در سمت کلاینت؟
- راه دیگه ای؟
public class ItemInfo { public string ItemCode { get; set; } public string Description { get; set; } public decimal Price { get; set; } } public class OutOfStockException : Exception { public OutOfStockException() : base() { } public OutOfStockException(string message) : base(message) { } }
public sealed class LookupItem : CodeActivity { // Define an activity input argument of type string public InArgument<string> ItemCode { get; set; } public OutArgument<ItemInfo> Item { get; set; } // If your activity returns a value, derive from CodeActivity<TResult> // and return the value from the Execute method. protected override void Execute(CodeActivityContext context) { // Obtain the runtime value of the Text input argument ItemInfo i = new ItemInfo(); i.ItemCode = context.GetValue<string>(ItemCode); switch (i.ItemCode) { case "12345": i.Description = "Widget"; i.Price = (decimal)10.0; break; case "12346": i.Description = "Gadget"; i.Price = (decimal)15.0; break; case "12347": i.Description = "Super Gadget"; i.Price = (decimal)25.0; break; } context.SetValue(this.Item, i); } }
item.ItemCode
نکته : از کلاس Code Activity برای ارسال و دریافت مقادیر به درون Workflow استفاده میشود.
new OutOfStockException("Item Code"+item.ItemCode)
if (platform.ToUpper().Contains("MAC") && browser.ToUpper().Contains("SAFARI")) { // do something }
var isSafari = browser.ToUpper().Contains("SAFARI"); var isMac = platform.ToUpper().Contains("MAC"); if (isSafari && isMac) { // do something }
مراحل انجام این بازسازی کد
- متغیر محلی ای را ایجاد نمایید و بخشی از عبارت پیچیده را به آن مقداردهی کنید.
- تمامی استفادهها از آن بخش از عبارت را با مقدار متغیر جایگزین نمایید.
- کد را کامپایل و تست نمایید.
- برای بخشهای دیگر عبارت پیچیده همین کارها را تکرار نمایید.
public decimal GetPrice() { // price = base price - quantity * discount + shipping return quantity * itemPrice - Math.Max(0, quantity - 500) * itemPrice * 0.05 + Math.Min(quantity * itemPrice * 0.1, 100); }
var basePrice = quantity * itemPrice;
public decimal GetPrice() { // price = base price - quantity * discount + shipping var basePrice = quantity * itemPrice; return basePrice - Math.Max(0, quantity - 500) * itemPrice * 0.05 + Math.Min(basePrice * 0.1, 100); }
public decimal GetPrice() { // price = base price - quantity * discount + shipping var basePrice = quantity * itemPrice; var discount = Math.Max(0, quantity - 500) * itemPrice * 0.05; return basePrice - discount + Math.Min(basePrice * 0.1, 100); }
public decimal GetPrice() { // price = base price - quantity * discount + shipping var basePrice = quantity * itemPrice; var discount = Math.Max(0, quantity - 500) * itemPrice * 0.05; var shipping = Math.Min(basePrice * 0.1, 100); return basePrice – discount + shipping; }
اول اینکه، کیفیت دادههای ذخیرهشده در دستگاههای تلفن همراه کاربر بیشتر شخصی میشود تا مواردی دیگر! به غیر از ایمیل، پیامهای فوری، SMS / MMS ، لاگ تماسها، عکسها و پست صوتی وجود دارند که عموما توسعه دهندگان را دچار مشکل میکند.
برخی از گزینههای فوق بر روی یک کامپیوتر رومیزی هم وجود دارند، ولی اهمیت این دادهها بر روی اندروید و اجزای آن اهمیت فوق العادهای دارد. اطلاعات روی دستگاه موبایل شما به احتمال زیاد از ارزش بیشتری برخوردار خواهد بود، چرا که آنها را در یک صفحه 4 - 5 اینچی به همراه خود حمل میکنید و با خود هر کجا میبرید! این حالت، یک پلتفرم همگرا را بوجود میآورد؛ به این دلیل که سیستم رومیزی شما و تلفن همراه یک مجموعه غنی و کامل از اطلاعات حساس هستند که هردوی آنها شامل اطلاعات شخصی میباشند و برای شما اهمیت زیادی خواهند داشت. تصور کنید زمانیکه برای جلوگیری از نفوذ یا به سرقت رفتن شماره تلفنهای خود، یک پشتیبان بر روی سیستم رو میزی خود تهیه میکنید و فایل پشتیبان شمارههای تماس را بر روی سیستم شخصی نگه داری میکنید! آیا این همان پلتفرم همگرا نیست؟ آیا این دو سیستم مکمل هم نیستند؟حتی اگر همگامسازی را با یک مکان دوردست (Google Drive) انجام دهید، با این حال شما فقط در مقابل از دست دادن دادهها محافظت کردهاید و نه از دست دادن حریم خصوصی!
همچنین در نظر بگیرید که فرمت دادههای ذخیرهشده در دستگاههای تلفن همراه، تعیین و مشخص شوند! این کار اطلاعات حساس شما را به مرز سرقت نزدیکتر میکند. هر تلفن همراه SMS / MMS ، تماسها، و پست صوتی خواهد داشت. مکانهای ذخیره شده از روی GPS و مواردی دیگر که قطعا اطلاع دارید، تمامی اینها جزء مواردی هستند که خطرات امنیتی را در سیستم عامل اندروید شامل میشود. حالا در نظر بگیرید که این اطلاعات تا چه حد مهم است؟ برای کاربرانی که هیچ گونه پشتیبانی از اطلاعاتی از خود ندارند، از دست دادن دادهها قابل تصور نیست!
خطرناکترین نوع حملات بر روی پلتفرم اندروید انجام میشوند، در سکوت کامل و چندین هزار مایل دروتر از شما و فرد مهاجم نیازی به دسترسی فیزیکی و لمس تلفن همراه شما نخواهد داشت! این نوع حملات در هر زمانی ممکن است رخ دهد و اغلب میتواند به دلیل امنیت ضعیف در جای دیگری بر روی دستگاه رخ دهد.
در مطلب بعدی پیرامون امنیت معماری اندروید صبحت خواهیم کرد...
میخواهید پروژهای را انجام دهید که شامل جداول زیر است:
مقالات، اخبار، گالری تصاویر، گالری ویدیو، اسلایدشو، تبلیغات و ... و تمامی این جداول حداقل شامل یک فایل پیوست (عکس، فیلم، ...) میباشند. به طور مثال جدول مقالات دارای یک عکس نیز میباشد. قصد داریم تمام فایلها را بر روی هاست ذخیره کرده و فقط آدرس و نام فایل را در دیتابیس ذخیره نمایم.
روش اول : استفاده از یک فیلد در هر جدول برای نگه دارای اسم فایل
مثال:
public class Article { public int Id { get; set; } public string Title { get; set; } public string Body { get; set; } public string RegisterDate { get; set; } public string FileName { get; set; } }
این روش فقط در صورتی پاسخگو میباشد که هر رکورد فقط شامل یک فایل باشد. به طور مثال ممکن است برای یک مقاله، چندین عکس و فایل را ضمیمهی آن کنیم. در این حالت این روش پاسخ گو نمیباشد؛ ولی میتوانیم به صورت زیر نیز عمل کنیم:
ایجاد جدولی برای نگهداری فایلهای هر رکورد از مقاله :
public class ArticleFiles { public int Id { get; set; } public string FielName { get; set; } public string FileExtension { get; set; } public Article Article { get; set; } public int FileSize { get; set; } }
میتوانیم جدولی را به نام Attachment ایجاد کرده و هر فایلی را که آپلود میکنیم، مشخصات آن را در این جدول ذخیره کنیم و هر جدول هم که نیازی به فایل داشت، رابطهای با این جدول برقرار کند. در این حالت خواهیم داشت:
public class Attachment { public int Id { get; set; } public string Title { get; set; } public string FileName { get; set; } public string Extension { get; set; } public DateTime RegisterDate { get; set; } public int Size { get; set; } public ICollection<Article> ArticleFiles { get; set; } public ICollection<News> NewsFiles { get; set; } public int Viewed { get; set; } }
روش سوم : جدولی برای نگه داری اسم فایلها، بدون رابطه
جدول Attachment در این روش، همانند روش دوم میباشد؛ با دو تفاوت:
1- با هیچ جدولی رابطهای ندارد.
2- دو فیلد به عنوان نام جدول و Id رکورد به آن اضافه شده است.
تفاوت نسبت به روش دوم:
در روش دوم، ثبت یک رکورد، وابستهی به ثبت رکورد در جدول Attachment بود و ابتدا میبایستی فایل در Attachment ذخیره میشد و بعد از بدست آوردن Id آن، رکورد مورد نظر (مقاله) را درج میکردیم. ولی در این روش ابتدا مقاله درج شده و بعد از آن فایل را با اسم جدول و ID رکورد مورد نظر ذخیره میکنیم:
public class Attachment { public int Id { get; set; } public string Title { get; set; } public string FileName { get; set; } public string Extension { get; set; } public DateTime RegisterDate { get; set; } public int Size { get; set; } public string TableName { get; set; } public int RowId { get; set; } public int Viewed { get; set; } }
ایجاد یک کلاس پایه و ارث بری سایر کلاسها از کلاس پایه و ایجاد رابطهای بین کلاس پایه و کلاسهای مشتق شده.
نظراتی پیرامون حالتهای مختلف:
1- داشتن یک جدول الحاقات برای هر جدول
- اضافه کردن یک فیلد: بعضیها این
روش را ترجیح میدهند. به این دلیل که هر جدول، یک جدول attachment مختص به
خود دارد؛ با توجه به فیلدهایی که لازم است. به طور مثال ممکن است بعد از
گذشت مدتی، نیاز باشد تا دو فیلد برای فایلهای هر مقاله اضافه شوند که در
این حالت فقط به جدول attachment مقاله اضافه خواهند شد.
2- داشتن یک جدول پایه که کل فایلها در آن ذخیره شوند (روشهای دوم و سوم)
- متمرکز شدن کل فایلها در یک جدول: بیشتر پروژهها و یا برنامه نویسان (طبق تجربهی بنده) یک جدول پایه را برای این منظور دوست دارند. به دلیل اینکه تمام اطلاعات یکجا باشد.
- عدم آپلود چندین بارهی یک فایل: در این حالت میتوان از یک فایل چندین بار در چند جای مختلف استفاده نمود و در فضای هاست صرفه جویی میشود. این روش مدیریت سختی دارد و نیازمند کوئریهای بیشتری میباشد.
- وجود فیلدهای زیاد null در جدول: در این حالت ممکن است ردیفهایی با ستونهای مقدار null در جدول زیاد شوند. فرض کنید دو فیلد در جدول attachment وجود دارند که فقط توسط جدول مقالات مورد استفاده قرار میگیرند و در بقیهی جداول بدون استفاده میباشند.
از کدام روش استفاده کنیم؟
نمی توان پیشنهاد کرد که الزاما از کدامیک از روشهای بالا باید استفاده کنیم؛ چون نیازمندهایهای هر پروژه با هم متفات است و نمیتوان نسخهای خاص را برای همه تجویز کرد.
کوئری ذیل را در نظر بگیرید:
var productsList1 = ctx.Products.Where(product => product.Id > 1) .Include(product => product.Category) .Include(product => product.User) .Where( product => product.Category.Title.Contains("t") && product.Category.Id > 1 && product.Price > 100) .OrderBy(product => product.Price) .ToList();
احتمالا شاید عنوان کنید که به ازای هر Include یک join خواهیم داشت. بنابراین دو جوین به جداول کاربران و گروههای محصولها ایجاد میشود.
اما ... در واقعیت این کوئری را تولید میکند:
SELECT [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent1].[Price] AS [Price], [Extent1].[CategoryId] AS [CategoryId], [Extent1].[UserId] AS [UserId], [Extent3].[Id] AS [Id1], [Extent3].[Name] AS [Name1], [Extent3].[Title] AS [Title], [Extent3].[UserId] AS [UserId1], [Extent4].[Id] AS [Id2], [Extent4].[Name] AS [Name2] FROM [dbo].[Products] AS [Extent1] INNER JOIN [dbo].[Categories] AS [Extent2] ON [Extent1].[CategoryId] = [Extent2].[Id] LEFT OUTER JOIN [dbo].[Categories] AS [Extent3] ON [Extent1].[CategoryId] = [Extent3].[Id] LEFT OUTER JOIN [dbo].[Users] AS [Extent4] ON [Extent1].[UserId] = [Extent4].[Id] WHERE ([Extent1].[Id] > 1) AND ([Extent2].[Title] LIKE N'%t%') AND ([Extent1].[CategoryId] > 1) AND ([Extent1].[Price] > 100) ORDER BY [Extent1].[Price] ASC
این دو جوین حاصل یکبار Include جدول Categories و یکبار استفاده از navigation property آن در قسمت where است.
این باگ در اینجا گزارش شده، ولی به نظر هنوز برطرف نشدهاست یا مجددا ظاهر شدهاست.
برای رفع آن در حال حاضر بهترین راه حل استفاده از روش ذیل است:
var query2 = from product in ctx.Products let category = product.Category where product.Id > 1 where category.Title.Contains("t") && category.Id > 1 && product.Price > 100 select new { product, category }; var productsList2 = query2.ToList();
SELECT [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent1].[Price] AS [Price], [Extent1].[CategoryId] AS [CategoryId], [Extent1].[UserId] AS [UserId], [Extent2].[Id] AS [Id1], [Extent2].[Name] AS [Name1], [Extent2].[Title] AS [Title], [Extent2].[UserId] AS [UserId1] FROM [dbo].[Products] AS [Extent1] INNER JOIN [dbo].[Categories] AS [Extent2] ON [Extent1].[CategoryId] = [Extent2].[Id] WHERE ([Extent1].[Id] > 1) AND ([Extent2].[Title] LIKE N'%t%') AND ([Extent2].[Id] > 1) AND ([Extent1].[Price] > 100)
چند نکته:
-در کوئری let دار، اگر در قسمت select نهایی فقط product ذکر شود، هرچند جوین به جدول گروهها تشکیل میشود اما فیلدهای این جدول انتخاب نخواهند شد.
-معادل کوئری LINQ نوشته شده را اگر بخواهیم توسط متدهای الحاقی بازنویسی کنیم، به کوئری ذیل خواهیم رسید:
var query2ChainedVersion = ctx.Products .Select(product => new { product, category = product.Category }) .Where(@t => @t.product.Id > 1) .Where(@t => @t.category.Title.Contains("t") && @t.category.Id > 1 && @t.product.Price > 100) .Select(@t => new { @t.product , @t.category });
اگر علاقمند به آزمایش این باگ هستید، کدهای کامل آنرا از اینجا میتوانید دریافت کنید:
Sample38.zip
من خطای زیر رو دارم. برای ویرایش چند رکورد به صورت یکجا از Entity Framework Extended Library استفاده کردم. اما مشکلی دارم این است من یک جدول در پایگاه دارم که میخوام به صورت یکجا ویرایش کنم به این صورت که ابتدا شماره فیلد هایی که را قرار است تغییر دهم(فیلد ID) داخل یک لیست ریختم و سپس از جدول فقط اون فیلدها رو ویرایش کنم
چند روش برای join جدول با این لیست امتحان کردم یا join خطا میدهد اگر join نیز مشکلی نداشت مقدار برگشتی از نوع enumerable هست و زمانی که از update کلاس Entity Framework Extended Libraryاستفاده میکنم
خطا میدهد که لیستی که قرار است update شود باید از نوع dbquery باشد
Unable to create a constant value of type 'extendeexample.MyClass'. Only primitive types or enumeration types are supported in this context.
سورس پروژه به همراه پایگاه داده
project.rar
یکی از مشکلاتی که در طراحی با نرم افزار Designer از گزارش ساز StimulSoft داشتم، قرار دادن چند جدول یا Business Objectهای مختلف در یک ردیف است.
یکی از راه حلهای موجود، استفاده از panel است که توضیح آن به شرح ذیل میباشد.
امیدوارم این راه حل بتونه برای شما مفید واقع باشه.
ابتدا برای نمونه چند Business Object مطابق شکل زیر ایجاد کنید:
سپس با استفاده از پنلهای تو در تو، این Business Objectها یا جداول را در کنار هم قرار میدهیم.
فقط دقت کنید که گزینههای Can Grow و Grow To Height فعال باشند تا در صورت وجود اطلاعات بیشتر در جدوال، تمام اطلاعات را نشان دهد.
در نهایت جداول یا business objectها را در پنلهای مربوطه قرار میدهیم.
موفق و موید باشید
public class AA { public virtual ICollection<CC> Cs { get; set; } } public class BB { public virtual ICollection<CC> Cs { get; set; } } public class CC { public virtual AA AA { get; set; } public virtual long AAId { get; set; } public virtual BB BB { get; set; } public virtual long BBId { get; set; } public virtual string Value{get;set} }
ایجاد یک Repository در پروژه برای دستورات EF
زمانیکه ToList، First و امثال آن روی این عبارت فراخوانی شود تبدیل به SQL شده و سپس بر روی بانک اطلاعاتی اجرا میشود. به این deferred execution یا اجرای به تعویق افتاده گفته میشود.
اگر این عبارت را در اختیار لایههای دیگر قرار دهید، یعنی انتهای کار را بازگذاشتهاید و حد و حدود سیستم شما مشخص نیست. شما اگر IQueryable بازگشت دهید، در لایهای دیگر میشود یک join روی آن نوشت و اطلاعات چندین جدول دیگر را استخراج کرد؛ درحالیکه نام متد شما GetUsers بوده. بنابراین بهتر است به صورت صریح اطلاعات را به شکل List بازگشت دهید، تا انتهای کار باز نمانده و طراحی شما نشتی نداشته باشد.