Модераторы: gambit, Partizan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Хранение Date в Int, помогите реализовать 
:(
    Опции темы
IApple
Дата 22.7.2008, 12:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 17.1.2008

Репутация: нет
Всего: нет



Помогите реализовать идею (не хватает знаний осилить самостоятельно).

Идея: хранить дату (без времени!) в БД на MS SQL (версии до 2008) в поле типа Int (поддержка значений NULL тоже необходима).
Преимущества: - размер и быстродействие (индекс/поиск по Int явно быстрее, чем по дате-времени, которое "внутре" клон действительного числа), возможность использовать = в селектах (для выборки всех дататайм конкретного дня нужно либо "обрезать" время, либо использовать BETWEEN).

В MS SQL преобразования:
Код

-- из даты @DT в Int:    
DateDiff( day, '', @DT )
-- из Int @N  в дату:    
DateAdd( day, @N, '' )


В C# преобразования:
Код

// если задана константа в классе Program
static public DateTime MyZeroDate = new DateTime(1900, 01, 01);

// из DateTime DT в Int:    
DT.Subtract(Program.MyZeroDate).Days;

// из Int N  в DateTime:    
Program.MyZeroDate.AddDays(N);


Недостатки окажутся минимальными, если добиться (вот в этом и заключаются задачи):

1) визуализации такого Int в DataGridView в виде даты (вернее строки по заданому формату, как для дат), помогите создать соответствующего наследника от DataGridViewTextBoxColumn;

2) переделка DateTimePicker (вернее NullableDateTimePicker), чтоб можно было такой компонент напрямую биндить на Int-колонку таблицы, для редактирования.

Код пикера для передоделки:
Код

using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Globalization;
using System.Threading;


namespace xxx
{
    [System.Drawing.ToolboxBitmap(typeof(System.Windows.Forms.DateTimePicker))]
    public class NullableDateTimePicker : DateTimePicker
    {
        public NullableDateTimePicker()
            : base()
        {
            base.Format = DateTimePickerFormat.Custom;
            NullValue = " ";
            this.Format = DateTimePickerFormat.Short;
            this.DataBindings.CollectionChanged += new CollectionChangeEventHandler(DataBindings_CollectionChanged);
        }

        // true, when no date shall be displayed (empty DateTimePicker)
        private bool _isNull;

        // If _isNull = true, this value is shown in the DTP
        private string _nullValue;

        // The format of the DateTimePicker control
        private DateTimePickerFormat _format = DateTimePickerFormat.Short;

        // The custom format of the DateTimePicker control
        private string _customFormat;

        // The format of the DateTimePicker control as string
        private string _formatAsString;

        public new String CustomFormat
        {
            get { return _customFormat; }
            set { _customFormat = value; }
        }

        public new DateTimePickerFormat Format
        {
            get { return _format; }
            set
            {
                _format = value;
                if (!_isNull) SetFormat();
                OnFormatChanged(EventArgs.Empty);
            }
        }
        private void SetFormat()
        {
            CultureInfo ci = Thread.CurrentThread.CurrentCulture;
            DateTimeFormatInfo dtf = ci.DateTimeFormat;
            switch (_format)
            {
                case DateTimePickerFormat.Long:
                    FormatAsString = dtf.LongDatePattern;
                    break;
                case DateTimePickerFormat.Short:
                    FormatAsString = dtf.ShortDatePattern;
                    break;
                case DateTimePickerFormat.Time:
                    FormatAsString = dtf.ShortTimePattern;
                    break;
                case DateTimePickerFormat.Custom:
                    FormatAsString = this.CustomFormat;
                    break;
            }
        }
        private string FormatAsString
        {
            get { return _formatAsString; }
            set
            {
                _formatAsString = value;
                base.CustomFormat = value;
            }
        }
        public new DateTime? Value
        {
            get
            {
                if (_isNull)
                    return null;
                else
                    return base.Value;
            }
            set
            {
                if (value == null)
                {
                    SetToNullValue();
                }
                else
                {
                    SetToDateTimeValue();
                    base.Value = (DateTime)value;
                }
            }
        }

        private void SetToDateTimeValue()
        {
            if (_isNull)
            {
                SetFormat();
                _isNull = false;
                base.OnValueChanged(new EventArgs());
            }
        }
        private void SetToNullValue()
        {
            _isNull = true;
            base.CustomFormat = (_nullValue == null || _nullValue == String.Empty)
                                ? " " : "'" + NullValue + "'";
            base.OnValueChanged(new EventArgs()); // IPY added
        }

        public String NullValue
        {
            get { return _nullValue; }
            set { _nullValue = value; }
        }
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x4e)                         // WM_NOTIFY
            {
                NMHDR nm = (NMHDR)m.GetLParam(typeof(NMHDR));
                if (nm.Code == -746 || nm.Code == -722)  // DTN_CLOSEUP || DTN_?
                    SetToDateTimeValue();
            }
            base.WndProc(ref m);
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct NMHDR
        {
            public IntPtr HwndFrom;
            public int IdFrom;
            public int Code;
        }
        protected override void OnKeyUp(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                this.SetToNullValue();
                this.OnValueChanged(EventArgs.Empty);
            }
            base.OnKeyUp(e);
        }

        private void DataBindings_CollectionChanged(object sender, CollectionChangeEventArgs e)
        {
            if (e.Action == CollectionChangeAction.Add)
                this.DataBindings[this.DataBindings.Count - 1].Parse +=
                       new ConvertEventHandler(NullableDateTimePicker_Parse);
        }

        private void NullableDateTimePicker_Parse(object sender, ConvertEventArgs e)
        {
            //saves null values to the object
            if (_isNull)
                e.Value = DBNull.Value; // for binding data outside
        }

        // ========================================
        // This member overrides Control.OnKeyPress
        //
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            if (this.Value == null)
            {
                Char chr = e.KeyChar;
                if (Char.IsNumber(e.KeyChar))
                {
                    // Set the Value to todays date
                    this.Value = DateTime.Now;
                    // The following two lines forces the 
                    // focus from the hidden checkbox to the month field
                    if (!this.ShowCheckBox)
                    {
                        this.ShowCheckBox = true;
                        this.ShowCheckBox = false;
                    }
                    // Resend the key pressed
                    SendKeys.Send(chr.ToString());
                }
            }
            base.OnKeyPress(e);
        } // end OnKeyPress
    }
}

PM MAIL   Вверх
PashaPash
Дата 22.7.2008, 14:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: нет
Всего: 49



Цитата(IApple @  22.7.2008,  12:17 Найти цитируемый пост)
Преимущества: - размер и быстродействие (индекс/поиск по Int явно быстрее, чем по дате-времени, которое "внутре" клон действительного числа)

Values with the datetime data type are stored internally by the SQL Server 2005 Database Engine as two 4-byte integers. The first 4 bytes store the number of days before or after the base date: January 1, 1900....The Database Engine stores smalldatetime values as two 2-byte integers. The first 2 bytes store the number of days after January 1, 1900. Поэтому поиск по дате будет явно не медленее, чем поиск по int. 
Цитата(IApple @  22.7.2008,  12:17 Найти цитируемый пост)
возможность использовать = в селектах (для выборки всех дататайм конкретного дня нужно либо "обрезать" время, либо использовать BETWEEN).
Если все значения в столбце уже урезаны до "date only", и ищешь ты по значению "date only", от никто не мешает тебе использовать обычное =. Это решается средствами одного orm/data layer, а не глобальной перепиской всего подряд, от базы до presentation.


--------------------
PM MAIL WWW   Вверх
IApple
Дата 22.7.2008, 16:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 17.1.2008

Репутация: нет
Всего: нет



Цитата(PashaPash Дата 22.7.2008 @  14:58)

...Database Engine as two 4-byte integers... stores smalldatetime values as two 2-byte integers...

т.е индекс по ДВУМ интежерам и по ОДНОМУ - это одно и то же ?

Цитата(PashaPash Дата 22.7.2008 @  14:58)

Если все значения в столбце уже урезаны до "date only", и ищешь ты по значению "date only", от никто не мешает тебе использовать обычное =. Это решается средствами одного orm/data layer, а не глобальной перепиской всего подряд, от базы до presentation.


Вот именно, что ЕСЛИ уже урезаны до "date only", а если не урезаны, то надобно урезать "средствами одного orm/data layer"...
Покажите пример реализации этого "средства", плиз.
Глобальной переписки базы я не просил, а как раз только presentation  int-а в датагриде, чтоб "выглядел", как дата. Именно в этом я просил помощи.

Это сообщение отредактировал(а) IApple - 22.7.2008, 16:41
PM MAIL   Вверх
1stain
Дата 22.7.2008, 17:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 486
Регистрация: 30.7.2007
Где: Киев - Харьков

Репутация: 4
Всего: 40



По-моему, единственный смысл хранить DateTime в базе в виде числа - избавиться от потери точности (MS SQL datetime менее точный чем .NET DateTime). При этом хранить сабж надо в виде bigint. Писать в базу и читать обратно можно примерно так:
Код

 class Program
    {
        static void Main(string[] args)
        {
            const string ReadSqlString = "SELECT DateCreated from dbo.Table1 where ID = @Id";
            const string UpdateSqlString = "UPDATE dbo.Table1 SET DateCreated = @dateCreated WHERE ID = @Id";

            const string ConnectionString = "connectionString";

            MyClass mc = new MyClass();

            // reading from database
            using (SqlConnection connection = new SqlConnection(ConnectionString))
            {
                SqlCommand readCommand = new SqlCommand(ReadSqlString, connection);
                readCommand.Parameters.AddWithValue("@Id", mc.Id);
                connection.Open();
                using (SqlDataReader reader = readCommand.ExecuteReader())
                {
                    if (reader.Read())
                    {
                        mc.Date = reader["DateCreated"] == DBNull.Value ? null : (DateTime?)DateTime.FromBinary((long)reader["DateCreated"]); 
                    }
                } 
            }

            // writing to database
            using (SqlConnection connection = new SqlConnection(ConnectionString))
            {
                SqlCommand writeCommand = new SqlCommand(UpdateSqlString, connection);
                writeCommand.Parameters.AddWithValue("@Id", mc.Id);
                writeCommand.Parameters.AddWithValue("@dateCreated", mc.Date == null ? (object)DBNull.Value : mc.Date.Value.Ticks);
                connection.Open();
                writeCommand.ExecuteNonQuery();
            }
        }
    }

    public sealed class MyClass
    {
        public long Id { get; set; }
        public DateTime? Date { get; set; }
    }


Сделать nullable DateTimePicker на мой взгляд, проще всего создав юзерконтрол с таким кодом:
Код

public partial class NullableDateTimePicker : UserControl
    {
        public NullableDateTimePicker()
        {
            InitializeComponent();

            this.dateTimePicker.Format = DateTimePickerFormat.Custom;
            this.CustomFormat = "yyyy-MM-dd HH:mm:ss";
        }

        private void dateTimePicker_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                ((DateTimePicker)sender).CustomFormat = " ";
            }
            else
            {
                ((DateTimePicker)sender).CustomFormat = this.CustomFormat;
            }
        }

        private void dateTimePicker_ValueChanged(object sender, EventArgs e)
        {
            ((DateTimePicker)sender).CustomFormat = this.CustomFormat;
        }

        /// <summary>
        /// Gets or sets the date/time value assigned to the control.
        /// </summary>
        public DateTime? Value
        {
            get
            {
                if (this.dateTimePicker.CustomFormat == " " )
                {
                    return null;
                }
                else
                {
                    return this.dateTimePicker.Value;
                }
            }
            set
            {
                if (value == null)
                {
                    this.dateTimePicker.CustomFormat = " ";
                }
                else
                {
                    this.dateTimePicker.CustomFormat = this.CustomFormat;
                    this.dateTimePicker.Value = value.Value;
                }
            }
        }

        public string CustomFormat { get; set; }
    }



--------------------
Все знают, что это невозможно. Но вот приходит невежда, которому это неизвестно - он-то и делает открытие. (Albert Einstein)
user posted image
PM MAIL   Вверх
PashaPash
Дата 22.7.2008, 17:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: нет
Всего: 49



Цитата(IApple @  22.7.2008,  16:38 Найти цитируемый пост)
т.е индекс по ДВУМ интежерам и по ОДНОМУ - это одно и то же ?
Индекс по одному полю длиной 4 байта (smalldatetime) и integer полю длиной 4 байта - да, одно и то же. То же поле, те же операции сравнения, только называется по-другому.
Цитата(IApple @  22.7.2008,  16:38 Найти цитируемый пост)
Вот именно, что ЕСЛИ уже урезаны до "date only", а если не урезаны, то надобно урезать "средствами одного orm/data layer"...
Покажите пример реализации этого "средства", плиз.
Триггеры на insert/update. Или явное преобразование в Data Layer (как 1stain предложил, только с другой целью). Или OnPropertyChanged обьектов домена. Или просто календарь с переопределенным Value. Все проще, чем вместо дат целые числа по всему приложению передавать, и только показывать их как даты. Очень, наверное, удобно отлаживать код, в котором сегодня - это 733244.


--------------------
PM MAIL WWW   Вверх
IApple
Дата 23.7.2008, 10:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 36
Регистрация: 17.1.2008

Репутация: нет
Всего: нет



Цитата(1stain @ 22.7.2008,  17:02)
 ... mc.Date == null ? (object)DBNull.Value : mc.Date.Value.Ticks...

какие Ticks? для хранения ДНЯ не нужен тик, нужен ДЕНЬ.

Но вопрос совсем не в том был, как читать или писать в ВБ int, подменяя на ходу на DateTime - это я как раз умею. Помощь нужна в другом совсем !!! Я хочу, чтоб читалось/писалось и в таблице как на сервере, так и в датасете только Int.

Упрощенно наново сформулирую чего я хочу добиться и в чем именно нужна подмога:

1) мне нужно добиться, чтоб грид, забинденый на таблицу в датасете, в которой есть колонка с данными типа INT, эту колонку ПОКАЗЫВАЛ в виде даты. Нужны, наверное, наследники от DataGridViewTextBoxColumn и/или от DataGridViewTextBoxCell, которые будут показывать хранимое в них (или прибинденое) значение типа Int в виде даты. Для редактирования на отдельной форме будет нужен дататаймпикер из п.2, а для редактирования в гриде, компонент, от него наследованиый.

2) к дататаймпикеру (я полный его код представил сам) и который работает и можно на его свойство Value (c типом DateTime) прибиндить колонку типа дататайм, "прикрутить" еще (или вместо) свойство с типом Int, к которому можно было б напрямую прибиндить Int колонку таблицы (в которой подразумевается дата).

Цитата(PashaPash)

Триггеры на insert/update. Или явное преобразование в Data Layer (как 1stain предложил, только с другой целью). Или OnPropertyChanged обьектов домена. 

 
Вот именно триггеры на insert/update для каждой таблицы с датой (ну это около половины всех моих таблиц в БД) мне трудно.

Цитата(PashaPash)

Или просто календарь с переопределенным Value. Все проще, чем вместо дат целые числа по всему приложению передавать, и только показывать их как даты.


Вот именно это мне нужно !!! помогите создать календарь с переопределенным Value (это ж и есть мой п.2)
Вопрос что легче, задавать кучу тригеров или передавать по всему приложению целые числа зависит от человека. Вам легче с тригерами. Мне легче "передавать". Помогите в том, в чем прошу, а не убеждайте меня в моей глупости, плиз.

Это сообщение отредактировал(а) IApple - 23.7.2008, 10:08
PM MAIL   Вверх
jonie
Дата 23.7.2008, 21:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 5
Всего: 118



на сугубо мой взгляд вы занимаетесь преждевременной оптимизацией
Цитата

2) к дататаймпикеру (я полный его код представил сам) и который работает и можно на его свойство Value (c типом DateTime) прибиндить колонку типа дататайм, "прикрутить" еще (или вместо) свойство с типом Int, к которому можно было б напрямую прибиндить Int колонку таблицы (в которой подразумевается дата).
ну вот набросал такой код.. работает... только зачем хз
Код

  // this is a BAD code.
    public class DateTimePickerInt : DateTimePicker
    {
        public new long Value
        {
            set
            {
                base.Value = new DateTime(value);
            }
            get
            {
                return base.Value.Ticks;
            }
        }
    }

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            dateTimePickerInt1.DataBindings.Add(new System.Windows.Forms.Binding("Value", this.dataSet11, "DataTable1.mydate", true));
            this.dateTimePickerInt1.Value = ((long)(633004489484687500));
        }

        private void button1_Click(object sender, EventArgs e)
        {
            dataSet11.DataTable1.Rows.Add(633524489794687500);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            MessageBox.Show(dateTimePickerInt1.Value.ToString());
        }
    }

ну тут тики, но думаю суть должна быть ясна...
чем там проблемы?
-----------------------------


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Разработка Windows Forms | Следующая тема »


 




[ Время генерации скрипта: 0.0770 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.