Pytanie
Czy można zdefiniować unikalne ograniczenie dla właściwości przy użyciu płynnej składni lub atrybutu? Jeśli nie, jakie są obejścia?
Mam klasę użytkownika z kluczem podstawowym, ale chciałbym się upewnić, że adres e-mail jest również niepowtarzalny. Czy jest to możliwe bez bezpośredniej edycji bazy danych?
Rozwiązanie (na podstawie odpowiedzi Matta)
public class MyContext : DbContext {
public DbSet<User> Users { get; set; }
public override int SaveChanges() {
foreach (var item in ChangeTracker.Entries<IModel>())
item.Entity.Modified = DateTime.Now;
return base.SaveChanges();
}
public class Initializer : IDatabaseInitializer<MyContext> {
public void InitializeDatabase(MyContext context) {
if (context.Database.Exists() && !context.Database.CompatibleWithModel(false))
context.Database.Delete();
if (!context.Database.Exists()) {
context.Database.Create();
context.Database.ExecuteSqlCommand("alter table Users add constraint UniqueUserEmail unique (Email)");
}
}
}
}
ObjectContext
lubDbContext
.Odpowiedzi:
O ile wiem, w tej chwili nie ma sposobu, aby to zrobić za pomocą Entity Framework. Jednak nie jest to tylko problem z unikalnymi ograniczeniami ... możesz chcieć utworzyć indeksy, sprawdzić ograniczenia i prawdopodobnie wyzwalacze i inne konstrukcje. Oto prosty wzorzec, którego możesz użyć w swojej pierwszej konfiguracji kodu, chociaż wprawdzie nie jest to agnostyk bazy danych:
Inną opcją jest to, że jeśli model domeny jest jedyną metodą wstawiania / aktualizowania danych w bazie danych, możesz samodzielnie zaimplementować wymóg unikalności i pozostawić bazę danych poza nim. Jest to bardziej przenośne rozwiązanie i wymusza jasne określenie reguł biznesowych w kodzie, ale pozostawia bazę danych otwartą na nieprawidłowe dane, które zostaną cofnięte.
źródło
SaveChanges()
), ale nadal istnieje możliwość, że kolejna wstawka / aktualizacja pojawi się między czasem sprawdzenia unikalności a czasemSaveChanges()
. Tak więc, w zależności od tego, jak krytyczna jest aplikacja i prawdopodobieństwo naruszenia jej wyjątkowości, prawdopodobnie najlepiej jest dodać ograniczenie do bazy danych.serializable isolation level
(lub niestandardowe blokowanie tabeli, ugh) faktycznie pozwoliłoby ci zagwarantować unikalność twojego kodu. Ale większość ludzi nie używa go zeserializable isolation level
względu na wydajność. Wartość domyślna w MS Sql Server toread committed
. Zobacz serię 4 części zaczynającą się od: michaeljswart.com/2010/03/…Począwszy od EF 6.1 jest to teraz możliwe:
Zapewni to unikalny indeks zamiast unikalnego ograniczenia, ściśle mówiąc. W większości praktycznych celów są takie same .
źródło
Niezupełnie z tym związane, ale w niektórych przypadkach może to pomóc.
Jeśli chcesz utworzyć unikalny indeks złożony na, powiedzmy, 2 kolumnach, który będzie stanowił ograniczenie dla Twojej tabeli, od wersji 4.3 możesz użyć nowego mechanizmu migracji, aby to osiągnąć:
Zasadniczo musisz wstawić takie wywołanie w jednym ze swoich skryptów migracji:
Coś w tym stylu:
źródło
DropIndex("TableName", new[] { "Column1", "Column2" });
Robię kompletny hack, aby wykonać SQL podczas tworzenia bazy danych. Tworzę własny DatabaseInitializer i dziedziczę z jednego z dostarczonych inicjatorów.
To jedyne miejsce, w którym mogłem znaleźć klin w moich instrukcjach SQL.
To pochodzi z CTP4. Nie wiem, jak to działa w CTP5.
źródło
Po prostu próbując dowiedzieć się, czy istnieje sposób na zrobienie tego, jedyny sposób, który do tej pory odkryłem, polegał na samodzielnym egzekwowaniu tego, stworzyłem atrybut, który ma być dodany do każdej klasy, w której podajesz nazwy pól, które musisz być niepowtarzalny:
Następnie w mojej klasie dodam to:
Na koniec dodam metodę w moim repozytorium, w metodzie Add lub podczas zapisywania zmian w następujący sposób:
Niezbyt ładne, ponieważ musimy polegać na refleksji, ale jak dotąd jest to podejście, które działa dla mnie! = D
źródło
Również w 6.1 możesz użyć płynnej wersji składni odpowiedzi @ mihkelmuur w następujący sposób:
Metoda płynna nie jest idealna IMO, ale przynajmniej jest teraz możliwa.
Więcej informacji na blogu Arthura Vickersa http://blog.oneunicorn.com/2014/02/15/ef-6-1-creating-indexes-with-indexattribute/
źródło
Łatwy sposób w Visual Basic przy użyciu migracji EF5 Code First
Przykład klasy publicznej
Koniec klasy
Atrybut MaxLength jest bardzo ważny dla unikalnego indeksu typu string
Uruchom cmd: update-database -verbose
po uruchomieniu cmd: dodaj-migrację 1
w wygenerowanym pliku
źródło
Podobny do odpowiedzi Tobiasa Schittkowskiego, ale C # i ma możliwość posiadania wielu pól w constrtaints.
Aby z tego skorzystać, po prostu umieść [Unique] na dowolnym polu, które chcesz, aby było unikalne. W przypadku ciągów będziesz musiał zrobić coś takiego (zwróć uwagę na atrybut MaxLength):
ponieważ domyślne pole ciągu to nvarchar (max) i nie będzie to dozwolone w kluczu.
W przypadku wielu pól w ograniczeniu możesz:
Najpierw UniqueAttribute:
Następnie dołącz przydatne rozszerzenie, aby uzyskać nazwę tabeli bazy danych z typu:
Następnie inicjator bazy danych:
źródło
Rozwiązałem problem przez refleksję (przepraszam, ludzie, VB.Net ...)
Najpierw zdefiniuj atrybut UniqueAttribute:
Następnie ulepsz swój model
Na koniec utwórz niestandardowy DatabaseInitializer (w mojej wersji tworzę bazę danych na zmianach DB tylko w trybie debugowania ...). W tym DatabaseInitializerze indeksy są tworzone automatycznie na podstawie Unique-Attributes:
Być może to pomoże ...
źródło
Jeśli zastąpisz metodę ValidateEntity w klasie DbContext, możesz również umieścić tam logikę. Zaletą jest to, że będziesz mieć pełny dostęp do wszystkich swoich zestawów DbSets. Oto przykład:
źródło
Jeśli używasz EF5 i nadal masz to pytanie, poniższe rozwiązanie rozwiązało je za mnie.
Używam podejścia najpierw kodu, dlatego umieszczam:
w skrypcie migracji wykonał swoją pracę dobrze. Pozwala również na wartości NULL!
źródło
Dzięki podejściu EF Code First można zaimplementować obsługę ograniczeń unikatowych opartych na atrybutach przy użyciu następującej techniki.
Utwórz atrybut znacznika
Zaznacz właściwości, które chcesz, aby były unikalne w obiektach, np
Utwórz inicjator bazy danych lub użyj istniejącego, aby utworzyć unikatowe ograniczenia
Ustaw kontekst bazy danych, aby użyć tego inicjatora w kodzie startowym (np. W
main()
lubApplication_Start()
)Rozwiązanie jest podobne do mheymana, z uproszczeniem polegającym na nieobsługiwaniu kluczy złożonych. Do użytku z EF 5.0+.
źródło
Rozwiązanie Fluent Api:
źródło
Zmierzyłem się dzisiaj z tym problemem i wreszcie udało mi się go rozwiązać. Nie wiem, czy to właściwe podejście, ale przynajmniej mogę kontynuować:
źródło
Użyj unikalnego walidatora właściwości.
ValidateEntity
nie jest wywoływana w ramach tej samej transakcji bazy danych. Dlatego w bazie danych mogą występować warunki wyścigu z innymi podmiotami. Musisz trochę zhakować EF, aby wymusić transakcję wokółSaveChanges
(a zatemValidateEntity
).DBContext
nie może bezpośrednio otworzyć połączenia, aleObjectContext
może.źródło
Według http://blogs.msdn.com/b/adonet/archive/2014/02/11/ef-6-1-0-beta-1-available.aspx , EF 6.1 będzie miał IndexAttribute, który pomoże nam .
źródło
Po przeczytaniu tego pytania miałem własne pytanie w procesie próby zaimplementowania atrybutu do oznaczania właściwości jako unikalnych kluczy, takich jak odpowiedzi Mihkel Müür , Tobiasa Schittkowskiego i mheymana sugerują: Mapowanie właściwości kodu Entity Framework na kolumny bazy danych (CSpace to SSpace)
W końcu dotarłem do tej odpowiedzi, która może odwzorować zarówno właściwości skalarne, jak i właściwości nawigacji w dół do kolumn bazy danych i stworzyć unikalny indeks w określonej kolejności wyznaczonej na atrybucie. Ten kod zakłada, że zaimplementowano UniqueAttribute z właściwością Sequence i zastosowano ją do właściwości klasy jednostki EF, które powinny reprezentować unikalny klucz jednostki (inny niż klucz podstawowy).
Uwaga: ten kod opiera się na programie EF w wersji 6.1 (lub nowszej), który uwidacznia
EntityContainerMapping
niedostępny w poprzednich wersjach.źródło
W przypadku osób korzystających z konfiguracji Code First można również użyć obiektu IndexAttribute jako ColumnAnnotation i ustawić jego właściwość IsUnique na true.
W przykładzie:
Spowoduje to utworzenie unikalnego indeksu o nazwie IX_name w kolumnie Name.
źródło
Przepraszam za spóźnioną odpowiedź, ale uznałam, że dobrze jest z tobą porozmawiać
Napisałem o tym w Code Project
Ogólnie rzecz biorąc, zależy to od atrybutów, które przypisujesz klasom, aby wygenerować unikalne indeksy
źródło