ładowanie plików do bazy danych

0

Witam!

Mam tabele w swojej bazie danych, gdzie jest kolumna typu image, i chciałbym się dowiedzieć jak zrobic aby załadować obrazek, lub ewentualnie plik PDF do tabeli z rekordami które posiadają taką kolumnę. Jak to obsłużyć, czy kolumna powinna być typu image czy np. tekst i na podstawie wpisanych danych do tej kolumny wyszukiwać i ładowac bezpośrednio te pliki na jakis dysk, aczkolwiek, docelowo aplikacja ma się łączyć z bazą przez internet, tak że lepiej pliki było by wczytac bezpośrednio do bazy żeby nie było problemów z przechowywaniem oddzielnie samych plików? Jest jeszcze kwestia samego wyswietlania, i podglądu tych plików w DataGrid'zie(myslałem o kolumnie z przyciskami odwołującymi się do ściągnięcia albo podglądu pliku, przy danym rekordzie). Macie jakieś pomysły jak to zrobić? Moze ktoś z was robił już coś takiego, i mógł by się podzielić tak ową wiedzą?

Pozdrawiam :)

0

Nie napisałeś (albo ja nie widzę) jaki to typ aplikacji, ani jak łączysz się z bazą, ani nawet jaka to baza.

Ogólnie musisz po stronie aplikacji odczytać ten plik do tablicy bajtów, następnie wysłać do bazy (w zależności od tego jak się z bazą łączysz). W bazie będziesz miał np. tabelę z kolumnami Id (int/guid), Name (*varchar) i Data (binary/image), więc pobierał będziesz np. Data na podstawie Id.

0

Już poprawiam swój bład. Aplikacja Windows Forms w C# łącząca się z bazą danych MS SQL za pomocą LINQ i EntityFramework. Baza jest na razie lokalnie ale docelowo będzie umieszczona na jakimś serwerze, aby była mozliwość użycia aplikacji przez wielu uzytkowników w jednym czasie.

0

To jeszcze jest coś niejasne, czy wyjaśnienie ogólne Ci wystarcza?

0

Generalnie wiem juz o co chodzi, gorzej z zakodowaniem tego. :/ Do tej pory wymysliłem coś takiego:

private byte[] skanDok = new byte[byte.MaxValue];

...

private void buttonPrzegladaj_Click(object sender, EventArgs e)
{
openFileDialogSkanDokuemntu.ShowDialog();
for (int i = 0; i <= skanDok.Length; i++)
{
skanDok[i] = Byte.Parse(openFileDialogSkanDokuemntu.FileName);
}

}

aczkolwiek nie wiem czy moje myslenie idzie w dobrym kierunku, bo raz że ta tablica musi wywędrować do bazy danych, a dwa że z innej formatki muszę miec dostęp do ściągnięcia całego dokumentu, ewentualnie sam podgląd.

Natomiast, jeśli macie inne pomysły to bardzo chętnie je rozważe, bo być może będą to lepsze koncepcje od mojej. Moja koncepcja to jeedna formatka do wczytywania plików i edytowania innych kolumn tabeli i druga formatka do wyświetlania danych tabeli a w kolumnie, która jest typu image do przechowywania obrazków bądź plików .pdf przyciski prowadzące do podglądu tegoż pliku, przypisanego do danego rekordu.

0

Twoje myślenie idzie w totalnie błędnym kierunku.

Po pierwsze jak korzystamy z dialogów. Okna dialogowe (metoda ShowDialog()) zwracają DialogResult. Na podstawie tej wartości odgadujemy co użytkownik zrobił, bo zazwyczaj zamknięcie okna to wynik kliknięcia jakiegoś przycisku, bez względu na to co wpisał w jakieś pola tekstowe etc. decyduje właśnie to który przycisk kliknął (OK, Anuluj, Wstecz, Następny). Więc twoje wywołanie dialogu wyboru pliku powinno wyglądać tak:

if (openFileDialogSkanDokuemntu.ShowDialog() == DialogResult.OK)
{
... // tu należy wykonać akcję, w innym przypadku użytkownik wybrał Anuluj lub [X], co nie znaczy że właściwość FileName jest pusta, więc poleganie na niej jest BŁĘDEM!
}

Nie wiem po co tworzysz tablicę wielkości 255 bajtów (skanDok), bo byte.MaxValue = 255.

skanDok[i] = Byte.Parse(openFileDialogSkanDokuemntu.FileName);

To też jest jakąś totalną głupotą. Nie wiem co chciałeś osiągnąć, ale metoda Parse, parsuje string do byte. Byte to nic innego jak liczba całkowita od 0 do 255, więc sparsować poprawnie można "0", "25", "127", "231", ...
To nie jest metoda przekształcania pliku do tablicy bajtów jak napisał ci somekind.

Jak powinno to być zrobione poprawnie?
Jeśli dialog otwarcia pliku został zatwierdzony OK, pobierasz nazwę pliku z właściwości FileName i albo zapamiętujesz w jakimś polu, a plik otwierasz w miejscu gdzie ci potrzeba, albo od razu otwierasz plik, co można zrobic od razu za pomocą metody OpenFileDialog.OpenFile().
Czytanie pliku.
Dostajesz strumień. M.in. ma on właściwość Length i o takiej długości musisz utworzyć sobie tablicę byte, do której wczytasz plik. Po wczytaniu pliku do tablicy zamykasz strumień. Masz już gotową tablicę byte, aby wstawić ją do bazy.
Jeśli plik otworzysz do czytania jako tekstowy (np. za pomocą System.IO.File.OpenText()/OpenRead()) i dostaniesz StreamReader (czy coś z TextReader) to musisz przeczytać zawartość pliku do string, a później przy użyciu odpowiedniego Encoding przekształcić go do tablicy byte.

0

Ok, wielkie dzieki za naprowadzenie mnie na odpowiedni tok myślenia. Z drugiej strony to co poprzednio napisałem to muszą byc kompletne bzdury. Kierując się wskazówkami(nie jestem tylko pewny czy wkładanie tablicy typu byte do bazy jest dobrze, czy powinienem jednak wsadzać plik do tabeli bazy danych za pomocą zapytania SQL, a co za tym idzie tworzenia oddzielnego połączenia z bazą danych itp itd), napisałem cos takiego:

private void buttonPrzegladaj_Click(object sender, EventArgs e)
        {
            openFileDialogSkanDokuemntu.ShowDialog();
            if (openFileDialogSkanDokuemntu.ShowDialog() == DialogResult.OK)
            {
                FileInfo daneWczytywanegoPliku = new FileInfo(openFileDialogSkanDokuemntu.FileName);
                FileStream strumienWczytywaniaPliku = new FileStream(sciezkaDokumentu, FileMode.Open, FileAccess.Read);
                BinaryReader wczytywanieBinariow = new BinaryReader(strumienWczytywaniaPliku);
                byte[] skanDok = new byte[daneWczytywanegoPliku.Length];

                nazwaDokumentu = daneWczytywanegoPliku.FullName;
                sciezkaDokumentu = daneWczytywanegoPliku.ToString();
                skanDok = wczytywanieBinariow.ReadBytes((int)daneWczytywanegoPliku.Length);

                Badania badanie = new Badania();    //deklaracja tabeli w bazie danych
                badanie.skanDokumentu = skanDok;  //przypisanie tablicy typu byte do odpowiedniego pola o nazwie 'skanDokumentu' w bazie danych
            }
            else
            {
                MessageBox.Show("Plik nie został wczytany do bazy! Spróbuj ponownie.");
            }
            
        }

W całym projekcie posługuje się zapytaniami Linq, Lambda i generalnie wszystko co tyczy się bazy danych jest robione z pomocą EntityFramework, dlatego tez wpisywanie danych do bazy, czy tez ustawianie BindingSource'ów to dwie odrębne funkcje.

0
  1. po co dwa razy pokazujesz OpenFileDialog?
  2. jak ty otwierasz plik? sciezkaDokumentu ustawiasz dopiero kilka linijek niżej.
  3. po co ci BinaryReader? FileStream jest jak najbardziej wystarczający
  4. zamknij strumienie po przeczytaniu pliku
  5. zapisz do bazy - musisz ObjectContext utworzyć i normalnie dodać czy zaktualizować rekord (obiekt)
0
private void buttonPrzegladaj_Click(object sender, EventArgs e)
        {
            if (openFileDialogSkanDokuemntu.ShowDialog() == DialogResult.OK)
            {
                FileInfo daneWczytywanegoPliku = new FileInfo(openFileDialogSkanDokuemntu.FileName);
                byte[] skanDok = new byte[daneWczytywanegoPliku.Length];
                nazwaDokumentu = daneWczytywanegoPliku.FullName;
                sciezkaWejDokumentu = daneWczytywanegoPliku.ToString();
                rozmiarDokumentu = int.Parse(daneWczytywanegoPliku.Length.ToString());

                FileStream strumienWczytywaniaPliku = new FileStream(sciezkaWejDokumentu, FileMode.Open, FileAccess.Read);
                while (rozmiarDokumentu > 0)
                {
                    int n = strumienWczytywaniaPliku.Read(skanDok, rozmiarPrzeczytanychDanych, rozmiarDokumentu);
                    if (n == 0) break;

                    rozmiarPrzeczytanychDanych += n;
                    rozmiarDokumentu -= n;
                }
                rozmiarDokumentu = skanDok.Length;

                FileStream strumienNowegoPlikDoBazy = new FileStream(sciezkaWyjDokumentu, FileMode.Create, FileAccess.Write);
                strumienNowegoPlikDoBazy.Write(skanDok, 0, rozmiarDokumentu);
            }
            else
            {
                MessageBox.Show("Plik nie został wczytany do bazy! Spróbuj ponownie.");
            }
            
        }

Tak wygląda mój aktualny kod. W tej chwili mam gotową tablice typu byte, do umieszczenia w bazie. Musze jednakskonwertować ją do typu string żeby trafiła do bazy, tak? Zwykła metoda Parse to chyba nie to czego mi potrzeba?

ObjectContext potrzebuje zmiennej Entity i plik który chce dodać do bazy w postaci typu byte, który już mam. Czy automatycznie ten sam plik trafi do odpowiedniego pola w tabeli bazy danych czy coś trzeba jeszcze zrobić?

0

jeju, za to

int.Parse(daneWczytywanegoPliku.Length.ToString());

to chyba ze 20 batów powinno być
jeśli juz to

(int)daneWczytywanegoPliku.Length

do czego ci strumienNowegoPlikDoBazy? przecież chcesz do bazy wsadzić plik, a nie zapisać w innej lokalizacji
tworzysz odpowiednie entity, które dla kolumny typu image w bazie zdaje się że powinno być poo stronie .net byte[], ale już od pewnego czasu nie tykałem EF więc nie pamiętam

0
if (openFileDialogSkanDokuemntu.ShowDialog() == DialogResult.OK)
            {
                FileInfo daneWczytywanegoPliku = new FileInfo(openFileDialogSkanDokuemntu.FileName);
                byte[] skanDok = new byte[daneWczytywanegoPliku.Length];
                nazwaDokumentu = daneWczytywanegoPliku.FullName;
                sciezkaWejDokumentu = daneWczytywanegoPliku.ToString();
                rozmiarDokumentu = (int)daneWczytywanegoPliku.Length;

                FileStream strumienWczytywaniaPliku = new FileStream(sciezkaWejDokumentu, FileMode.Open, FileAccess.Read);
                while (rozmiarDokumentu > 0)
                {
                    int n = strumienWczytywaniaPliku.Read(skanDok, rozmiarPrzeczytanychDanych, rozmiarDokumentu);
                    if (n == 0) break;

                    rozmiarPrzeczytanychDanych += n;
                    rozmiarDokumentu -= n;
                }
                rozmiarDokumentu = skanDok.Length;
                
                int idSkanu = int.Parse(textBoxNumerBadania.Text);

                EntityConnection conn = new EntityConnection("name=BudSystemEntities");
                BudSystemEntities context = new BudSystemEntities(conn);

                if (conn.State != ConnectionState.Open) conn.Open();

                Badania skan = context.Badania.Where("skanDokumentu = @idSkanu", new ObjectParameter("idSkanu", idSkanu)).Execute(MergeOption.AppendOnly).First();
                context.SaveChanges();

                //ObjectContext wczytaniePlikuDoBazy = new ObjectContext("name=BudSystemEntities");
                //wczytaniePlikuDoBazy.DefaultContainerName = "BudSystemEntities";

                labelKomunikatOPliku.Text = "PLIK WCZYTANY";
            }
            else
            {
                MessageBox.Show("Plik nie został wczytany do bazy! Spróbuj ponownie.");
            }
        }

Ok,

Parse
wyrzucone już. Czy w takim razie cos takiego ma sens? ObjectContext nie obsługuje wrzucania tablicy typu byte do pola typu varbinary tylko image, a do pola typu varbinary chcę wczytywać te pliki. Zrobiłem to tak jak było napisane w MSDN.

0

Wiem że trzeba otworzyć strumień, nastepnie przeczytac cały plik do strumienia, wcześniej zapisac jakieś dodatkowe metadane, zamknąć strumień, zapisany plik do tablicy byte wsadzić do bazy, ale "no własnie" jak to zrobić??

Próbowałem przez ObjectContext ale ni jak mi to nie wychodziło. Mój kod wygląda nastepująco:

if (openFileDialogSkanDokuemntu.ShowDialog() == DialogResult.OK)
            {
                FileInfo daneWczytywanegoPliku = new FileInfo(openFileDialogSkanDokuemntu.FileName);
                byte[] skanDok = new byte[daneWczytywanegoPliku.Length];
                nazwaDokumentu = daneWczytywanegoPliku.FullName;
                sciezkaDokumentu = daneWczytywanegoPliku.ToString();
                rozmiarDokumentu = (int)daneWczytywanegoPliku.Length;

                FileStream strumienWczytywaniaPliku = new FileStream(sciezkaDokumentu, FileMode.Open, FileAccess.Read);
                while (rozmiarDokumentu > 0)
                {
                    int n = strumienWczytywaniaPliku.Read(skanDok, rozmiarPrzeczytanychDanych, rozmiarDokumentu);
                    if (n == 0) break;

                    rozmiarPrzeczytanychDanych += n;
                    rozmiarDokumentu -= n;
                }
                rozmiarDokumentu = skanDok.Length;

                //??kod realizujący ładowanie tablicy byte z plikiem do bazy danych??

                labelKomunikatOPliku.Text = "PLIK WCZYTANY";
            }
            else
            {
                MessageBox.Show("Plik nie został wczytany do bazy! Spróbuj ponownie.");
            }

i w dalszym ciągu nie potrafie tego rozgryźć.

Może ktoś z was ma jakiś pomysł? Za wszelką pomoc będe bardzo wdzięczny, bo ja już powoli kapituluje przy tym :/

0

Po wielu godzinach spędzonych na poszukiwaniach odpowiedniego rozwiązania, skleciłem cos takiego:

Badania badanie = new Badania();

            wpiszDaneDoBazy(badanie);
            bazaBudSystem.AddToBadania(badanie);
            bazaBudSystem.SaveChanges();

            if (openFileDialogSkanDokuemntu.ShowDialog() == DialogResult.OK)
            {
                FileInfo daneWczytywanegoPliku = new FileInfo(openFileDialogSkanDokuemntu.FileName);
                byte[] skanDok = new byte[daneWczytywanegoPliku.Length];
                nazwaDok = daneWczytywanegoPliku.FullName;
                sciezkaDokumentu = daneWczytywanegoPliku.ToString();
                rozmiarDokumentu = (int)daneWczytywanegoPliku.Length;

                FileStream strumienWczytywaniaPliku = new FileStream(sciezkaDokumentu, FileMode.Open, FileAccess.Read);
                while (rozmiarDokumentu > 0)
                {
                    int n = strumienWczytywaniaPliku.Read(skanDok, rozmiarPrzeczytanychDanych, rozmiarDokumentu);
                    if (n == 0) break;

                    rozmiarPrzeczytanychDanych += n;
                    rozmiarDokumentu -= n;
                }
                rozmiarDokumentu = skanDok.Length;

                SqlConnection polaczenie = new SqlConnection("Data Source=SZYMON-DELL;Initial Catalog=BudSystem;Integrated Security=True;");
                string zapytanieInsert = "UPDATE Badania (nazwaDokumentu, skanDokumentu) VALUES(@Name, @ImageData)";
                SqlCommand zapytanie = new SqlCommand(zapytanieInsert, polaczenie);
                zapytanie.Parameters.AddWithValue("@Name", nazwaDok);
                zapytanie.Parameters.AddWithValue("@ImageData", skanDok);
                try
                {
                    polaczenie.Open();
                    zapytanie.ExecuteNonQuery();
                }
                finally
                {
                    polaczenie.Close();
                    labelKomunikatOPliku.Text = "PLIK WCZYTANY";
                }
            }
            else
            {
                MessageBox.Show("Plik nie został wczytany do bazy! Spróbuj ponownie.");
            }

Tabela do której chce wstawić ten plik, posiada również inne pola, które uzupełniam w funkcji wpiszDaneDoBazy(), a ten kod który umiesciłem wyzej jest podpięty do przycisku Przeglądaj na formatce. Z racji użycia zapytania z klauzulą UPDATE przeniosłem tworzenie i obsługę obiektu badanie, jak i uzupełnienie innych pól przez wcześniej zdefiniowaną funkcje wpiszDaneDoBazy() tutaj, gdyż w jednej tabeli mam kilka kolumn m.in. skanDokumentu i nazwaDokumentu które uzupełniam zapytaniem, reszta pól jest uzupełniana przez Linq2SQL(EF) w funkcji wpiszDaneDoBazy(), ale, no właśnie, w dalszym ciągu takie rozwiązanie nie działa.

Pola skanDokumentu i nazwaDokumentunullable, gdyż są, albo mają być uzupełniane później przez zapytanie UPDATE. W tej chwili rekordy są dodawane, ale mimo to pola skanDokumentu i nazwaDokumentu pozostają null'ami a kompilator wywala linijkę:

zapytanie.ExecuteNonQuery();

wyjątkiem, który "nie został obsłużony" SQLException - komunikat Incorrect syntax error near "("

0

byte[] bytes = File.ReadAllBytes("C:\plik.txt");

1 użytkowników online, w tym zalogowanych: 0, gości: 1