I am new to Visual Studio MVC3 and trying to connect to a database. I have my connection string in the web.config file:
add name="con" connectionString="Data Source=190.190.200.100,1433;Network Library=DBMSSOCN;Initial Catalog=myDataBase;
User ID=myUsername;Password=myPassword;" providerName="System.Data.SqlClient"
However, the server has multiple tables. How/where will I specify which table to use when querying the database?
EDIT:
For example, I am looking at this example. How does the application differentiate between the tables to display data? When you call return View(db.Students.ToList()) as in the example in the link, how does the application know to look in the student table and not in the enrollment table?
How does the application differentiate between the tables to display
data? When you call return View(db.Students.ToList()) as in the
example in the link, how does the application know to look in the
student table and not in the enrollment table?
The db.Students part comes from Entity Framework.
Read the "Creating the Database Context" section in the link that you posted.
You will find the following code there:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using ContosoUniversity.Models;
using System.Data.Entity.ModelConfiguration.Conventions;
namespace ContosoUniversity.Models
{
public class SchoolContext : DbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Course> Courses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
}
This sets up the database context, which is basically Entity Framework's "setup", from where it knows which C# class it has to map to database tables.
So db.Students (from your question) is actually a DbSet<Student>.
Entity Framework's default convention looks like this: it tries to map a class to a table with the same name.
Usually, it would map the Student class to a table named Students (pluralized), but you can change/override these conventions...which they also did in this example, in this line:
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
This is also explained in the tutorial, directly under the above code.
Quote from the tutorial:
This code creates a DbSet property for each entity set. In Entity
Framework terminology, an entity set typically corresponds to a
database table, and an entity corresponds to a row in the table.
The statement in the OnModelCreating method prevents table names from
being pluralized. If you didn't do this, the generated tables would be
named Students, Courses, and Enrollments. Instead, the table names
will be Student, Course, and Enrollment. Developers disagree about
whether table names should be pluralized or not. This tutorial uses
the singular form, but the important point is that you can select
whichever form you prefer by including or omitting this line of code.
Related
Feel free to tell me that this question needs to be moved and I will move it. I just don't know where else to go for help.
My current work flow is:
Create the database first (database Actual)
Run scaffold command which creates my models
Create a Visual Studio Database project
Import the database (database project)
Whenever I need to make a change to the database I follow the below:
Change the database project
Run a Schema Compare
Verify and update the database Actual
rerun the scaffold command with a -Force to rebuild all the models.
What (if any) type of problems am I leaving myself open to down the road?
I am not seeing the value of database migrations as I am updating the database first but using the database project to provide source control and some protection.
I always used to use the graphic database tool, but obviously with Core that is no longer an option.
I have also considered Devart's Entity Developer as a ORM.
Your thoughts and feedback are VERY much appreciated.
So the biggest problem is what happens when I need to make changes to the model.
So something simple like:
public partial class UserInfo
{
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public DateTime RecordCreated { get; set; }
}
My '[Required]' will obliviously be gone after a -force.
Joe
That is the correct "database first" workflow for EF Core, and you would not use migrations in that scenario. Be sure to place customizations to your entities or DbContext in separate partial class files so they don't get clobbered when you regenerate the entities.
always used to use the graphic database tool, but obviously with Core that is no longer an option.
With this workflow you can use any graphical design tool you want for your database schema.
I'm using C#, .NET 4.5 and Entity Framework 6 in my project. It uses both Oracle and SQL Server, depending on the installation at the client.
The approach is database-first, as this database existed already by the time we decided to change the ORM from NHibernate to Entity Framework 6.
The mapping looks like this:
ToTable(schema + ".Motorista");
Property(x => x.Criacao).HasColumnName("criacao").IsOptional();
The table and column names are all in PascalCase in the mapping, which works fine with SQL Server but, in Oracle, all the names are UpperCase which causes an error:
ORA-00942: table or view does not exist
If I manually make it uppercase, then it works fine on Oracle. But I can't do that because of compatibility to SQL Server.
How can I say to Entity Framework to uppercase all the names when using Oracle?
Can I use conventions in this scenario?
When the database names (tables and columns) are equal to the class and property names in the class model it's very easy to introduce custom code-first conventions:
In the context's OnModelCreating overload you can add these lines to add conventions how table and column names will be derived from the class and property names, respectively:
modelBuilder.Types().Configure
(c => c.ToTable(c.ClrType.Name.ToUpper(), schema));
modelBuilder.Properties().Configure
(c => c.HasColumnName(c.ClrPropertyInfo.Name.ToUpper()));
Of course you should do this conditionally, i.e. when connecting to Oracle. For instance by checking a global constant like OnOracle that you could set by
ConfigurationManager.ConnectionStrings[0].ProviderName
== "System.Data.OracleClient"
on application start up.
Check the providerName attribute in the named connection string to see if your connection is for SQL Server or Oracle (OR add a redundant value in the appSettings section of the configuration). Then do what #AaronLS suggested and add a helper method to case your names correctly and apply any additional formatting. The helper method should be tasked with checking the database type as mentioned above and applying or not applying casing/formatting.
Here is an example.
public class MyDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new SomeMappedTypeMapper());
base.OnModelCreating(modelBuilder);
}
}
public class SomeMappedType
{
public int SomeMappedColumnId { get; set; }
public string SomeMappedColumn { get; set; }
}
public class SomeMappedTypeMapper : EntityTypeConfiguration<SomeMappedType>
{
public SomeMappedTypeMapper()
{
this.HasKey(x => x.SomeMappedColumnId);
this.ToTable("SomeMappedType"); // If needed, apply the same technique as used in the column name extension
this.Property(x => x.SomeMappedColumnId).HasColumnNameV2("SomeMappedColumnId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(x => x.SomeMappedColumn).HasColumnNameV2("SomeMappedColumn");
}
}
public static class TypeHelper
{
private static bool isOracle;
static TypeHelper()
{
isOracle = System.Configuration.ConfigurationManager.ConnectionStrings["yourDbConnectionName"].ProviderName.IndexOf("oracle", StringComparison.OrdinalIgnoreCase) >= 0;
}
public static PrimitivePropertyConfiguration HasColumnNameV2(this PrimitivePropertyConfiguration property, string columnName)
{
if (isOracle)
return property.HasColumnName(columnName.ToUpper());
return property.HasColumnName(columnName);
}
}
This link is in EF CORE but it may help you, this converts ToUpper, but you can change ToLower, you can also use the Nuget ** Humanizer ** for another type of capitalize.
Import that file into your project and use it like this.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ToUpperCaseTables();
modelBuilder.ToUpperCaseColumns();
// ...
}
Consider a table called "Person" with a column called "Name" in SQL Server but in oracle the table is called "PERSON" with a column called "NAME".
We were able to use our models generated against sql server on our oracle database by adding the following code to the DBContext classe's OnModelCreating
modelBuilder.Entity<Person>()
.HasEntitySetName("Person")
.ToTable("PERSON");
modelBuilder.Entity<Person>()
.Property(t => t.Name)
.HasColumnName("NAME");
I use database first. In the auto-generated EF5 code:
Account has ClientID(FK)
Client has AddressID(FK)
Address has public List<EFClient> Clients { get; set; } (i did not specify this in DB but ef5 auto generated it)
When I serialize Address object, it throws exception "there is a circular reference" because the client collection in the address also cotains same address again
What can I do in this situation?
How can I not let EF5 auto-generate that Clients collection?
Thanks in advance!
I don't think you actually want to stop EF from auto-generating this navigation property, as it will affect lots of places. What you can do is simply remove the property that it generated from the model, which will remove the property from the class.
I am using Entity Framework on a project, but am finding the large queries, especially those which use LEFT joins, to be very tedious to write, and hard to debug.
Is it common, or accepted practice, to make use of Views in the database, and then use those views within the EntityFramework? Or is this a bad practice?
the question is not very clear but there is no absolute right or wrong in Software. it all depends on your case.
there is native support for views in ef core but there is no native support for views in EF < 6. at least not in the current latest version 6.3. there is, however, a work around to this. in database first you would create your view via sql normally and when you reverse engineer your database, EF will treat your view as a normal model and will allow you to consume it regularly as you would do in a normal table scenario. in Code First it's a bit more tedious. you would create a POCO object that maps to the columns in your view. notice that you need to include an Id in this POCO class. for example
public class ViewPOCO
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id {get;set;}
public string ViewColumn1 {get;set;}
... etc.
}
you would add this POCO class in your DbContext
public class MyDbContext : DbContext
{
public virtual DbSet<ViewPOCO> MyView {get;set;}
}
now you will normally apply the command of adding migration through the package manager console
Add-Migration <MigrationName> <ConnectionString and provider Name>
now in the migration up and down you will notice that EF treats your Model as table. you would clear all of this and write your own sql to add/alter the view in the up and drop the view in the down method using the Sql function.
public override void Up()
{
Sql("CREATE OR ALTER VIEW <ViewName> AS SELECT NEWID() AS Id, ...");
}
public override void Down()
{
Sql("DROP VIEW <ViewName>");
}
First create your view.
Update Your .edmx File.
then use like this.
using (ManishTempEntities obj = new ManishTempEntities())
{
var a = obj.View_1.ToList();
}
I need to design domain that has two simple entities:
public class User
{
public virtual int Id { get; protected set; }
public virtual string Email { get; protected set; }
public virtual Country Country { get; protected set; }
...
}
public class Country
{
public virtual int Id { get; protected set; }
public virtual string Name { get; protected set; }
...
}
It's all nice and clear in domain world but the problem is that User and Country persisted in two different databases on two different servers (tho they are both MSSQL 2005 servers).
So, how should I correctly implement persistance of entites across different sql servers in NHibernate?
Using IDs instead of objects in references? Yeah, thats simple but it's hitting hard on the whole domain thing making domain object more like DTO. And it will require that IUserRepository get it's hands on ICountryRepository to load User entity.
Linked servers? Hm... Somehow I don't like it (distributed transactions and no XML columns). And what I should be aware in case of using them and more importantly how should I configure NHibernate to work effectively with linked servers?
Maybe some other solution?
I've heard of people using the schema property in a class mapping to contain the linked server name (like otherserver.dbo), but I don't know anyone that hasn't ran into one problem or another when doing that.
There are a few DDD bootstrapping frameworks that allow you to transparently map entities to different databases (resulting in multiple ISessionFactories, which it will manage for you). NCommon is one I would recommend. This assumes, however, that Country only exists in one database, and User only exists in another.
As for transactions... well, if you use a TransactionScope and configure DTS, that might work. NCommon uses a UnitOfWork API that also wraps TransactionScope.
You would have to change User so that Country is just an ID. Here's why. You'd end up with two session factories, one that has a mapping for Country and the other that has a mapping for User. If you don't make that change, NHibernate will complain that there is no mapping for Country when you save User (since they are stored in two different DBs).
Now you could instruct NHibernate to ignore Country property, and keep Country so your domain doesn't change. However, when you load User from the database next time, Country will be null.
You could use NHibernate.Shards from NHContrib.