entity-framework-4 asp.net-mvc-3 ninject

Aplicación ASP.NET MVC 3 utilizando Ninject, Entity Framework 4 Code-First CTP 5, Patterns



entity-framework-4 asp.net-mvc-3 (2)

Eww. Este era astuto En realidad no sé mucho, así que no pude resolverlo de inmediato.

Encontré la solución para la SEGUNDA pregunta que estaba relacionada con el error al encontrar que ninject en realidad dispara dos instancias de DatabaseFactory, una para el repositorio y otra para la unidad de trabajo. En realidad, el error no fue el problema. Fue un error interno en la base de datos de objetos, pero creo que es normal ya que estoy usando Entity Framework.

El problema real fue que Ninject estaba vinculando dos instancias diferentes de IDatabaseFactory, lo que llevó a 2 conexiones abiertas.

La revisión se agregó al primer conjunto en _reviewRepostory que estaba usando la primera instancia de la base de datos.

Al llamar a commit en la unidad de trabajo ... no se guardó nada debido al hecho de que la revisión no estaba en esta instancia de la base de datos. De hecho, la unidad de trabajo llamó la base de datos de base que llevó a crear una nueva instancia ya que ninject envió una nueva instancia de la misma.

Para solucionarlo simplemente usa:

Bind<IDatabaseFactory>().To<DatabaseFactory>().InSingletonScope();

en lugar de

Bind<IDatabaseFactory>().To<DatabaseFactory>();

¡Y ahora todo el sistema funciona correctamente!

Ahora, ¿me encantarían algunas respuestas con respecto a la primera pregunta, que es si hay algún problema con mi código actual? ¿He aplicado patrones correctamente? ¿Alguna sugerencia o recomendación que me lleve en la dirección correcta?

He intentado construir un proyecto base con las tecnologías anteriores. Quería la máxima flexibilidad y capacidad de prueba, así que intenté usar patrones en el camino para hacer esto como base para futuros proyectos. Sin embargo, parece que algo está mal o lo que sea y realmente necesito ayuda aquí. Así que tengo dos preguntas:

  1. ¿Hay algún problema con mi código actual? He aplicado patrones correctamente? ¿Alguna sugerencia o recomendación que me lleve en la dirección correcta?

  2. ¿Por qué este código realmente se conecta a la base de datos, lo crea, pero no admite la inserción incluso si realizo la operación correcta? (Mire el final de la publicación para obtener detalles sobre este error) CORREGIDO

Creo que esto también podría ayudar a otros, ya que no he encontrado suficiente información para poder hacer algo correctamente. Estoy bastante seguro de que muchas personas intentan hacerlo de la manera correcta y no estoy segura de que yo sepa si lo que estoy haciendo es correcto.

Tengo dos entidades: Comentar y Revisar.

COMENTARIO

public class Comment { [Key] public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual string Author { get; set; } public virtual string Body { get; set; } }

REVISIÓN

public class Review { [Key] public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual string Author { get; set; } public virtual string Body { get; set; } public virtual bool Visible { get; set; } public IEnumerable<Comment> Comments { get; set; } }

Construí un repositorio base para cada uno de ellos de esta manera:

Repositorio genérico

public abstract class EFRepositoryBase<T> : IRepository<T> where T : class { private Database _database; private readonly IDbSet<T> _dbset; protected IDatabaseFactory DatabaseFactory { get; private set; } protected Database Database { get { return _database ?? (_database = DatabaseFactory.Get()); } } public EFRepositoryBase(IDatabaseFactory databaseFactory) { DatabaseFactory = databaseFactory; _dbset = Database.Set<T>(); } public virtual void Add(T entity) { _dbset.Add(entity); } public virtual void Delete(T entity) { _dbset.Remove(entity); } public virtual T GetById(long id) { return _dbset.Find(id); } public virtual IEnumerable<T> All() { return _dbset.ToList(); } }

Para operaciones específicas , uso una interfaz:

public interface IReviewRepository : IRepository<Review> { // Add specific review operations IEnumerable<Review> FindByAuthor(string author); }

Así que estoy obteniendo las operaciones genéricas de la clase abstracta más las operaciones específicas:

public class EFReviewRepository : EFRepositoryBase<Review>, IReviewRepository { public EFReviewRepository(IDatabaseFactory databaseFactory) : base(databaseFactory) { } public IEnumerable<Review> FindByAuthor(string author) { return base.Database.Reviews.Where(r => r.Author.StartsWith(author)) .AsEnumerable<Review>(); } }

Como se dio cuenta, también uso una fábrica de bases de datos producirá el contexto de la base de datos:

FABRICA DE BASES DE DATOS

public class DatabaseFactory : Disposable, IDatabaseFactory { private Database _database; public Database Get() { return _database ?? (_database = new Database(@"AppDb")); } protected override void DisposeCore() { if (_database != null) _database.Dispose(); } }

DISPONIBLE (Algunos métodos de extensiones ...)

public class Disposable : IDisposable { private bool isDisposed; ~Disposable() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (!isDisposed && disposing) { DisposeCore(); } isDisposed = true; } protected virtual void DisposeCore() { } }

BASE DE DATOS

public class Database : DbContext { private IDbSet<Review> _reviews; public IDbSet<Review> Reviews { get { return _reviews ?? (_reviews = DbSet<Review>()); } } public virtual IDbSet<T> DbSet<T>() where T : class { return Set<T>(); } public Database(string connectionString) : base(connectionString) { //_reviews = Reviews; } public virtual void Commit() { base.SaveChanges(); } /* protected override void OnModelCreating(ModelBuilder modelBuilder) { // TODO: Use Fluent API Here } */ }

Y para terminar, tengo mi unidad de trabajo ....

Unidad de trabajo

public class UnitOfWork : IUnitOfWork { private readonly IDatabaseFactory _databaseFactory; private Database _database; public UnitOfWork(IDatabaseFactory databaseFactory) { _databaseFactory = databaseFactory; } protected Database Database { get { return _database ?? (_database = _databaseFactory.Get()); } } public void Commit() { Database.Commit(); } }

También enlazé usando Ninject las interfaces:

FÁBRICA DEL CONTROLADOR DE NINJECTOS

public class NinjectControllerFactory : DefaultControllerFactory { // A Ninject "Kernel" is the thing that can supply object instances private IKernel kernel = new StandardKernel(new ReviewsDemoServices()); // ASP.NET MVC calls this to get the controller for each request protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { if (controllerType == null) return null; return (IController)kernel.Get(controllerType); } private class ReviewsDemoServices : NinjectModule { public override void Load() { // Bindings... Bind<IReviewRepository>().To<EFReviewRepository>(); Bind<IUnitOfWork>().To<UnitOfWork>(); Bind<IDatabaseFactory>().To<DatabaseFactory>(); Bind<IDisposable>().To<Disposable>(); } } }

Sin embargo, cuando llamo al constructor (la acción predeterminada) ...

public class ReviewController : Controller { private readonly IReviewRepository _reviewRepository; private readonly IUnitOfWork _unitOfWork; public ReviewController(IReviewRepository postRepository, IUnitOfWork unitOfWork) { _reviewRepository = postRepository; _unitOfWork = unitOfWork; } public ActionResult Index() { Review r = new Review { Id = 1, Name = "Test", Visible = true, Author = "a", Body = "b" }; _reviewRepository.Add(r); _unitOfWork.Commit(); return View(_reviewRepository.All()); } }

Esto parece crear la base de datos pero no inserta nada en la base de datos en EF4. Parece que puedo resolver el problema ... mientras observo el objeto de la base de datos ... el estado de conexión se cierra y la versión del servidor lanza una excepción de este tipo:

ServerVersion = ''(((System.Data.Entity.DbContext (_database)).Database.Connection).ServerVersion'' threw an exception of type ''System.InvalidOperationException''

Estoy haciendo las cosas bien? ¿Hay algo mal en lo que he construido?

Además, si tiene alguna recomendación sobre el código que publiqué, me alegraría. Solo estoy tratando de aprender la manera correcta de construir cualquier tipo de aplicación en MVC 3. Quiero un buen comienzo.

Yo suelo :

  • Entity Framework 4 con Code-First

  • ASP.NET MVC 3

  • Ninject como contenedor DI

  • SQL Server Express (no R2)

  • Visual Studio 2010 Web Express


Una pequeña observación: al tener su EFRepositoryBase e IReviewRepository con métodos que devuelven un IEnumerable<> lugar de un IQueryable<> , evita que los métodos posteriores agreguen expresiones / restricciones o proyecciones de filtros, etc., a la consulta. En su lugar, al usar IEnumerable<> , realizará cualquier filtrado posterior (por ejemplo, utilizando los métodos de extensión LINQ) en el conjunto de resultados completo, en lugar de permitir que esas operaciones afecten y simplifiquen la declaración SQL que se ejecuta en el almacén de datos.

En otras palabras, está realizando un filtrado adicional en el nivel del servidor web, no en el nivel de la base de datos al que realmente pertenece, si es posible.

Nuevamente, esto puede ser intencional; a veces, usar IEnumerable<> es válido si desea evitar que las personas que llaman a su función modifiquen el SQL que se genera, etc.