ho cercato una risposta a th è una domanda e ho scoperto che è facile fare uso del Managed Extensibility Framework. C'è un modo più veloce in fondo a questo post, tuttavia MEF consente un approccio molto più scalabile.
MEF consente di creare plug-in di accesso dinamico da gruppi disparati; tuttavia può essere utilizzato per popolare rapidamente le raccolte all'interno di una singola applicazione di assemblaggio. In pratica, lo utilizzeremo come un modo sicuro per rispecchiare il nostro assembly nella classe. Per rendere tutto ciò perfettamente funzionante, implementerò anche il modello di strategia per il modello di Entity Framework.
Aggiungere un riferimento al progetto, che punta a System.ComponentModel.Composition
. Ciò consentirà l'accesso alla libreria MEF.
Ora è necessario implementare il modello di strategia. Se non si dispone di una cartella Interfacce, crearne una e aggiungere IEntity.cs, come di seguito.
IEntity.cs
namespace Your.Project.Interfaces
{
/// <summary>
/// Represents an entity used with Entity Framework Code First.
/// </summary>
public interface IEntity
{
/// <summary>
/// Gets or sets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
int Id { get; set; }
}
}
Ora, ognuno di voi entità concrete necessità di implementare questa interfaccia:
public class MyEntity : IEntity
{
#region Implementation of IEntity
/// <summary>
/// Gets or sets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
public int Id { get; set; }
#endregion
// Other POCO properties...
}
trovo che è meglio la pratica, non creare interfacce individuali per ogni entità, a meno che non sei lavorando in un ambiente di test elevato. Pragmaticamente, le interfacce dovrebbero essere utilizzate solo dove è necessario quel livello di astrazione; soprattutto quando più di una classe concreta erediterà, o quando si lavora con un motore Inversion of Control troppo entusiasta. Se hai interfacce per tutto ciò che è nel tuo modello di produzione, la tua architettura più che probabile, ha grossi difetti. Ad ogni modo, abbastanza del vagabondare.
Ora che abbiamo tutte le nostre entità "strategizzate", possiamo usare MEF per raggrupparle e popolare una raccolta nel vostro contesto.
All'interno del vostro contesto, aggiungere una nuova proprietà:
/// <summary>
/// Gets a dynamically populated list of DbSets within the context.
/// </summary>
/// <value>
/// A dynamically populated list of DbSets within the context.
/// </value>
[ImportMany(typeof(DbSet<IEntity>))]
public IEnumerable<DbSet<IEntity>> Sets { get; private set; }
Il [ImportMany(typeof(DbSet<IEntity>))]
qui, permette MEF per popolare la raccolta.
Successivamente, aggiungere il Export
attributo corrispondente a ciascun DbSet nel contesto:
[Export(typeof(DbSet<IEntity>))]
public DbSet<MyEntity> MyEntities { get; set; }
Ciascuna delle proprietà Import
cati e Export
DE è noto come "parte". Il pezzo finale del puzzle è comporre quelle parti. Aggiungere il seguente al costruttore del contesto:
// Instantiate the Sets list.
Sets = new List<DbSet<IEntity>>();
// Create a new Types catalogue, to hold the exported parts.
var catalogue = new TypeCatalog(typeof (DbSet<IEntity>));
// Create a new Composition Container, to match all the importable and imported parts.
var container = new CompositionContainer(catalogue);
// Compose the exported and imported parts for this class.
container.ComposeParts(this);
Ora, con tutta la fortuna, si dovrebbe avere un elenco popolato dinamicamente dei DbSets, all'interno del vostro contesto.
Ho usato questo metodo per consentire un facile troncamento di tutte le tabelle tramite un metodo di estensione.
/// <summary>
/// Provides extension methods for DbSet objects.
/// </summary>
public static class DbSetEx
{
/// <summary>
/// Truncates the specified set.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="set">The set.</param>
/// <returns>The truncated set.</returns>
public static DbSet<TEntity> Truncate<TEntity>(this DbSet<TEntity> set)
where TEntity : class, IEntity
{
set.ToList().ForEach(p => set.Remove(p));
return set;
}
}
Ho aggiunto un metodo al contesto per troncare l'intero database.
/// <summary>
/// Truncates the database.
/// </summary>
public void TruncateDatabase()
{
Sets.ToList().ForEach(s => s.Truncate());
SaveChanges();
}
EDIT (Overhaul):
Questa soluzione è stata ora ammortizzati. Qualche tweeking come doveva essere fatto per farlo funzionare ora. Per fare in modo che funzioni, è necessario importare i DbSet in una raccolta temporanea di DbSet di tipo "object", quindi lanciare questa raccolta su DbSet del tipo di interfaccia richiesto. Per gli scopi di base, l'interfaccia IEntity sarà sufficiente.
#region Dynamic Table List
/// <summary>
/// Gets a dynamically populated list of DbSets within the context.
/// </summary>
/// <value>
/// A dynamically populated list of DbSets within the context.
/// </value>
public List<DbSet<IEntity>> Tables { get; private set; }
/// <summary>
/// Gets a dynamically populated list of DbSets within the context.
/// </summary>
/// <value>
/// A dynamically populated list of DbSets within the context.
/// </value>
[ImportMany("Sets", typeof (DbSet<object>), AllowRecomposition = true)]
private List<object> TableObjects { get; set; }
/// <summary>
/// Composes the sets list.
/// </summary>
/// <remarks>
/// To make this work, you need to import the DbSets into a temporary collection of
/// DbSet of type "object", then cast this collection to DbSet of your required
/// interface type. For basic purposes, the IEntity interface will suffice.
/// </remarks>
private void ComposeSetsList()
{
// Instantiate the list of tables.
Tables = new List<DbSet<IEntity>>();
// Instantiate the MEF Import collection.
TableObjects = new List<object>();
// Create a new Types catalogue, to hold the exported parts.
var catalogue = new TypeCatalog(typeof (DbSet<object>));
// Create a new Composition Container, to match all the importable and imported parts.
var container = new CompositionContainer(catalogue);
// Compose the exported and imported parts for this class.
container.ComposeParts(this);
// Safe cast each DbSet<object> to the public list as DbSet<IEntity>.
TableObjects.ForEach(p => Tables.Add(p as DbSet<IEntity>));
}
#endregion
Avanti, eseguire il CompileSetsList()
facciata dal costruttore (con le migliori pratiche per il Web mostrati):
public MvcApplicationContext()
{
// Enable verification of transactions for ExecuteSQL functions.
Configuration.EnsureTransactionsForFunctionsAndCommands = true;
// Disable lazy loading.
Configuration.LazyLoadingEnabled = false;
// Enable tracing of SQL queries.
Database.Log = msg => Trace.WriteLine(msg);
// Use MEF to compile a list of all sets within the context.
ComposeSetsList();
}
Poi, basta decorare il vostro DbSet <> s come questo:
/// <summary>
/// Gets or sets the job levels.
/// </summary>
/// <value>
/// The job levels.
/// </value>
[Export("Sets", typeof(DbSet<object>))]
public DbSet<JobLevel> JobLevels { get; set; }
Ora funzionerà correttamente.
Un approccio totalmente diverso in un contesto diverso, ma forse interessante per te: http://stackoverflow.com/questions/9762808/change-fluent-api-mapping-dynamically –