I want to seed the database with default data but I get an exception thrown.
I added this initialize class in the DAL namespace
public class MyModelInitialise : DropCreateDatabaseIfModelChanges<MyModelContext>
{
protected override void Seed(MyModelContext context)
{
base.Seed(context);
var MyMarks = new List<MyMark>
{
new Mark{ Name="Mark1", Value="250"},
new Mark{ Name="Mark2", Value="350"},
new Mark{ Name="Mark3", Value="450"}
};
Marks.ForEach(bm => context.Marks.Add(bm));
context.SaveChanges();
}
}
I added this initialiser to app startup
protected void Application_Start()
{
Database.SetInitializer<MyModelContext>(new MyModelInitialise());
}
I get the following error while invoking this
Model compatibility cannot be checked because the DbContext instance was not created
using Code First patterns. DbContext instances created from an ObjectContext or using
an EDMX file cannot be checked for compatibility.
Use the IDatabaseInitializer<TContext> interface instead since DropCreateDatabaseIfModelChanges only works with Code-First models:
public class MyModelInitialise : IDatabaseInitializer<MyModelContext>
{
public void InitializeDatabase(MyModelContext context)
{
// Runs everytime so just avoid if the table already has records.
if (context.Marks.Count() == 0)
{
var MyMarks = new List<MyMark>
{
new Mark{ Name="Mark1", Value="250"},
new Mark{ Name="Mark2", Value="350"},
new Mark{ Name="Mark3", Value="450"}
};
Marks.ForEach(bm => context.Marks.Add(bm));
context.SaveChanges();
}
}
}
Leave the Database.SetInitializer exactly the same. You probably should wrap it in a pre-processor directive to ensure it never ends up in production code.
#if DEBUG
Database.SetInitializer<MyModelContext>(new MyModelInitialise());
#endif
Make sure you have public DbSet<MyMark> MyMarks { get; set; } in the MyModelContext class.
Related
We have ASP MVC web project. After reading a lot of articles and discussions here in stackoverflow about the correct architechture we have decided to go with the following one, although there is not only one correct way of doing things this is the way we have decided, but we still have some doubts.
We are publishing this here not only to be helped but also to show what we have done in case it is helpful to somebody.
We are working in ASP .NET MVC project, EF6 Code first with MS SQL Server.
We have divided the project into 3 main layers that we have separate into 3 projects: model, service and web.
The model creates the entities and setup the DataContext for the database.
The service make the queries to the data base and transform those entities into DTOs to pass them to the web layer, so the web layer doesn't know anything about the database.
The web uses AutoFac for the DI (dependency Injection) to call the services we have in the service layer and obtain the DTOs to transform those DTOs into Model Views to use them in the Views.
After reading a lot of articles we decided not to implement a repository pattern and unit of work because, in summary, we have read the EF acts as a unit of work itself. So we are simplifying things a little here.
https://cockneycoder.wordpress.com/2013/04/07/why-entity-framework-renders-the-repository-pattern-obsolete/
This is the summary of our project. Now I'm going to go through every project to show the code. We are going to show only a couple of entities, but our project has more than 100 different entities.
MODEL
Data Context
public interface IMyContext
{
IDbSet<Language> Links { get; set; }
IDbSet<Resources> News { get; set; }
...
DbSet<TEntity> Set<TEntity>() where TEntity : class;
DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class;
}
public class MyDataContext : DbContext, IMyContext
{
public MyDataContext() : base("connectionStringName")
{
}
public IDbSet<Language> Links { get; set; }
public IDbSet<Resources> News { get; set; }
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
}
}
Here is how we declare the entities
public class Link
{
public int Id{ get; set; }
public string Title { get; set; }
public string Url { get; set; }
public bool Active { get; set; }
}
SERVICES
These are the generic classes we use for all the services.
As you see we use the DTOs to get data from the web layer. Also we connect to the database using Dbset = Context.Set()
public interface IService
{
}
public interface IEntityService<TDto> : IService where TDto : class
{
IEnumerable<TDto> GetAll();
void Create(TDto entity);
void Update(TDto entity);
void Delete(TDto entity);
void Add(TDto entity);
void Entry(TDto existingEntity, object updatedEntity);
void Save();
}
public abstract class EntityService<T, TDto> : IEntityService<TDto> where T : class where TDto : class
{
protected IClientContext Context;
protected IDbSet<T> Dbset;
protected EntityService(IClientContext context) { Context = context; Dbset = Context.Set<T>(); }
public virtual IEnumerable<TDto> GetAll()
{
return Mapper.Map<IEnumerable<TDto>>(Dbset.AsEnumerable());
}
public virtual void Create(TDto entity)
{
if (entity == null)
{
throw new ArgumentNullException(nameof(entity));
}
Dbset.Add(Mapper.Map<T>(entity));
Context.SaveChanges();
}
public virtual void Update(TDto entity)
{
if (entity == null) throw new ArgumentNullException(nameof(entity));
Context.Entry(entity).State = EntityState.Modified;
Context.SaveChanges();
}
public virtual void Delete(TDto entity)
{
if (entity == null) throw new ArgumentNullException(nameof(entity));
Dbset.Remove(Mapper.Map<T>(entity));
Context.SaveChanges();
}
public virtual void Add(TDto entity)
{
Dbset.Add(Mapper.Map<T>(entity));
}
public virtual void Entry(TDto existingEntity, object updatedEntity)
{
Context.Entry(existingEntity).CurrentValues.SetValues(updatedEntity);
}
public virtual void Save()
{
Context.SaveChanges();
}
}
We declare the DTOs in this project (this is a very simple example so we don't have to put all the code here):
public class LinkDto
{
public int Id { get; set; }
public string Title { get; set; }
public string Url { get; set; }
public bool Active { get; set; }
}
Then one of our services:
public interface ILinkService : IEntityService<LinkDto>
{
IPagedList<LinkDto> GetAllLinks(string searchTitle = "", bool searchActive = false, int pageNumber = 1, int pageSize = 10);
LinkDto FindById(int id);
LinkDto Test();
}
public class LinkService : EntityService<Link, LinkDto>, ILinkService
{
public LinkService(IClientContext context) : base(context) { Dbset = context.Set<Link>(); }
public virtual IPagedList<LinkDto> GetAllLinks(bool searchActive = false, int pageNumber = 1, int pageSize = 10)
{
var links = Dbset.Where(p => p.Active).ToPagedList(pageNumber, pageSize);
return links.ToMappedPagedList<Link, LinkDto>();
}
public virtual LinkDto FindById(int id)
{
var link = Dbset.FirstOrDefault(p => p.Id == id);
return Mapper.Map<LinkDto>(link);
}
public LinkDto Test()
{
var list = (from l in Context.Links
from o in Context.Other.Where(p => p.LinkId == l.Id)
select new OtherDto
{ l.Id, l.Title, l.Url, o.Other1... }).ToList();
return list;
}
}
As you see we use AutoMapper (version 5 which has changed a little) to transform from Entities to DTOs the data.
One of the doubts we have is if the use of "Dbset.Find" or "Dbset.FirstOrDefault" is correct and also if the use of "Context.Links" (for any entity).
WEB
FInally the web project where we receive the DTOs and transform those DTOs into ModelViews to show in our views.
We need to call, in the Global.asax Application_Start, AutoFac to do the DI so we can use our services.
protected void Application_Start()
{
...
Dependencies.RegisterDependencies();
AutoMapperBootstrapper.Configuration();
...
}
public class Dependencies
{
public static void RegisterDependencies()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
builder.RegisterModule(new ServiceModule());
builder.RegisterModule(new EfModule());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
public class ServiceModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(Assembly.Load("MyProject.Service")).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope();
}
}
public class EfModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType(typeof(MyDataContext)).As(typeof(IMyContext)).InstancePerLifetimeScope();
}
}
As you see we also call AutoMapper to configure the different maps.
Then in our controllers we have this.
public class LinksController : Controller
{
private readonly ILinkService _linkService;
public LinksController(ILinkService linkService)
{
_linkService = linkService;
}
public ActionResult Index()
{
var links = _linkService.GetAllLinks();
return View(links.ToMappedPagedList<LinkDto, LinksListModelAdmin>());
}
...
public ActionResult Create(LinksEditModelAdmin insertedModel)
{
try
{
if (!ModelState.IsValid) return View("Create", insertedModel);
var insertedEntity = Mapper.Map<LinkDto>(insertedModel);
_linkService.Create(insertedEntity);
return RedirectToAction("Index");
}
catch (Exception ex)
{
throw ex;
}
}
}
Well, this is it...I hope this can be useful for somebody...and also I hope we can have a little help with the questions we have.
1) Although we are separating database from the web project we do need a reference in the web project to initialize the database and also to inject dependencies, is this correct?
2) Is it correct the approach we have done having our Entities->DTOs->ViewModels? It's a little more work but we have everything separated.
3) In the Service project, when we need to reference a different entity than the main one we are using in the service, is it correct to call Context.Entity?
For example, if we need to retrieve also data from the News entity in the links service, is it correct to call "Context.News.Where..."?
4) We do have a little problem with Automapper and EF proxy, because when we call "Dbset" to retrieve data, it gets a "Dynamic proxies" object so Automapper can't find the proper map so, in order to work, we have to set ProxyCreationEnabled = false in the DataContext definition. This way we can get an Entity in order to map it to the DTO. This disables LazyLoading, which we don't mind, but is this a correct approach or there is a better way to solve this?
Thanks in advance for your comments.
For Question no. 2
Entities->DTOs->ViewModels? is good approach
because you are doing the clean separation, the programmer can work together with ease.
The person who design ViewModels, Views and Controllers don't have to worry about the service layer or the DTO implementation because he will make the mapping when the others developpers finish their implementation.
For Question no. 4
When the flag ProxyCreationEnabled is set to false, the proxy instance will not be created with creating a new instance of an entity. This might not be a problem but we can create a proxy instance using the Create method of DbSet.
using (var Context = new MydbEntities())
{
var student = Context.StudentMasters.Create();
}
The Create method has an overloaded version that accepts a generic type. This can be used to create an instance of a derived type.
using (var Context = new MydbEntities())
{
var student = Context.StudentMasters.Create<Student>();
}
The Create method just creates the instance of the entity type if the proxy type for the entity would have no value (it is nothing to do with a proxy). The Create method does not add or attach the entity with the context object.
Also i read some where if you set ProxyCreationEnabled = false the child element will not loaded for some parent object unless Include method is called on parent object.
I have two projects each with their own DbContext class that write to the same SQL Server 2012 database.
The DbContext classes are of the form:
public class BlogDbContext : DbContext
{
public BlogDbContext()
: base("CodeFirstTestConnString")
{
}
public BlogDbContext(string connectionString)
: base(connectionString)
{
}
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//modelBuilder.HasDefaultSchema("blogtest");
}
}
Using Code First Migrations I can create my tables in the (existing) database by executing the following in each project:
Enable-Migrations
Add-Migration Initial
Update-Database
This works fine, however if I add in the line commented out above to set the default schema (both projects use the same schema), Update-Database fails in the second project with the error "There is already an object named '__MigrationHistory' in the database.".
By running "Update-Database -Verbose" I can see that with the default schema changed, "CREATE TABLE [blogtest].[__MigrationHistory]" is executed for the second project; if I don't change the default schema it only tries to create this table the first time.
Is this a bug in Entity Framework, or am I missing something?
Turns out that this is reported in Codeplex as a bug in EF6.
https://entityframework.codeplex.com/workitem/1685
The workaround shown there is to use a custom HistoryContext to set the default schema:
internal sealed class Configuration : DbMigrationsConfiguration<ConsoleApplication11.MyContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
SetHistoryContextFactory("System.Data.SqlClient", (c, s) => new MyHistoryContext(c, s));
}
}
internal class MyHistoryContext : HistoryContext
{
public MyHistoryContext(DbConnection existingConnection, string defaultSchema) : base(existingConnection, defaultSchema)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema("foo");
}
}
Im trying nto enable Migration with code first but im having some issues.
Im working on a mvc5 website and I have a dll with the datalayer, dll with the domain classes and then the website itself.
I have already run the website and all the tables have been created. Now I change the name of a single property on one of the domain classes and want to update the db. But instead it tries to create everything again!
I change the property, enter add-migration into the console and then the migration file is created, but it contains CreateTable for all my classes instead of just the change for that one table/class.
I have alredy used the console to enable-migration so that should be in order. It created the Migration folder and the Configuration.cs file in my website project.
Here is how my code looks:
internal sealed class Configuration :DbMigrationsConfiguration<Playground.Web.Models.ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = false;
}
protected override void Seed(Playground.Web.Models.ApplicationDbContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}
}
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("PlaygroundContext", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
When you first configure migrations you need to add a baseline migration. If you have existing tables, you need to tell EF to make a no-op migration:
Add-Migration InitialCreate –IgnoreChanges
Now, future migrations will be incremental based on the baseline. https://msdn.microsoft.com/en-us/data/dn579398.aspx#option1
I am struggling with using multiple dbContext with an single web application in ASP.NET MVC 5. I am following code First existing database design approach.
so i have created dashboardModel using ADO.NET Entity model, that comes with its own dbContext (DashboardContext) and then roleModel using again ADO.net Entity Model (dbContext = RoleContext).
I want to keep similar concern of model separtate and their individual DBContext.
On creating DashboardModel, code run without problem but when i have created RoleModel and run; it gives me error on Dashboard controller ==> MetadataException was unhandled by user code
public DashboardContext()
: base("name=DashboardContext")
{
}
////
public class DashboardController : Controller
{
//
// GET: /Dashboard/
public ActionResult Home()
{
using (var db = new DashboardContext())
{
var query = from b in db.sys_Functions
orderby b.Function_ID
select b;
foreach(var item in query)
{
var a1 = item.Title;
}
}
return View();
}
}
//
public RoleContext()
: base("name=RoleContext")
{
}
//
public class TestController : Controller
{
//
// GET: /Test/
public ActionResult Index()
{
using(var db = new RoleContext())
{
var query = from x in db.AspNetRoles
orderby x.Name
select x;
foreach(var item in query)
{
var t = item.Name;
}
}
return View();
}
}
Many Thanks
I want to keep similar concern of model separtate and their individual DBContext.
DbContext is the abstraction for a database. So unless you are connecting your entities to different databases, there's no reason to use different Db contexts.
Note: this may not be so related to the question
I wanted to make two ApplicationDbContext with two different connections in ASP.NET MVC 5 (not ASP.NET CORE)
This is what worked for me, first you will need to add a second / overloaded constructor to ApplicationDbContext
Then add another ApplicationDbContext class like "ReadOnly_1_Local_ApplicationDbContext" that inherits the orignial ApplicationDbContext not the "IdentityDbContext" and make its constructor calls the overloaded base constructor with your new connection
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("<your connection>", throwIfV1Schema: false)
{
}
public ApplicationDbContext(string nameOrConnectionString) : base(nameOrConnectionString, throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
public class ReadOnly_1_Local_ApplicationDbContext : ApplicationDbContext
{
public ReadOnly_1_Local_ApplicationDbContext() : base("<your read only connection>")
{
}
}
Usage (I stopped sync from the first db to the read only one and changed the data in one of them to see it really connects to the other db)
public ActionResult TestMultiDbContext_1()
{
var db_context = new ApplicationDbContext();
return Content(db_context.Shipments.Find(123456).CustomerName); // name #1
}
public ActionResult TestMultiDbContext_2()
{
var db_context = new ReadOnly_1_Local_ApplicationDbContext();
return Content(db_context.Shipments.Find(123456).CustomerName); //name #2
}
That is tested with code first migrations and does not cause any issue and is not generating any extra migrations.
If you are adding another connection for entirely new db (not duplicated one), just make another class that inherits the IdentityDbContext normally
Thanks
I'm using the Fluent Validation framework in my ASP.net MVC 3 project. So far all of my validations have been very simple (make sure string is not empty, only a certain length, etc.) but now I need to verify that something exists in the database or not.
Should Fluent Validation be used in this case?
If the database validation should be done using Fluent Validation, then how do I handle dependencies? The validator classes are created automatically, and I would need to somehow pass it one of my repository instances in order to query my database.
An example of what I'm trying to validate might:
I have a dropdown list on my page with a list of selected items. I want to validate that the item they selected actually exists in the database before trying to save a new record.
Edit
Here is a code example of a regular validation in Fluent Validation framework:
[Validator(typeof(CreateProductViewModelValidator))]
public class CreateProductViewModel
{
public string Name { get; set; }
public decimal Price { get; set; }
}
public class CreateProductViewModelValidator : AbstractValidator<CreateProductViewModel>
{
public CreateProductViewModelValidator()
{
RuleFor(m => m.Name).NotEmpty();
}
}
Controller:
public ActionResult Create(CreateProductViewModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
var product = new Product { Name = model.Name, Price = model.Price };
repository.AddProduct(product);
return RedirectToAction("Index");
}
As you can see, I never create the Validator myself. This works because of the following line in Global.asax:
FluentValidation.Mvc.FluentValidationModelValidatorProvider.Configure();
The problem is that now I have a validator that needs to interact with my database using a repository, but since I'm not creating the validators I don't know how I would get that dependency passed in, other than hardcoding the concrete type.
Can't you just create your own validation method where in you would kick-off the database validation?
RuleFor(m => m.name)
.Must(BeInDatabase)
private static bool BeInDatabase(string name)
{
// Do database validation and return false if not valid
return false;
}
I'm using FluentValidation for DataBase validations. just pass the Validation class the session in the Ctor. and do the validation inside the action something like:
var validationResult = new ProdcutValidator(session).Validate(product);
Update: Based on your example I add my example...
public class CreateProductViewModel
{
public string Name { get; set; }
public decimal Price { get; set; }
}
public class CreateProductViewModelValidator : abstractValidator<CreateProductViewModel>
{
private readonly ISession _session;
public CreateProductViewModelValidator(ISession session)
{
_session = session;
RuleFor(m => m.Name).NotEmpty();
RuleFor(m => m.Code).Must(m, Code => _session<Product>.Get(Code) == null);
}
}
Controller:
public ActionResult Create(CreateProductViewModel model)
{
var validator = new CreateProductViewModelValidator();
var validationResult =validator.Validate(model);
if(!validationResult.IsValid)
{
// You will have to add the errors by hand to the ModelState's errors so the
// user will be able to know why the post didn't succeeded(It's better writing
// a global function(in your "base controller" That Derived From Controller)
// that migrate the validation result to the
// ModelState so you could use the ModelState Only.
return View(model);
}
var product = new Product { Name = model.Name, Price = model.Price };
repository.AddProduct(product);
return RedirectToAction("Index");
}
Second update:
If you insist using parameterless constructor you will have to use some Inversion Of control container, a static class that is something like the Factory of your objects.
use it like this:
public class CreateProductViewModelValidator : abstractValidator<CreateProductViewModel>
{
private readonly ISession _session;
public CreateProductViewModelValidator()
{
_session = IoC.Container.Reslove<ISession>();
RuleFor(m => m.Name).NotEmpty();
RuleFor(m => m.Code).Must(m, Code => _session<Product>.Get(Code) == null);
}
}
You can find many IoC containers, most famous are Windsor and Ninject,
You will need to register- instruct the container once to resolve all the ISession to return your's session object.
The other way this could work for you is using Constructor injection. While this method isn't as clear cut as using an IoC library, it may help if you have a static way of accessing or fetching your session.
public class CreateProductViewModelValidator
{
private ISession _session;
public CreateProductViewModelValidator()
:this(SessionFactory.GetCurrentSession()) //Or some other way of fetching the repository.
{
}
internal CreateProductViewModelValidator(ISession session)
{
this._session = session;
RuleFor(m => m.Name);//More validation here using ISession...
}
}
I have been spending quite a bit of time thinking about this exact same issue. I am using ninject to inject my repository into my web UI layer so that my web UI only accesses the database through an interface.
I am wanting to be able to validate things that access the database such as checking for duplicate names and hence my validation needs to access the injected repository. I think that the best way to do this is to just setup Fluent Validation via the manual method rather than the MVC integrated way. For Example:
Create your validation Class (can pass in repository Interface):
public class CategoryDataBaseValidation : AbstractValidator<CategoryViewModel>
{
private IRepository repository;
public CategoryDataBaseValidation (IRepository repoParam)
{
repository = repoParam;
RuleFor(Category => Category.Name).Must(NotHaveDuplicateName).WithMessage("Name already exists");
}
private bool NotHaveDuplicateName(string name)
{
List<Category> c = repository.Categories.ToList(); //Just showing that you can access DB here and do what you like.
return false;
}
}
}
Then in your controller you can just create an instance of above class and pass in the repository (that ninject would have injected in the controller constructor)
[HttpPost]
public ActionResult Create(CategoryViewModel _CategoryViewModel )
{
CategoryDataBaseValidation validator = new CategoryDataBaseValidation (repository);
ValidationResult results = validator.Validate(_CategoryViewModel );
if (results.IsValid == false)
{
foreach (var failure in results.Errors)
{
//output error
}
}
return View(category);
}
Both the above files can live in the Web UI project and you can then also just use the standard MVC DataAnnotations for client side validation.
Just thought that I would put this up for comment / help someone.