# Native Code > برنامه نویسی در Delphi > مباحث عمومی دلفی و پاسکال >  شماره نامه

## www2006

سلام
فرض کنید یک سیستم نامه نگاری داریم که کاربران برای ارسال نامه خود به یک شماره نامه نیاز دارند ...
برای دادن شماره نامه منحصر بفرد برای هر نامه ( که هر کاربر درخواست آن را به سرور میدهد و سرور شماره را تولید کرده و برای کلاینت ارسال میکند) چه راهی پیشنهاد میکنید ؟

منظورم اینه که این فیلد ( احتمالا bigint ) رو تو کدوم یکی از تیبلهای دیتابیس باید قرار بدم ..

با تشکر ..

----------


## dkhatibi

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

----------


## www2006

> تیبلهای شما چگونه است؟
> مثلا تیبلی که یوزر را چک می کنه و یا به درخواستها رسیدگی می کنه.
> شاید هم یک تیبل مجزا بهتر باشه!


سه تا تیبل دارم :
یکی اطلاعات کاربران ، یکی برای گروههای کاری و یکی هم برای نامه ها ...
من فکر میکنم اگه تو تیبل نامه ها یک فیلد AutoInc بعنوان شماره نامه در  نظر  بگیرم  مشکل حل بشه ..
درسته ؟

----------


## www2006

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

راه استاندارد تری وجود نداره ؟؟

----------


## Valadi

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


دوست عزیز چرا راه استانداری وجود نداره البته که داره اگر شما اطلاعاتی در سیستم دبیرخانه داشته باشید تا حدود می دونید باید چه کار کنید .
در سیستم دبیرخانه یک شماره وجود داره که این شماره دو حالت داره 
1- فرستاده 
2 - دریافتی 
با توجه به دفاتر اندیکاتور دبیر خانه فعلی بازار


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

Table1.Fields[0].asinteger:=Table1.RecordCount+1

این کد هر موقع که فرم ثبت اطلاعات نامه باز میشه یک عدد به شما می ده که شما می تونید بعنوان شماره نامه تلقی کنید 


اگر هم کمکی در زمینه خواستی ما در خدمتیم

----------


## www2006

> اگر شما اطلاعاتی در سیستم دبیرخانه داشته باشید تا حدود می دونید باید چه کار کنید .
> در سیستم دبیرخانه یک شماره وجود داره که این شماره دو حالت داره 
> 1- فرستاده 
> 2 - دریافتی 
> با توجه به دفاتر اندیکاتور دبیر خانه فعلی بازار


 تا حدودی (با یه تحقیق سرپایی) یه چیزایی دستم اومده بود ..




> و اما برای شماره نامه شما می تونید موقعی که فرم لود میشه (البته دوستان هم اشاره به این موضوع داشتند) از این کد استفاده کنی :
> 
> Table1.Fields[0].asinteger:=Table1.RecordCount+1
> 
> این کد هر موقع که فرم ثبت اطلاعات نامه باز میشه یک عدد به شما می ده که شما می تونید بعنوان شماره نامه تلقی کنید


ببینید نامه از طریق کاربرهای مختلف تو زمانهای مختلف تنظیم میشه ... این راهی که شما گفتید و این مساله ای که من اشاره کردم (احتمالا) این مشکلات را خواهد داشت :

1- اگر دو یا چند کاربر دقیقا همزمان فرم مربوطه به تایپ نامه را باز کنند احتمالا یک شماره یکسان خواهند داشت ( البته این مطلبو بر اساس ته مونده های اطلاعات مغزم از مبحث نواحی بحرانی که تو درس سیستم عامل داشتیم میگم ).. دقیقا به همین دلیل بود که من  میخواستم از یک فیلد AutoInc استفاده کنم .

2- اگه یه کاربر فرم مربوط به ارسال نامه را باز کرد (وشمارنده یک واحد اضافه شد) و از ارسال نامه پشیمون شد عملا یکی از شماره های مربوط به نامه ها  بدون دلیل مصرف شده . پس اگه جداگانه (مثلا توسط یک Button ) شماره نامه بگیره فکر میکنم بهتر باشه .. درسته ؟


آقا این راه همین الان به فکرم رسید :
وقتی کاربر درخواست شماره نامه داد ، ما یه Record خالی تو جدول Insert کنیم و شماره ای که از اضافه شدن فیلد "Lid "  حاصل میشود (Lid همون فیلد AutoInc است) را برای کاربر ارسال کنیم .. حالا وقتی کاربر نامه را ارسال کرد ، نامه را در همین Record ( که مربوط به همین کاربر هست) اضافه کنیم ..

به نظر شما عملیه ..؟

----------


## FSarab

شما می خواهید یک شماره منحصر بفرد بر اساس یک فرمول خاصی تولید کنید
فیلد شما می تواند از نوع varchar باشد 
ولی مسله اینجا مشکل همزمانی است ممکن است چند کاربر همزمان یک شماره دریافت کنند
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
{تولید شماره جدید}
COMMIT TRANSACTION
SET TRANSACTION ISOLATION LEVEL READ COMMITTED

----------


## Valadi

> تا حدودی (با یه تحقیق سرپایی) یه چیزایی دستم اومده بود ..
> 
> ببینید نامه از طریق کاربرهای مختلف تو زمانهای مختلف تنظیم میشه ... این راهی که شما گفتید و این مساله ای که من اشاره کردم (احتمالا) این مشکلات را خواهد داشت :
> 
> 1- اگر دو یا چند کاربر دقیقا همزمان فرم مربوطه به تایپ نامه را باز کنند احتمالا یک شماره یکسان خواهند داشت ( البته این مطلبو بر اساس ته مونده های اطلاعات مغزم از مبحث نواحی بحرانی که تو درس سیستم عامل داشتیم میگم ).. دقیقا به همین دلیل بود که من  میخواستم از یک فیلد AutoInc استفاده کنم .
> 
> 2- اگه یه کاربر فرم مربوط به ارسال نامه را باز کرد (وشمارنده یک واحد اضافه شد) و از ارسال نامه پشیمون شد عملا یکی از شماره های مربوط به نامه ها  بدون دلیل مصرف شده . پس اگه جداگانه (مثلا توسط یک Button ) شماره نامه بگیره فکر میکنم بهتر باشه .. درسته ؟
> 
> 
> ...


فکر بدی نیست اگر این کار را می کنید باید شماره  نامه بعد تمام پر کردن فلید ها باشه که اگر خواست نامه را ثبت نکنه مشکلی نباشه

----------


## www2006

امتحانش میکنم و نتیجه رو اعلام میکنم ..

----------


## ehsane

دوست عزیز فکر کنم منظور ایشان اینست که هر کسی بتواند در هر لحظه یک رکورد را در بانک  ذخیره کند و شماره تولید شده توسط AutoInc توسط هر فرد مشخص باشد. من هم همین مشکل را دارم ، بنظرم باید یک برنامه در سرور نوشته شود و کار مدیریت این درخواست ها  را بر عهده بگیرد و با توجه به هر درخواست شماره تولید شده را به همان کاربر برگرداند

----------


## arshia_

باید در هنگام ذخیره نمودن نامه توسط کاربر مقدار عددی را دریافت کنی و ذخیره نمایی
اینطوری احتمال شماره تکراری کم می شود 
مخصوصا اگر از auto number استفاده کنی
با این روش در بدترین حالت دو کاربر باید در کمتر از یک هزارم ثانیه با هم درخواست ذخیره بدهند که این امر بعید به نظر می رسد

----------


## darvishiali

سلام؛

اولا باید بگم استفاده از TRANSACTION نباید در یک بازه طولانی انجام بشه (حتی در حدود یک ثانیه!) مخصوصا اگه تعداد Client ها زیاد باشن.

ثانیا اگه یه رکورد توی Table اضافه کنیم و بعد بخوایم Update کنیم چندتا مشکل داره مثلا اگه برنامه Crash بشه (مثلا در اثر خرابی سیستم یا قطع برق!)، یه رکورد بدون محتوا توی جدول باقی می مونه!

در ضمن، چون SQL Server داره Auto Increment رو پشتیبانی می کنه، هیچوقت نمیشه که دو رکورد با یک آیدنتیتی ذخیره بشن، حتی اگه هر دو با اختلاف زمانی یک میلیاردم ثانیه با هم بخوان ثبت بشن!


به نظر من بهترین راه حل اینه که تمام عملیات تایپ و اصلاح نامه انجام بشه و درنهایت وقتی که ذخیره شد، شماره رو برگردونه. (برای فیلد آیدنتیتی(Auto Increment) در SQL Server اینکار با SELECT @@IDENTITY امکان پذیره)

باز هم راه حل داره، اگه این به دردت نخورد، دوباره پیغام بذار. مرسی!

----------


## Navid7h

> سلام؛
> 
> اولا باید بگم استفاده از TRANSACTION نباید در یک بازه طولانی انجام بشه (حتی در حدود یک ثانیه!) مخصوصا اگه تعداد Client ها زیاد باشن.
> 
> ثانیا اگه یه رکورد توی Table اضافه کنیم و بعد بخوایم Update کنیم چندتا مشکل داره مثلا اگه برنامه Crash بشه (مثلا در اثر خرابی سیستم یا قطع برق!)، یه رکورد بدون محتوا توی جدول باقی می مونه!
> 
> در ضمن، چون SQL Server داره Auto Increment رو پشتیبانی می کنه، هیچوقت نمیشه که دو رکورد با یک آیدنتیتی ذخیره بشن، حتی اگه هر دو با اختلاف زمانی یک میلیاردم ثانیه با هم بخوان ثبت بشن!
> 
> 
> ...




من یک همچنین مشکلی رو با روش پیشنهادی شما حل کردمک
حالا اگه میشه شما هم راههای دیگه رو بگید.

متشکرم

----------


## www2006

> سلام؛
> 
> اولا باید بگم استفاده از TRANSACTION نباید در یک بازه طولانی انجام بشه (حتی در حدود یک ثانیه!) مخصوصا اگه تعداد Client ها زیاد باشن.
> 
> ثانیا اگه یه رکورد توی Table اضافه کنیم و بعد بخوایم Update کنیم چندتا مشکل داره مثلا اگه برنامه Crash بشه (مثلا در اثر خرابی سیستم یا قطع برق!)، یه رکورد بدون محتوا توی جدول باقی می مونه!
> 
> در ضمن، چون SQL Server داره Auto Increment رو پشتیبانی می کنه، هیچوقت نمیشه که دو رکورد با یک آیدنتیتی ذخیره بشن، حتی اگه هر دو با اختلاف زمانی یک میلیاردم ثانیه با هم بخوان ثبت بشن!


1- درباره Transaction : من تا حالا از Transaction استفاده نکردم پس اطلاعات کاربردی  به درد بخوری دربارش ندارم .. اگه لطف کنید و بیشتر درباره ایجاد Transaction  و مفاهیم مربوطه توضیح بدید ممنون میشم .
(انشاالله بتونم در برنامه های بعدی ازش استفاده کنم)

2- اینکه شما گفتی :



> به نظر من بهترین راه حل اینه که تمام عملیات تایپ و اصلاح نامه انجام بشه و درنهایت وقتی که ذخیره شد، شماره رو برگردونه.


حتما در پیاده سازیم اعمال میکنم .. 

3-



> (برای فیلد آیدنتیتی(Auto Increment) در SQL Server اینکار با SELECT @@IDENTITY امکان پذیره)


من با یک کویری آخرین شماره ای که بنام کاربر درخواست دهنده در جدول موجود است را برمیگردانم و فکر میکنم درست عمل کنه...
(به بیان ساده : منظور شما را متوجه نشدم )

با تشکر ..

----------


## Mah6447

*یک مشکل دیگری که در پاسخ های اساتید می باشد این است که در سیستم های نامه نگاری نیاز است که شروع هر سال شماره نامه ها از 1 شروع شود حال اینکه در فیلدهایی از نوع  Auto Increment این عمل به نظر غیر ممکن می باشد .*

----------


## ehsane

[quet]
من با یک کویری آخرین شماره ای که بنام کاربر درخواست دهنده در جدول موجود است را برمیگردانم و فکر میکنم درست عمل کنه...
[quet/]
دوست عزیز اگر تعداد رکوردهای شما زیاد باشد مثلا 20000 یا 50000 آنوقت هر دفعه شما با کوئری این تعداد را در حافظه لود می کنید. مشکل سرعت برای شما پیش نمی آد

----------


## Valadi

اکر دیتا بیس اکسس باشد بعد از 150000 فیلد سرعت کم می شود و طبیعتا سرعت برنامه هم کم می شود

----------


## Valadi

> *یک مشکل دیگری که در پاسخ های اساتید می باشد این است که در سیستم های نامه نگاری نیاز است که شروع هر سال شماره نامه ها از 1 شروع شود حال اینکه در فیلدهایی از نوع  Auto Increment این عمل به نظر غیر ممکن می باشد .*


اینکه مشکلی نیست خیلی راحت می شه این مسئله را حل کرد اما مسیر یک مقدار پیچیده است

----------


## www2006

> اکر دیتا بیس اکسس باشد بعد از 150000 فیلد سرعت کم می شود و طبیعتا سرعت برنامه هم کم می شود


بانک من SQLServer است ... فکر نمیکنم مشکل پیش بیاد
البته کویری گرفتن اجتناب نپذیره ( منظورم این مورد نیست ، کلا تو برنامه از  کویری های مختلفی استفاده میکنم ..




> اینکه مشکلی نیست خیلی راحت می شه این مسئله را حل کرد اما مسیر یک مقدار پیچیده است


ولی تا اونجایی که من میدونم فیلد Identity را نمیشه به هیچ وجه دستکاری کرد ...

----------


## Valadi

جناب www2006 این از یک راه دیگری است و ربطی هم به فیلد Identity  ندارد از همین ترفند در نرم افزارهای حسابداری که قابلیت تعریف سال کاری دارد استفاده شده است

----------


## www2006

> جناب www2006 این از یک راه دیگری است و ربطی هم به فیلد Identity  ندارد از همین ترفند در نرم افزارهای حسابداری که قابلیت تعریف سال کاری دارد استفاده شده است


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

----------


## ehsane

دوست عزیز اگه منظور شما از تغییر در فیلد Identity صفر کردن آن است شما میتوانید با استفاده از این دستور براحتی میتونید این کار رو را انجام بدید. قبلا دوستان به این موضوع اشاره کردند.
DBCC CHECKIDENT (table1, RESEED, 30)

----------

