SignalR + EF - automatyczne pobieranie swiezych danych z DB

Odpowiedz Nowy wątek
2014-12-16 14:24
ne0
0

Hej,

Znalazlem całkiem spoko kursik jak zrobić notyfikacje SignalR z bazy danych: http://venkatbaggu.com/signal[...]et-mvc-usiing-sql-dependency/

Chciałbym teraz trochę to pozmieniać i użyć LINQ i podejścia DB first czyli wygenerować ten Model EDMX. Zrobiłem to, mogę robić zapytania i dostaję wynik. Jednak nie działa mi automatyczne odświerzanie jeśli w bazie się coś nowego pojawi...

W tym kodzie mam takiego coś:

  private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
        {
            if (e.Type == SqlNotificationType.Change)
            {
                MessageHub.SendMessages();
            }
        }

i jest to wywołane w metodzie GetAllMessages w MessageRepository. Nie umiem tego zastosować aby działało z tym EDMX - nie wiem jak to zrobić. W kontrolerze robię to tak:

var repo = new MessageRepository();
            var data = repo.GetAllMessages();

i ten obiekt "data" wysyłam do widoku. to działa jak uzywam SqlCommand w repozytorium. Ale nie działa jak zaczynam używać tego EDMX. Proszę o pomoc.


Pomogłem? To dobrze :)
edytowany 1x, ostatnio: ne0, 2014-12-16 14:46

Pozostało 580 znaków

2014-12-17 13:15
0

http://www.codeproject.com/Ar[...]endency-with-Entity-Framework

Który moment konkretnie nie działa?
Do handlera dependency_OnChange wpada cokolwiek w przypadku EF?

Pozostało 580 znaków

2014-12-17 13:48
ne0
0

W przykładzie który podałeś (i przejrzałem go) oni uzywają Code First, a ja chce polecieć z tego modelu EDMX. W ogóle odpaliłem ten kod i to nie działa. Dodałem do DB jakieś wpisy i nic mi nie zgłosił...

Inaczej może. Żebym to mógł łatwiej zrozumieć.
Obecnie (code first) mam tak w projekcie:
klasa Raport (tabela w bazie).
potem mam DatabaseContext:

 public class DatabaseContext: DbContext
    {
        public DatabaseContext()
            : base("DefaultConnection")
        {
        }
 
        public DbSet<Raport> Raports{ get; set; }
 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        }
    }

potem mam klase DatabaseInitializer w której mam tylko metodę Seed. I potem mam jeszcze klasę RaportRepository:

 public IEnumerable<Raport> GetAllRaports()
        {
            IList<Raport> raports;
 
            using (var db = new InformationSystemEntities())
            {
                db.Database.Connection.Open();
                raports = (from s in db.Raports
                    select s).ToList();
                db.Database.Connection.Close();
                return raports;
            }
        }

i teraz jak mam przerobić to wszystko aby nie używać Code First, tylko używać Database First oraz tego modelu (czy jak to się nazywa) typu EDMX ?

EDIT
teraz mam taki kod:

  public static IEnumerable<Raport> GetRaports()
        {
            ObjectSet<Raport> objectSet = null;
            IList<Raport> raportData = HttpContext.Current.Cache.Get("Raport") as IList<Raport>;
            if (raportData == null)
            {
                using (var context = new InformationSystemEntities())
                {
                    IQueryable<Raport> categoryDataCache = context.Raports;
                    using (SqlConnection connection = new SqlConnection(connectionString.ProviderConnectionString))
                    {
                        connection.Open();
                        var db = new DatabaseContext();
                        ObjectContext objectContext = ((IObjectContextAdapter)db).ObjectContext;
                        objectSet = objectContext.CreateObjectSet<Raport>("Raports");
                        connection.Close();
 
                   /*     SqlCommand command = new SqlCommand(((ObjectQuery)categoryDataCache).ToTraceString(), connection);
                        SqlCacheDependency dependency = new SqlCacheDependency(command);
                        raportData = categoryDataCache.ToList();
                        HttpContext.Current.Cache.Insert("Raport", raportData, dependency);
                        command.ExecuteNonQuery();
                    */
                    }
                }
            }
 
            return objectSet;

i to też nie reaguje na zmianę w bazie.


Pomogłem? To dobrze :)
edytowany 4x, ostatnio: ne0, 2014-12-17 14:07

Pozostało 580 znaków

2014-12-17 15:11
0

Możesz jeszcze spojrzeć na to: https://code.msdn.microsoft.c[...]qlDependency-5c0da0b3#content
Może w czymś pomoże.
Co do DB-first, Code-first, jak się zagłebisz np w Model.edmx -> Model.Context.tt -> Model.Context.cs, to tam znajdziesz DbContext wygenerowany z EDMXa, więc nie powinno być różnicy , bo z tego co patrzę po tych przykładach, potrzebny jest tylko DbContext, a ten mamy w obu podejściach.

dobra, sprawdze ten kod, sprobuje to przerobic na swoj. Zobaczymy czy się uda. - ne0 2014-12-17 15:17

Pozostało 580 znaków

2014-12-17 15:19
ne0
0

Miałbyś jakiś pomysł aby zamiast tabeli używać widoku ?
bo jak odpalam to pierwszym sposobem (code first, który działa) na tabeli to dostaje od razu powiadomienie, natomiast jak uzywam widok z DB to wtedy to w ogóle nie działa.
Różnica jaka jest to w tym miejscu:

 private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
        {
            if (e.Type == SqlNotificationType.Change)
            {
                MessageHub.SendMessages();
            }
        }
  1. Dla tabeli:
    przy pierwszym uruchomieniu, nie dostaje nic. Natomiast jak zmienie w bazie danych to mi tu debugger staje i mam w tym "e" że jest to "Change".
  2. dla widoku:
    przy pierwszym uruchomieniu od razu staje debuger i w tym "e" jest "subscribe" i potem jak dodam rekord do tabeli/widoku to niestety nie reaguje na zminę.

dlaczego? jak to poprawić?


Pomogłem? To dobrze :)

Pozostało 580 znaków

2014-12-17 15:31
0

http://msdn.microsoft.com/en-us/library/ms181122.aspx

The statement must not reference a view.

Tak, więc dla widoku nie wiem czy da rade coś wykombinować.

ale to sie odnosi do tego co ja uzywam? - ne0 2014-12-17 15:57
no dobra to olac te widoku. zrobmy to dla View... - ne0 2014-12-17 15:58

Pozostało 580 znaków

2014-12-17 16:10
ne0
0

To też nie jest to co ja potrzebuje. Ja potrzebuje używać EDMX!!!!


Pomogłem? To dobrze :)

Pozostało 580 znaków

2014-12-17 16:22
ne0
0

Zobacz, mam takie coś:

   public IEnumerable<Raport> GetAllMessages1()
        {
            var messages = new List<Raport>();
            using (var connection = new SqlConnection(_connString))
            {
                connection.Open();
                using (var command = new SqlCommand(@"SELECT [Id], [What]  FROM [dbo].[Raport]", connection))
                {
                    command.Notification = null;
 
                    var dependency = new SqlDependency(command);
                    dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
 
                    if (connection.State == ConnectionState.Closed)
                        connection.Open();
 
                    var reader = command.ExecuteReader();
 
                    while (reader.Read())
                    {
                        messages.Add(item: new Raport
                        {
                            Id= (int)reader["Id"], 
                            What = (string)reader["What"],
                            Where = "",//(string)reader["Where"], 
                            Project = "",//(string)reader["Project"],
                            Who = "",//(string) reader["Who"],
                            When = DateTime.Now,// Convert.ToDateTime(reader["When"]),
                            How = "",//(string)reader["How"],
                            Asset = "",//(string)reader["Asset"],
                            Name = "",//(string)reader["Name"],
                            Item = "",//(string)reader["Item"],
                            ItemId = "",//(string)reader["ItemId"],
                            Notes = ""//(string)reader["Notes"]
                        });
                    }
                }
 
            }
            return messages;
 
        }
 

i jak teraz uzyc tutaj tego z EDMX ? jak mam wsadzic ten context z EDMX ?


Pomogłem? To dobrze :)

Pozostało 580 znaków

2014-12-17 18:32
0

W załączniku możliwie prosty przykład przerobiony z tego co podałem w pierwszym linku. Z użyciem EDMXa, SignalR już nie implementowałem, bez bawienia się ze SqlReaderem i bez własnoręcznego pisania zapytań.

w ogóle teraz mi z DB nie pobiera rekordów :( - ne0 2014-12-18 11:27

Pozostało 580 znaków

2014-12-18 10:28
ne0
0

Nie wiem czy to dobrze działa... Odpaliłem i po każdym wstawieniu nowego wiersza do DB on mi zwraca wszystkie rekordy...a nie tylko te nowe wiec pytanie czy dało by się to jakoś dorobić?

A mam pytanie do Ciebie jeszcze: jakbym chciał tego użyć w aplikacji internetowej, to gdzie to powinienem powsadzać? no bo jak wyświetle strone no to tam nie ma nic takiego co jakby "czeka" na sygnal z bazy danych ze sie cos zmienilo... a w tym programie konsolowym to tam masz jakby pętle w ktorej to siedzi. Jak to zrobić a apce webowej?

To co mam teraz jest tutaj:
Baza danych nazywa sie "InformationSystem" tabela "Raport".
http://www.filedropper.com/informationsystemtest


Pomogłem? To dobrze :)
edytowany 2x, ostatnio: ne0, 2014-12-18 11:21

Pozostało 580 znaków

2014-12-18 12:41
0

Wrzucenie fragmentu

using (var notifier = new EntityChangeNotifier<Raport, InformationSystemEntities>(x => x.Id > 0))
            {
                notifier.Changed += (sender, e) =>
                {
                    IMessageHub<IEnumerable<Raport>> hub = new MessageHub();
                    hub.SendMessages(e.Results);
 
                    foreach (var et in e.Results)
                    {
                        raports.Add(et);
                    }
                };
            }
 

do Application_Start w global.asax powinno rozwiązać sprawę.
Pytanie co chcesz z tym dalej zrobić. Jak SignalR to rozumiem, że wyświetlać na bieżąco na jakiejś stronie.
W tym przypadku piszesz klienta w jQuery, który będzie dodawał nowe rekordy albo wszystkie je odświeżał.

Do tego, by nie pobierało wszystkich rekordów, tylko nowe. Zdaje się, informacja jest tylko o tym że coś zostało dodane, zmienione w tabeli, nie ma co konkretnie. Można oczywiście śledzić ręcznie te zmiany, jednak zawsze dostaniesz całą tabelę. Można ew. pokombinować z fragmentem

 
Results = GetCurrent()

dopisać metodę w stylu

 
Results = GetCurrentLatest()

i dopisać kod by tylko pobierało np. tylko najnowszy rekord.

edytowany 1x, ostatnio: QwertzOne, 2014-12-18 12:42

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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