2014-10-27 15 views
11

Jak skopiować encję z jednego kontekstu (dziedzicząc z DbContext) do innego?Jak skopiować encję z jednego kontekstu Entity Framework do innego?

Wszystko, co znalazłem działa tylko dla ObjectContext, ale nie dla DbContext lub używa DbContext, ale nie działa.

Na przykład, znalazłem/próbowałem:

  • Używa ObjectContext: CloneHelper na CodeProject
  • Ustawienie LazyLoadingEnabled do fałszywych wyników w nie wypełniania ICollection <> właściwości (zagranicznych klucze)
  • ustawienie ProxyCreationEnabled na fałszywe wyniki w utrzymywaniu właściwości ICollection <> jako puste (klucze obce).
  • Entry <> .State = Oddzielne wyniki nie wypełniają ICollection <> właściwości (klucze obce), jeśli ustawione przed dołączeniem właściwości, lub blokuje identyfikator rozliczania, jeśli zostanie ustawiony później.
  • AsNoTracking() powoduje wyjątek (jedna z następujących zależności czy wkładania do pierwszego pilota kontekście przedmiot z rodzica interfejs ICollection <> nieruchomości czy najpierw macierzystego)
    • dominującej: obiekt w ' Rola ModelFirstSub_First_Target "nie może być automatycznie dodana do kontekstu, ponieważ została pobrana przy użyciu opcji NoTracking merge. Jawnie dołącz encję do ObjectContext przed zdefiniowaniem relacji.
    • Pozycja: Nie można dodać lub dołączyć obiektu, ponieważ jego EntityReference ma wartość właściwości EntityKey, która nie jest zgodna z EntityKey dla tego obiektu.

będę go używać w dwóch celach:

  1. skopiować wszystko z jednej bazy danych na inny (docelowy będzie klonem oryginału; lokalna kopia zdalnej bazy danych). Identyfikatory obiektów powinny zostać zachowane.
  2. Dodawaj lub aktualizuj wybrane obiekty z jednej bazy danych do innej (upstreaming zmian w lokalnej pamięci podręcznej do zdalnego pochodzenia). Identyfikatory nowo utworzonych obiektów nie muszą być zachowywane.

Jak to zrobić?

EF 6.1.1, 4.5.2 .NET, C#

Oto kod test, który próbuje symulować drugą operację (zmiany upstreaming powrotem do zdalnej bazy danych):

var addedFirst = localContext.Firsts.AsNoTracking().Single(m => m.Id == 4); 
var updatedFirst = localContext.Firsts.AsNoTracking().Single(m => m.Id == 2); 

addedFirst.Items.First().Id = 0; 
addedFirst.Items.First().FirstId = 0; 
addedFirst.Id = 0; 

remoteContext.FirstItems.Add(addedFirst.Items.First()); 
remoteContext.Firsts.Add(addedFirst); 

var originalFirst = remoteContext.Firsts.Single(m => m.Id == 2); 
var originalItem = originalFirst.Items.First(); 
originalItem.Title = updatedFirst.Items.First().Title; 

Tutaj jest to model:

public class ModelFirstBase 
{ 
    public virtual int Id { get; set; } 
    public virtual ICollection<ModelFirstSub> Items { get; set; } 
    public virtual string Title { get; set; } 
} 

public class ModelFirstSub 
{ 
    public virtual int Id { get; set; } 
    public virtual int FirstId { get; set; } 
    public virtual ModelFirstBase First { get; set; } 
    public virtual string Title { get; set; } 
} 

PS: właściwości musi być trzymane jako wirtualny model dzielone z aplikacji produkcyjnych, które korzysta z dynamicznych serwerów proxy.

+0

czy wypróbowałeś kontekst odłączyć i dołączyć metody? –

+1

Nie ma takich metod w DbContext. – alik

+0

Context.Set () .Attach (poco) lub Context.Set (typ pocoType) .Attach (poco) wersja. DbContext obsługuje wiele typów tabel. Dołączasz/odłączasz się do jednego z (n) zestawów. Nie kontekst bezpośrednio –

Odpowiedz

0

Próbowałeś po prostu tłumaczenia modelu do drugiego modelu

public class ModelFirstBase 
{ 
public virtual int Id { get; set; } 
public virtual ICollection<ModelFirstSub> Items { get; set; } 
public virtual string Title { get; set; } 
} 

public class ModelFirstSub 
{ 
public virtual int Id { get; set; } 
public virtual int FirstId { get; set; } 
public virtual ModelFirstBase First { get; set; } 
public virtual string Title { get; set; } 
} 

public class ModelTranslator 
{ 
public ModelFirstSub TranslateModelFirstBase(ModelFirstBase entity) 
{ 
//do some error handling and null checks. 
var second = new ModelFirstSub(){ 
        FirstId = entity.Id, 
        ..... 
      }; 
return second; 
} 
} 

public void TransferModels(){ //I haven't thought about disposing stuff, you should. 
var firstContext = new FirstContext(); 
var secondContext = new SecondContext(); 
foreach (var first in firstContext.ModelFirstBases){ 
    var second = new ModelTranslator().TranslateModelFirstBase(first); 
    secondContext.ModelFirstSubs.Add(second); 
} 
secondContext.SaveChanges(); 
} 

Jednak należy pamiętać, że EF nie jest przeznaczona do zbiorczego kopiowania danych, to chociaż powinno działać nie jest prawdziwym rozwiązaniem. Powinieneś pomyśleć o SqlBulkCopy zamiast tego, jeśli używasz serwera Sql lub czegoś podobnego do dowolnego DB, którego używasz.

SQLBulkCopy: How does SqlBulkCopy Work

+0

Tłumaczenie ModelFirstBase na ModelFirstSub wydaje się dziwne. Mimo to liczyłem na coś, co nie wykorzystuje żadnej konwersji między obiektami (do tego mogę wykorzystać klonowanie, modele biznesowe lub niektóre klasy automatycznego mapowania). – alik

+0

Możesz użyć auto-maperów, jeśli chcesz, to jest doskonała biblioteka dla tego samego: http://automapper.org/. Pamiętaj, że niezależnie od map "auto" użyjesz refleksji i nie będzie ona tak wydajna, więc jeśli to jest coś, co działa w tle i kilka milisekund (i większe użycie procesora) nie ma większego znaczenia, śmiało. Jeśli masz oddzielne klasy dla podmiotów, nie możesz uniknąć tłumaczenia. Można jednak korzystać z tych samych klas i używać EntityTypeConfiguration (http://msdn.microsoft.com/en-us/library/gg696117(v=vs.113).aspx) dla właściwości, które nie są zgodne. –

0

Czy za 3rd biblioteki firm, takie jak AutoMapper lub ValueInjector?

Wygląda na to, że zostały zbudowane, aby stawić czoła tego typu wyzwaniom.

Możesz z łatwością wykonać głębokie klonowanie, ale musisz zachować wartość configure EF for identity inserts, jeśli chcesz zachować wartości kolumny tożsamości.