Possiamo usare le enumerazioni come id di quadro tipografica?

Stiamo lavorando con un modello piuttosto grande in una prima configurazione del codice EF 6.1 e stiamo usando gli inte per gli id ​​delle entity framework.

Sfortunatamente, questo non è così tipicamente come vorremmo, dal momento che si possono facilmente mescolare id, per esempio confrontando id di quadro di diverso tipo (myblog.Id == somePost.Id) o simili. O ancora peggio: myBlog.Id ++.

Pertanto, mi è venuta l’idea di usare id scritti, quindi non è ansible mescolare gli id. Quindi abbiamo bisogno di un tipo BlogId per la nostra quadro blog. Ora, la scelta più ovvia sarebbe quella di usare un int racchiuso in una struct, ma non si possono usare le structs come chiavi. E non puoi prolungare int … – aspetta, puoi! Usando enum!

Quindi mi sono inventato questo:

public enum BlogId : int { } public class Blog { public Blog() { Posts = new List(); } public BlogId BlogId { get; set; } public string Name { get; set; } public virtual List Posts { get; set; } } internal class BlogConfiguration : EntityTypeConfiguration { internal BlogConfiguration() { HasKey(b => b.BlogId); Property(b=>b.BlogId) .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); } } 

Quindi ora abbiamo id typesable – il confronto tra un BlogId e un PostId è un errore in fase di compilazione. E non possiamo aggiungere 3 a un BlogId. Le enumerazioni vuote possono sembrare un po ‘strane, ma questo è più un dettaglio di implementazione. E dobbiamo impostare l’opzione DatabaseGeneratedOption.Identity esplicitamente nella nostra mapping, ma questo è uno sforzo una tantum.

Prima di iniziare a convertire tutto il nostro codice in questo schema, ci sono problemi evidenti?

Edit: Probabilmente ho bisogno di chiarire il motivo per cui dobbiamo lavorare con id invece di quadro complete in primo luogo. A volte è necessario abbinare le quadro nelle query EF Linq e il confronto delle quadro non funziona lì. Ad esempio (basandosi sull’esempio del blog e assumendo un modello di dominio più ricco): trova i commenti sulle voci del blog degli utenti correnti. Ricorda, che vogliamo farlo nel database (abbiamo molti dati) e assumiamo che non ci siano proprietà di navigazione diretta. E l’utente corrente non è collegato. Un approccio ingenuo sarebbe

 from c in ctx.Comments where c.ParentPost.Blog.Author == currentUser 

Questo non funziona, dal momento che non è ansible confrontare quadro in EF Linq. Quindi proviamo

 from c in ctx.Comments where c.ParentPost.Blog.Id == currentUser.Id 

Questo compila e funziona ma è sbagliato – avrebbe dovuto essere

 from c in ctx.Comments where c.ParentPost.Blog.Author.Id == currentUser.Id 

Gli id ​​dattiloscopici l’avrebbero catturato. E abbiamo domande molto più complesse di questa. Prova a “trovare commenti agli attuali post di blog degli utenti fatti da specifici altri utenti che l’utente corrente non ha commentato in seguito”.

Saluti, Niels

È un approccio interessante, ma la domanda è: ne vale la pena e quali sono le conseguenze?

Potresti ancora fare qualcosa del genere

  if ((int)blog.BlogId == (int)comment.CommentId) { } 

Personalmente, investirò più tempo nell’educare le persone, scrivere buoni test e recensioni di codice, invece di cercare di aggiungere qualche forma di complessità extra che influenza il modo in cui usi e chiedi le tue entity framework.

Pensa – per esempio:

  • Che effetto ha questo casting sulle prestazioni nelle query LINQ?
  • Come applicheresti questo se esponi le tue operazioni tramite l’API Web di WCF?
  • Funziona con le proprietà di navigazione ??
  • Inoltre, sei limitato nei tipi che potresti usare come chiave primaria; Non credo che funzioni con Guids.

Una modalità di protezione aggiuntiva è quella di fare in modo che il livello del dominio gestisca questo tipo di cose accettando le istanze di entity framework invece degli ID.

Non ero nemmeno a conoscenza di questo utilizzo, ma ho fatto un po ‘di scavo e anche il team EF dice che è fattibile. Dal loro post sul blog iniziale sul supporto enum in EF, questo è elencato:

Enum come chiavi Inoltre, le proprietà dei tipi di enum possono partecipare alla definizione di chiavi primarie, vincoli univoci e chiavi esterne, oltre a prendere parte ai controlli di controllo della concorrenza e hanno dichiarato valori predefiniti.

fonte: http://blogs.msdn.com/b/efdesign/archive/2011/06/29/enumeration-support-in-entity-framework.aspx

Non l’ho mai fatto da solo, ma quella citazione mi dà fiducia. Quindi è ansible, ma come suggerisce L-Three: considera davvero se è quello che vuoi (pro e contro … ma sembra che tu l’abbia già fatto) e test test!

Davvero non provo a schernirti, ma come si possono mescolare Id di Tipo X con Id di Tipo Z? Non ho mai incontrato nessuno che facesse cose come myBlog.Id ++ (o almeno non senza essere licenziato).

Ad ogni modo, ecco una soluzione che sembra meno laboriosa e meglio mantenibile (in particolare per i db-admins):

-In TypeConfiguration, crea un Id attraverso l’API fluente (vedrai perché dopo)

-Crea una class base astratta per tutte le tue quadro con:

* proprietà: proteced int Id

* metodo: public int getIdValue ()

* metodo: public bool isSameRecord (T otherEntity) dove T: EntityBaseClass

Immagino che il primo metodo si spieghi da sé, isSameRecord prenderà l’altra istanza della tua class base, prima esegue un controllo del tipo e se lo passa, eseguirà anche un checkup dell’ID.


Questo è un approccio non testato, ci sono buone probabilità che non si possano creare identificatori protetti.

Se non funziona, puoi creare public int _id e dire semplicemente al tuo team di non usarlo direttamente.

Non è sicuro che ciò funzionerà in EF, ma una cosa che potresti fare è implementare IEquatable :

Ad esempio la tua class Blog :

 public class Blog : IEquatable { // other stuff public bool Equals(Blog other) { return this.Id.Equals(other.Id); } } 

In alternativa è ansible utilizzare un ORM più flessibile come NHibernate. Se questo è interessante, fammelo sapere e amplierò la mia risposta.

So di essere un po ‘in ritardo per questa festa, ma ho usato questa tecnica e funziona decisamente!

La sicurezza del tipo funziona esattamente come suggerisci. Il compilatore colpirà errori come

 from c in ctx.Comments where c.ParentPost.Blog.Id == currentUser.Id 

E impedisce la matematica sciocca.

 currentUser.Id++; currentUser.Id * 3; 

Le proprietà di navigazione funzionano ancora bene, purché entrambe le estremità della navigazione siano dello stesso tipo di enumerazione.

E le query SQL funzionano proprio come fanno con un int .

È certamente un’idea interessante!

Puoi usare gli ID entity framework tipografici? – Sì!

Dovresti ? Non ne sono sicuro. Non sembra che questo sia il modo in cui EF è stato progettato e si sente un po ‘hacky.