2010-11-18 14 views
79

Powiedzmy, że przeszukuję bazę danych i załaduję listę przedmiotów. Następnie otwieram jeden z elementów w formularzu widoku szczegółowego, a zamiast ponownego wysyłania zapytania do elementu z bazy danych, tworzę instancję elementu ze źródła danych na liście.Zaktualizuj rekord bez wcześniejszych zapytań?

Czy istnieje sposób na aktualizację rekordu bazy danych bez pobrania rekordu pojedynczego elementu?

Oto przykład, jak robię to teraz:

dataItem itemToUpdate = (from t in dataEntity.items 
           where t.id == id 
           select t).FirstOrDefault(); 

Następnie po wyciągnięciu rekord zaktualizować niektóre wartości w pozycji i przesunąć rekord powrotem:

itemToUpdate.itemstatus = newStatus; 
dataEntity.SaveChanges(); 

Myślę byłby lepszy sposób na zrobienie tego, jakieś pomysły?

+2

To nie jest strasznie zły sposób na robienie rzeczy. Czy masz równoczesny dostęp do tego stołu? –

+0

Myślę, że jest to użycie, które ORM jak EF jest dokładnie tam, aby służyć. Aby umożliwić wykonywanie operacji w kontekście aplikacji na obiektach, które chcesz utworzyć/zmodyfikować/usunąć, bez obaw o zasadnicze wdrożenie bazy danych? –

+27

Myślę, że dla programistów z doświadczeniem w TSQL, którzy próbują zaakceptować i zaakceptować ORM, jest to trochę mało wydajne, aby wyszukać rekord tylko po to, aby go zaktualizować i nigdy nie wykorzystywać pobranych danych. Ta koncepcja, że ​​deweloper nie musi zajmować się podstawową implementacją DB, to garść. Im więcej programista wie o całym systemie, tym lepsze może być rozwiązanie. Opcje nigdy nie są złe. – barrypicker

Odpowiedz

61

Należy użyć metody Attach().

Attaching and Detaching Objects

+13

czy możesz podać przykład? –

+14

context.Products.Attach (produkt); context.Entry (product) .State = EntityState.Modified; – Gabriel

+4

@Gabriel Czy to nie spowoduje aktualizacji wszystkich właściwości? Co zrobić, jeśli chcę zmodyfikować tylko jeden? –

0

Ogólnie rzecz biorąc, jeśli używane Entity Framework można zbadać wszystkie elementy, a obiekt został zapisany jednostki, można zaktualizować poszczególne elementy obiektu encji i wywołać SaveChanges() kiedy skończysz. Na przykład:

var items = dataEntity.Include("items").items; 
// For each one you want to change: 
items.First(item => item.id == theIdYouWant).itemstatus = newStatus; 
// After all changes: 
dataEntity.SaveChanges(); 

Pobieranie pojedynczego elementu nie powinno generować nowego zapytania.

+0

Interesująca odpowiedź, czy ktoś inny to potwierdził? – Ian

+3

Robi się to samo, co problem OP: pobierz cały rekord, a następnie zaktualizuj go. .First() deserializuje obiekt. – Jerther

27

Można również użyć bezpośredniego SQL do bazy danych przy użyciu kontekstu magazynu danych. Przykład:

dataEntity.ExecuteStoreCommand 
    ("UPDATE items SET itemstatus = 'some status' WHERE id = 123 "); 

Ze względów wydajności można przekazywać zmienne zamiast pojedynczego, zakodowanego ciągu SQL. Umożliwi to programowi SQL Server buforowanie zapytania i ponowne korzystanie z parametrów. Przykład:

dataEntity.ExecuteStoreCommand 
    ("UPDATE items SET itemstatus = 'some status' WHERE id = {0}", new object[] { 123 }); 

AKTUALIZACJA - dla EF 6.0

dataEntity.Database.ExecuteSqlCommand 
     ("UPDATE items SET itemstatus = 'some status' WHERE id = {0}", new object[] { 123 }); 
+6

dlaczego obniżyłeś tę odpowiedź, nie zostawiając komentarza. Ta sugestia odnosi się do pierwotnego pytania autorów. – barrypicker

+11

'ExecuteStoreCommand' tak naprawdę nie jest metodą EF, to po prostu użycie' DbConnection' zawartego wewnątrz 'DbContext' w celu wykonania polecenia. Nie jest to agnostyka bazy danych, nie mówiąc już o agnostyce uporczywości (np. Ten przykład zawiesiłby się, gdyby OP zmienił się na XML). –

+7

@ just.another.programmer - z wielką mocą stanowi wielką odpowiedzialność. – barrypicker

6

Jeśli DataItem ma pola EF będzie pre-validate (jak zakaz pustych pól), będziemy musieli wyłączyć to sprawdzanie tego kontekstu:

DataItem itemToUpdate = new DataItem { Id = id, Itemstatus = newStatus }; 
dataEntity.Entry(itemToUpdate).Property(x => x.Itemstatus).IsModified = true; 
dataEntity.Configuration.ValidateOnSaveEnabled = false; 
dataEntity.SaveChanges(); 
//dataEntity.Configuration.ValidateOnSaveEnabled = true; 

W przeciwnym razie możemy spróbować spełnić wstępnej walidacji i jeszcze tylko zaktualizować pojedynczą kolumnę:

DataItem itemToUpdate = new DataItem 
{ 
    Id = id, 
    Itemstatus = newStatus, 
    NonNullableColumn = "this value is disregarded - the db original will remain" 
}; 
dataEntity.Entry(itemToUpdate).Property(x => x.Itemstatus).IsModified = true; 
dataEntity.SaveChanges(); 

Zakładając dataEntity jest System.Data.Entity.DbContext

można zweryfikować th Zapytanie e generowane przez dodanie tego do DbContext:

/*dataEntity.*/Database.Log = m => System.Diagnostics.Debug.Write(m); 
3

kodu:

ExampleEntity exampleEntity = dbcontext.ExampleEntities.Attach(new ExampleEntity { Id = 1 }); 
exampleEntity.ExampleProperty = "abc"; 
dbcontext.Entry<ExampleEntity>(exampleEntity).Property(ee => ee.ExampleProperty).IsModified = true; 
dbcontext.Configuration.ValidateOnSaveEnabled = false; 
dbcontext.SaveChanges(); 

TSQL wynik:

exec sp_executesql N'UPDATE [dbo].[ExampleEntities] 
SET [ExampleProperty ] = @0 
WHERE ([Id] = @1) 
',N'@0 nvarchar(32),@1 bigint',@0='abc',@1=1 

Uwaga:

W "IsModified = true" jest potrzebna, ponieważ podczas tworzenia nowego obiektu ExampleEntity (tylko z właściwością Id jest wypełniona) wszystkie inne właściwości mają swoje wartości domyślne (0, null, itp.). Jeśli chcesz zaktualizować bazę danych za pomocą "wartości domyślnej", zmiana nie zostanie wykryta przez strukturę encji, a następnie baza danych nie zostanie zaktualizowana.

Na przykład:

exampleEntity.ExampleProperty = null; 

nie będzie działać bez linii „IsModified = true”, bo ExampleProperty nieruchomość jest już zerowa podczas tworzenia pusty obiekt ExampleEntity, to trzeba powiedzieć, EF, że ta kolumna musi zostać zaktualizowana, a taki jest cel tej linii.

Powiązane problemy