Modeling an existing database - asp.net-mvc

I want to generate a model based on an existing database -- I thought it would be as simple as writing the model, adding a DbContext class, and configuring a connection string:
namespace MyProject.Models
{
public class Account
{
public int Id { get; set; }
public string Email { get; set; }
public string Name { get; set; }
}
public class AccountDBContext : DbContext
{
public DbSet<Account> Accounts { get; set; }
}
}
With a simple boilerplate controller
public ActionResult Index()
{
return View(db.Accounts.ToList());
}
The boilerplate view, which I won't post here, which lists all of the members of the db object that we return.
ANd finally, a connection string:
<add name="AccountDBContext" providerName="System.Data.SqlClient" connectionString="[server connection string]" />
Only problem is I don't see any entries being displayed. It's definitely connecting, but not retrieving or displaying the data that the particular DB contains.. am I missing something?
Edit
Ok, so first thing is first: it wasn't connecting. I had a typo in my connection string name. It was hitting the default, and subsequently displaying nothing.
What I am getting now, though, is The model backing the 'AccountDBContext' context has changed since the database was created.
Is this because my model doesn't match exactly to what the database contains?

This is the "Code First with an Existing Database" scenario.
What version of EF are you using?
In EF 4.3 when you let code first create a database for you, it inserts a Migration-History table into the new database. It’s hidden in System Tables.This is equivalent to the EdmMetadata table you got with EF 4.1 & 4.2. But when you already have the database you can use code first migrations. (http://msdn.microsoft.com/en-US/data/jj591621)
Either way you should probably check if such a table exist. If it does you can delete it and then you'll be solely responsible to correctly matching your pocos to the database.
Another quick workaround i have found is putting
Database.SetInitializer<YourContext>(null);
to your Application_Start() in Global.asax
See also this similar question: Entity Framework Code Only error: the model backing the context has changed since the database was created

Related

Access a table of a separate database using entity framework

I have an MVC website with its own database and everything is working fine. Now I want to access a table of a database from a different MVC site. I added the connection string in the Web.config and named it OldMvcDB. Then I added a class to access this table:
public class OldSiteDB : DbContext
{
public OldSiteDB() : base("name=OldMvcDB") { }
public DbSet<OldTable> OldTables { get; set; }
}
When I try to access this table, I get the error:
The model backing the 'OldSiteDB' context has changed since the database was created.
This is because the old database has a lot of other tables so the context doesn't match.
How can I access this one table without having to duplicate all the items in my new site?
You should add the following to your class constructor:
Database.SetInitializer<OldSiteDB>(null);
From this SO answer.

Getting a the new value of RowVersion using Entity Framework 6

Is is possible, to get the new value of RowVersion using the same DbContext, without reloading the entity from the database?
Scenario:
Load data into editor form
Save new values
The row in the table gets updated, new value of RowVersion is generated
However, the saved entity still holds the old value of RowVersion, so the new value can not be passed back to the client
All concurrency control articles are usually concerned only with preventing the update (e.g. see this).
However, in the example from the article, a successful update is followed by a redirect to page, where the saved entity is read again and now it has a new RowVersion value. I would like to avoid this redirect.
Thanks to grennis, I found out the source of my problems.
I defined the interface and an entity like
public interface IRowVersion
{
// Attention: this will not be "inherited" by the implementing class !!!
[Timestamp]
byte[] VersionStamp { get; set; }
}
public class Directory : IRowVersion
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
// If this attribute is missing here, then row version is used
// My initial version was without this attribute
[Timestamp]
public byte[] VersionStamp { get; set; }
}
In my problematic version, I thought that having the attribute on the interface property is enough. However, the attribute must be explicitly applied on the entity's property. Otherwise it will not be used at all (not even as the part of update SQL statement). The value was updated only because the DB updates the column value automatically and of course, at next read, I got the new value.
Not entirely related to the problem, but still worth mentioning... The following is really a killer feature of EF6
ctx.Database.Log = s => Debug.Write(s);
SQL Profiler, it was nice knowing you :-)

MVC4 Scaffolding Add Controller gives error "Unable to retrieve metadata..."

I'm using RTM version of Windows 8 and VS 2012 Ultimate. I have a MVC4 project using SqlCe 4.0 with a code first entity framework model.
Model is very simple:
public class MyThing
{
public int MyThingId { get; set; }
public int UserId { get; set; }
public string Title { get; set; }
public string Address { get; set; }
public string Description { get; set; }
public DateTime Date { get; set; }
}
When I try to create a new controller with the built in scaffolding too I get the following error:
"Unable to retrieve metadata for MyThing"
"Using the same DbCompiledModel to create contexts against different
types of database servers is not supported. Instead, create a
separate DbCompiledModel for each type of server being used.
How do I get scaffolding to work?
By trial and error I found the line of code (it's the DbContext ctor) that is causing the error:
public class MyThingDb : DbContext
{
// If I comment this constructor out the scaffolding works
public MyThingDb()
: base("DefaultConnection")
{
}
public DbSet<MyThing> Things{ get; set; }
}
WTF?
I also stumbled into this symptom while running a tutorial on the subject of building an MVC Music Store application.
There definitely seem to be a bug within Visual Studio. What seems to trigger this bug is choosing some name, other than the default, used for the connection string.
My thanks goes to user dwaynef on http://forums.asp.net/t/1838396.aspx/1 for finding this workaround.
A bit elaborated you need to, temporarily during addition of the new scaffolding controller, change the name of your connection string to 'DefaultConnection' in web.config:
<connectionStrings>
<add name="DefaultConnection" ... />
</connectionStrings>
If you have more than one connection string - make sure only this one is there while performing the action.
Here's my two cents worth. I don't believe your solution actually addresses the real issue. The real fix is to pass the base constructor the database name rather than the connection string name so if your connection string is
<add name="MyContext" connectionString="Data Source=|DataDirectory|MyDatabase.sdf" providerName="System.Data.SqlServerCe.4.0" />
you're context class should be defined as
public class MyContext : DbContext
{
public MyContext() : base("MyDatabase") { }...
Hope this works for you and others as it does for me.
Here is what worked for me:
Go to connection string in web.config change the following:
providerName="System.Data.SqlClient"
instead of
providerName="System.Data.SqlServerCe.4.0"
Generate your controller.
Rename providerName back to "System.Data.SqlServerCe.4.0".
run your project.
Works for me:
In the "Add New Scaffolded Item" dialog, i added a new context (plus) with any name (for me "ScaffoldingContext").
Then the scaffolding works. Just rename the context in the Controller.
After trying different options, the below method resolves the error..
If the name value in connection string matches with the value passed to the constructor, it works.
public MyThingDb()
: base("name=MyContext")
{
}
Problem may be because of missing
[NotMapped] Attribute
in one of the model class.
As I missed the attribute and I was cunning my head.
[Display(Name="Logo")]
[DataType(DataType.Upload)]
[NotMapped]
public HttpPostedFileBase Logo { set; get; }
This may sometimes be caused by an association property or a foreign key attribute
I had a similar issue but it wasn't the default constructor. It also happens if you have multiple projects in your solution and your "Web" facing MVC project does not reference EntityFramework.
Change "Things" inside
public
DbSet<MyThing> Things
{ get; set; }
}
to
"Database1" where "Database1" is the name of the database file on disk which appears in your Web.config file as "Database1.sdf"
The solution that worked for me is to pass the same database name as in your connection string to the base constactor of your dbContext class.
I solved this by pressing CTRL+F5 to rebuild my project before adding my controller.
I had a similar issue when trying to create a view from my controller using the scaffolding. In the create view dialog I simply cleared the "Data Context Class" dropdown and then the scaffolding mechanism worded fine.
This is what that worked out for me ..
I commented out the connectionstring using the 'System.Data.SqlServerCe.4.0' and
then added the controller with scaffolding templates.
In your context class you have to comment the DbConfigurationType when you are going to create a controller with scaffolding.
//[DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]
public class NameDbContext
{}
MVC 5 / EF 6
perhaps you can do this in the older version?
commented out the connection strings in the web / app.config then save
try to create new controller and have VS create a "new" dbcontext item instead of choosing the one you already have
click create
delete new dbcontext class
replace controller dbcontext with yours
uncomment connection strings in web / app.config then save
worked for me!
I had the same error message, but it was nothing to do with the connection string.
It is a very rare case, but hopefully this will help someone. My model name was the same as one of the segments of my namespace name.
For example:
namespace blah.blah.Building
public class Building
I renamed my namespace and fixed all usages and then the t4 scaffolding worked!
Her's another possible solution. You may have to run scaffolding for "dependent" models first. Then work your way up to complicated models that have many dependencies.

Asp.Net MVC2 TekPub Starter Site methodology question

Ok I've just ran into this and I was only supposed to be checking my emails however I've ended up watching this (and not far off subscribing to TekPub).
http://tekpub.com/production/starter
Now this app is a great starting point, but it raises one issue for me and the development process I've been shown to follow (rightly or wrongly). There is no conversion from the LinqToSql object when passing data to the view. Are there any negitives to this?
The main one I can see is with validation, does this cause issues when using MVC's built in validation as this is somthing we use extensivly. Because we are using the built in objects generated by LinqToSql how would one go about adding validation, like
[Required(ErrorMessage="Name is Required")]
public string Name {get;set;}
Interested to understand the benifits of this methodology and any negitives that, should we take it on, experiance through the development process.
Should this be taken as a guide and we should be using ViewModels? If so should we always use them even in simple cases? And how/where in the application logic does the Entity get converted to a ViewModel?
With entity objects, you could use buddy classes, whereby you create a second class which acts as a metadata provider for your entity. For instance, with a Customer entity generated by Linq-to-Sql, I could create a buddy class like so:
[MetadataType(typeof(CustomerMeta))]
partial class Customer {
}
public class CustomerMeta {
[DisplayName("Forename", Required(ErrorMessage = "Forename is required.")]
public string Forename { get; set;}
}
Entities are generated as partial classes so you can add your own code to them.
Alternatively, you could forego pushing your entity types to your views and create specific models based around the functionality required, for instance I would typically have a User entity, but when I need to create a User, I have something called a CreateUserSpec model:
public class CreateUserSpec
{
[DisplayName("Forename")]
public string Forename { get; set; }
}
Which has a subset of the properties of the User, only those required to create a User. This is the model I would pass to my view, and repopulate from the form data. For instance:
public class AccountController
{
public ActionResult Register() {
return View(new CreateUserSpec());
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Register(CreateUserSpec spec) {
if (!ModelState.IsValid) {
return View(spec);
}
var user = UserFactory.CreateUser(spec);
// Redirect to authorisation page?
}
}

ASP.NET MVC / DDD architecture help

I am creating a Web application using ASP.NET MVC, and I'm trying to use domain-driven design. I have an architecture question.
I have a WebControl table to store keys and values for lists so they can be editable. I've incorporated this into my business model, but it is resulting in a lot of redundant code and I'm not sure it belongs there. For example, in my Request class I have a property called NeedType. Because this comes from a list, I created a NeedType class to provide the values for the radio buttons. I'm showing just one example here, but the form is going to have probably a dozen or so lists that need to come from the database.
[edit, to clarify question] What's a better way to do this? Are these list objects really part of my domain or do they exist only for the UI? If not part of the domain, then they don't belong in my Core project, so where do they go?
public class Request : DomainObject
{
public virtual int RequestId { get; set; }
public virtual DateTime SubmissionDate { get; set; }
public virtual string NeedType { get; set; }
public virtual string NeedDescription { get; set; }
// etc.
}
public class NeedType : DomainObject
{
public virtual int NeedTypeId { get; set; }
public virtual string NeedTypeCode { get; set; }
public virtual string NeedTypeName { get; set; }
public virtual int DisplayOrder { get; set; }
public virtual bool Active { get; set; }
}
public class RequestController : Controller
{
private readonly IRequestRepository repository;
public RequestController()
{
repository = new RequestRepository(new HybridSessionBuilder());
}
public RequestController(IRequestRepository repository)
{
this.repository = repository;
}
public ViewResult Index(RequestForm form)
{
ViewData.Add("NeedTypes", GetNeedTypes());
if (form == null)
{
form = new RequestForm();
form.BindTo(repository.GetById(125));
}
}
private NeedType[] GetNeedTypes()
{
INeedTypeRepository repo = new NeedTypeRepository(new HybridSessionBuilder());
return repo.GetAll();
}
}
Create a seperate viewmodel with the data you need in your view. The Model in the M of MVC is not the same as the domainmodel. MVC viewmodels are dumb DTO's without behaviour, properties only. A domain model has as much behaviour as possible. A domain model with get;set; properties only is considered an anti-pattern called "anemic domain model". There are 2 places where most people put the viewmodels: in the web layer, close to the views and controllers, or in a application service layer.
Edit:
When you only need to display a list of all needtypes in the database and one request in your view, I would indeed create one viewmodel with the request and the list of needtypes as properties. I don't think a call to multiple repositories in a controller is a smell, unless you have a larger application and you might want a seperate application service layer that returns the whole viewmodel with one method call.
I think it might also be a good idea to follow the advise of Todd Smith about value object.
When the needtypes can be added or edited by users at runtime, needtype should be an entity. When the needtypes are hardcoded and only changed with new releases of the project, needtype should be a value object and the list of needtypes could be populated by something like NeedType.GetAll() and stored in the database by adding a column to the request table instead of a seperate needtype table.
If it comes from a list, then I'm betting this is a foreign key. Don't think about your UI at all when designing your domain model. This is simply a case where NeedType is a foreign key. Replace the string NeedType with a reference to an actual NeedType object. In your database, this would be a reference to an id.
When you're building your list of NeedType choices, you simply need to pull every NeedType. Perhaps keeping it cached would be a good idea if it doesn't change much.
Your NeedType looks like a value object to me. If it's read-only data then it should be treated as a value object in a DDD architecture and are part of your domain.
A lot of people run into the "omg so much redundancy" issue when dealing with DDD since you're no longer using the old Database -> DataTable -> UI approach.

Resources