2014-08-29 13 views
7

Mam pomysł na projekt domeny, który chciałbym zaimplementować. Używam Entity Framework jako mechanizmu przechowywania i jedyny sposób, w jaki mogę to zobaczyć, nie wydaje się idealny.Przechowywanie relacji opartej na interfejsie w Entity Framework

Mam wiele obiektów domeny i wiele z nich musi być "flagowalnych". Użytkownicy muszą mieć możliwość "oznaczenia" każdego z nich jako wymagającego uwagi w pewien sposób.

Więc pomyślałem, że tworzenie tego interfejsu:

public interface IFlaggable 
{ 
    [Required] 
    Tally Tally { get; } 
    Guid? TallyId { get; } 
} 

i tych klas:

public class Flag 
{ 
    public Guid Id { get; internal set; } 
    [Required] 
    public Tally Tally { get; internal set; } 
    public Guid TallyId { get; internal set; } 
    [Required] 
    public User Creator { get; internal set; } 
    public Guid CreatorId { get; internal set; } 
    [Required] 
    public FlagIndication Indication { get; internal set; } 
} 

public class Tally 
{ 
    public Guid Id { get; internal set; } 
    public IFlaggable Subject { get; internal set; } 
    public ICollection<Flag> Flags { get; internal set; } 
} 

FlagIndication jest enum, jeśli nie jest to oczywiste.

Następnie wszystkie inne obiekty domenowe muszą zrobić, to implementować IFlaggable i stać się flagowymi.

public class TestFlaggable : IFlaggable 
{ 
    public Guid Id { get; internal set; } 
    public Tally Tally { get; internal set; } 
    public Guid? TallyId { get; internal set; } 
} 

Wydaje się świetne. Pod względem DB powinno działać dobrze, ponieważ jest to relacja jeden do jednego, a pozostałe tabele zawsze zawierają obcy klucz do pola id tabeli Tallies.

Kłopot w tym, że Entity Framework rzuca okiem na interfejs i dławiki. Oczywiście. Wiemy, że Entity Framework nie działa dobrze z interfejsami.

Jedynym sposobem, jaki widzę, aby działało z Entity Framework, jest złomowanie interfejsu, tworzenie klas potomnych, takich jak "TestFlaggableTally", które dziedziczą po Tally, a następnie każdy inny obiekt może mieć własną specjalną klasę Tally z płatkami śniegu.

public class Tally 
{ 
    public Guid Id { get; internal set; } 
    public ICollection<Flag> Flags { get; internal set; } 
} 

[Table("TestFlaggableTallies")] 
public class TestFlaggableTally : Tally 
{ 
    public TestFlaggable Subject { get; internal set; } 
} 

public class TestFlaggable 
{ 
    public Guid Id { get; internal set; } 
    public TestFlaggableTally Tally { get; internal set; } 
    public Guid? TallyId { get; internal set; } 
} 

To powinno zadziałać, ale wydaje się głupie i nadęte.

Tak, jestem tutaj, aby zapytać. Czy istnieje lepszy sposób?

Czy mam pewne podstawowe nieporozumienie?

Czy to moja najlepsza opcja?

ok, uderzył mnie

+0

Co masz na myśli mówiąc EF dławiki? Wiele razy używałem interfejsów do moich jednostek. –

+0

Po prostu nie jest w stanie stworzyć relacji z takiej własności. Rozumiem dlaczego. Nie wie, gdzie to odwzorować. –

+0

Entity Framework nie ma sensu dla właściwości "public IFlaggable Subject {get; internal set;}". –

Odpowiedz

3

myślę EF nie ma takiego wsparcia dla interfejsów. - nieprawda, zobacz Aktualizacja

Proponuję przepisanie interfejsu do klasy abstrakcyjnej:

public abstract class FlaggableBase<T> 
{ 
    public abstract T Id { get; internal set; } 
    public abstract Tally Tally { get; internal set; } 
    public abstract Guid? TallyId { get; internal set; } 
} 

pamiętać, że dodana właściwość ID do klasy bazowej, aby zapewnić, że każdy podmiot, który wywodzi się z FlaggableBase ma klucz (EF wymaga tego, aby móc odróżnić podmioty).

następnie używać go tak:

public class TestFlaggable : FlaggableBase<Guid> 
{ 
    public override Guid Id { get; internal set; } 
    public override Tally Tally { get; internal set; } 
    public override Guid? TallyId { get; internal set; } 
} 

public class Tally 
{ 
    public Guid Id { get; internal set; } 
    public FlaggableBase<Guid> Subject { get; internal set; } 
    public ICollection<Flag> Flags { get; internal set; } 
} 

public class Flag 
{ 
    public Guid Id { get; internal set; } 
    [Required] 
    public Tally Tally { get; internal set; } 
    public Guid TallyId { get; internal set; } 
    public Guid CreatorId { get; internal set; } 
} 

Jedyną wadą korzystania z klasy abstrakcyjnej zamiast interfejsu widzę od razu, jest to, że nie będzie w stanie wykorzystać leniwy załadunku, ponieważ nie można zastosować wirtualne słowo kluczowe na przesłonach.

Jeśli z jakiegoś powodu nadal polegać na IFlaggable interfejsu, po prostu wdrożyć go w klasie bazowej:

public abstract class FlaggableBase<T> : IFlaggable 

UPDATE

grałem około trochę w VS i okazuje się rzeczywiście może robić, co chcesz, za pomocą interfejsów:

public interface IFlaggable<out T> 
{ 
    T Id { get; } 
    Tally Tally { get; } 
    Guid? TallyId { get; } 
} 

Następnie w swojej klasie Tally:

public class Tally 
{ 
    public Guid Id { get; internal set; } 
    public IFlaggable<Guid> Subject { get; internal set; } 
    public ICollection<Flag> Flags { get; internal set; } 
} 

Oto jak to będzie wyglądać w DB: enter image description here

+0

To nie działa w kolekcji: kolekcja encji interfejsów (IFlaggables tutaj) nigdy nie zostanie zapełniona po pobraniu instancji Tally przy użyciu EF. – neural5torm

+0

Zostanie wypełniony po wprowadzeniu wirtualnej własności. – Alisson

Powiązane problemy