I am Using Entity Framework 6.1.1
I have a class in one project, which include FBuyShopContext, another for models, and one Asp project with MVC 5
In my first project I have following
public class FBuyShopContext : DbContext
{
public FBuyShopContext()
: base("name=FBuyShopContext")
{
}
public virtual DbSet<Product> Admins { get; set; }
}
}
And a Product Model in a other Library project
public class Product
{
public Product()
{}
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
my connection string is following
<connectionStrings>
<add name="FBuyShopContext" connectionString="data source=tschikovani\SQLEXPRESS;initial catalog=OnlineShop;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
and when I want to add a new product into database in my controller
FBuyShopContext db = new FBuyShopContext();
Product new = new Product ();
new.Name = "Iphone";
db.Products.Add(new);
db.SaveChanges();
I have a following exception
An exception of type 'System.ArgumentException' occurred in EntityFramework.dll
keyword not supported: 'data source'.
Why this happened? connection string is fully right
I can see three things going on here:
1) DbContext's contructor should take the name of the connection string, therefore change it to just FBuyShopContext and not name=FBuyShopContext.
public class FBuyShopContext : DbContext
{
public FbuyShopContext() : base("FBuyShopContext") {}
}
2) Your connection string ends with a ", which is an invalid character. You should remove it.
3) You should specify your primary key on the model, either using the fluent API, or by data annotations:
public class Product {
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
I'm pretty sure the error you are getting is caused by 2), but 1) and 3) would have caused you problems later.
Related
I have the following Entity class definition:
[Table("Users")]
public class WebUser
{
public virtual int Id { get; set; }
public virtual ICollection<Client> Clients { get; set; }
// more properties...
}
Notice that table name is different than the class name. I also have a ClientUsers table which is a many-to-many mapping for clients and users. Problem is, when I try to access the webUser.Clients property I get the following exception:
"Invalid object name 'dbo.ClientWebUsers'."
Looks like Entity Framework is trying to guess the name of the third table, but it apparently was not smart enough to take into account the table attribute that I have there. How can I tell EF that it is ClientUsers and not ClientWebUsers? Also what rule does it follow to know which table name comes first and which one comes second in the new table name? I think it's not alphabetical order.
I'm using EF 5.0. Thanks!
From the looks of things you're using Code First, so I'll answer accordingly. If this is incorrect, please let me know.
I believe the convention being used to determine the name of the many-to-many table is determined by the order in which they occur as DbSet properties in your SomeContext : DbContext class.
As for forcing EntityFramework to name your table whatever you like, you can use the Fluent API in the OnModelCreating method of your SomeContext : DbContext class as follows:
public class DatabaseContext : DbContext
{
public DatabaseContext()
: base("SomeDB")
{
}
public DbSet<WebUser> Users { get; set; }
public DbSet<Client> Clients { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<WebUser>().HasMany(c => c.Clients)
.WithMany(p => p.WebUsers).Map(
m =>
{
m.MapLeftKey("ClientId");
m.MapRightKey("UserId");
m.ToTable("ClientUsers");
});
}
}
This assumes your classes are something like the following:
[Table("Users")]
public class WebUser
{
public virtual int Id { get; set; }
public virtual ICollection<Client> Clients { get; set; }
// more properties...
}
public class Client
{
public int Id { get; set; }
public ICollection<WebUser> WebUsers { get; set; }
// more properties
}
Finally, here's an integration test (NUnit) demonstrating the functionality working. You may need to drop your database before running it as Code First should want to update/migrate/recreate it.
[TestFixture]
public class Test
{
[Test]
public void UseDB()
{
var db = new DatabaseContext();
db.Users.Add(new WebUser { Clients = new List<Client> { new Client() } });
db.SaveChanges();
var webUser = db.Users.First();
var client = webUser.Clients.FirstOrDefault();
Assert.NotNull(client);
}
}
Edit: Link to relevant documentation for the Fluent API
Rowan's answer (adding here for reference):
Here is the information on how to configure a many-to-many table (including specifying the table name). The code you are after is something like:
modelBuilder.Entity<WebUser>()
.HasMany(u => u.Clients)
.WithMany(c => c.WebUsers)
.Map(m => m.ToTable("ClientUsers");
~Rowan
Last few weeks I have been learning entity Framework, had exposure to ADO.Net and some LINQ syntax. I am basically finding so much setup and wiring to do before you can actually get into the developing the stuffs. I am especially having hard time in Code First approach, have also spent sometime in passionate blogs of Julie Larnam. Any suggestions on books, articles or blogs on entity framework to expedite my learning and deeper understanding would be appreciated.
Thanks
Alaxi
Initialization
Step one, setup your models
public class Person
{
public Int32 Id { get; set; }
public String Name { get; set; }
public String Email { get; set; }
// one-to-many relationship to Pet (EF picks up on this automatically)
public ICollection<Pet> Pets { get; set; }
}
public class Pet
{
public Int32 Id { get; set; }
public String Name { get; set; }
public String Breed { get; set; }
// foreign key back to person (EF picks up on this automatically)
public Person Owner { get; set; }
}
Step two, create a context using your models
public MyContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Pet> Pets { get; set; }
}
Step three, create a connectionString
protip: The name of the connection string should match that of your context.
<connectionStrings>
<add name="MyContext"
providerName="System.Data.SqlClient"
connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=MyContext;IntegratedSecurity=True;" />
</connectionStrings>
Run through
Basic
// automatically find the connection string matching the context name,
// as well as performs a check to see if:
// 1. The database exists
// 2. The schema is up-to-date
MyContext context = new MyContext();
context.Persons.Add(new Person {
Name = "Brad Christie",
Email = "bchristie#contoso.com"
});
context.SaveChanges();
Intermediate
You can also change how the data is generated using Initializers. For example, if you wanted to pre-populate the database with information you can do the following:
public class MyContextInitializer
// this could be `DropCreateDatabaseAlways<TContext> or any other
// preexsting initializer:
: DropCreateDatabaseIfModelChanges<MyContext>
// you can also create your own explicitly if you implement the
// following interface, but that's a bit much starting out.
//: IDatabaseInitializer<MyContext>
{
protected override void Seed(MyContext context)
{
new List<Person> {
new Person {
Name = "Brad Christie",
Email = "bchristie#contoso.com",
Pets = new HashSet<Pet> {
new Pet {
Name = "Spot",
Breed = "Dalmation"
}
}
}, new Person {
Name = "Alaxi04",
Email = "Alaxi04#contoso.com",
Pets = new HashSet<Pet> {
new Pet {
Name = "Petey",
Breed = "Parrot"
}
}
}
}.ForEach(p => context.Persons.Add(p));
base.Seed(context);
}
}
In practice:
// call this somewhere early on in the application (but only once!)
Database.SetInitializer<MyContext>(new MyContextInitializer());
// This can also be configured through the `web.config`:
<entityFramework>
<contexts>
<context type="MyNamespace.MyContext, MyAssembly">
<databaseInitializer type="MyNamespace.MyContextInitializer, MyAssembly" />
</context>
</contexts>
</entityFramework>
/* ***** */
// then use the context as normal:
MyContext context = new MyContext();
var petOwners = context.Persons.AsEnumerable();
I've successfully mapped an Entity Framework Code-First data model with an existing Sql Server Compact database by a declarative approach using app.config but it would be great if I could build such connection programmatically with perhaps the help of the EntityConnectionStringBuilder (System.Data.EntityClient) class. Unfortunately this approach is not working as the [DbContext].Connection.ConnectionString is not accepting most of its properties.
Here's the actual working code with the faulty one commented out:
Book.cs
public class Book
{
[Key]
public string Isbn { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Publisher { get; set; }
public DateTime Published { get; set; }
public int Pages { get; set; }
public bool InStock { get; set; }
public string Description { get; set; }
}
Catalog.cs
public class Catalog : DbContext
{
public DbSet<Book> Books { get; set; }
}
app.config
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add
name="Catalog"
providerName="System.Data.SqlServerCE.4.0"
connectionString="Data Source=res/Catalog.sdf"
/>
</connectionStrings>
</configuration>
Main()
static void Main()
{
// var res = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "res");
// var str = new EntityConnectionStringBuilder();
// str.Name = "Catalog";
// str.Provider = "System.Data.SqlServerCe.4.0";
// str.ProviderConnectionString = String.Format("Data Source {0}", Path.Combine(res, "Catalog.sdf"));
try
{
using (var catalog = new Catalog())
{
// catalog.Database.Connection.ConnectionString = str.ConnectionString;
// remaining code not relevant - skipped
I've tried using other builder classes such as SqlCeConnectionStringBuilder (System.Data.SqlServerCe), SqlConnectionStringBuilder (System.Data.SqlClient) and even DbConnectionStringBuilder (System.Data.Common) but apparently none of them seem to match what [DbContext].Connection.ConnectionString is expecting.
Should I conclude there is no programmatic way to achieve this?
Any advice will be surely appreciated. Thanks much in advance for your contributions.
If you are using SQL Server Compact 4.0 and DbContext with code first you cannot use EntityConnectionStringBuilder - it builds connection string for EF with EDMX file. You need SqlCeConnectionStringBuilder from System.Data.SqlServerCe assembly with version 4.0.0.0!
You should also pass the connection string to the context instance through the constructor - DbContext has constructor accepting name of the connection string (from configuration) or connection string itself.
Open a DbConnection and pass it to the DbContext constructor or use a DefaultConnectionFactory:
Database.DefaultConnectionFactory
= new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
using (var catalog = new Catalog("Catalog.sdf"))
{
}
SqlCeConnectionFactory is a ready-to-use connection factory provided by Microsoft, but you can also implement your own factory.
I'm trying to use the Entity Framework 4.1 RC with a SQL Server 2005 instance. I've created an empty database and I'd like to persist my POCO objects to it. My POCO looks like:
public class Cart
{
public Cart()
{
this.CartId = Guid.NewGuid();
}
public Guid CartId { get; set; }
public decimal TotalCost { get; set; }
public decimal SubTotalCost { get; set; }
public decimal Tax { get; set; }
public decimal EstimatedShippingCost { get; set; }
}
My CartContext is:
public class CartContext : DbContext
{
public DbSet<Cart> Carts { get; set; }
public DbSet<Attribute> Attributes { get; set; }
public DbSet<AttributeItem> AttributeItems { get; set; }
}
I have a connection string:
<add name="CartContext" connectionString="Server=myserver.mynetwork.net;User ID=MyUser;Pwd=mypassword;Initial Catalog=ExistingDb" providerName="System.Data.SqlClient" \>
When I try and add an object to the context and save it I get:
System.Data.Entity.Infrastructure.DbUpdateException:
An error occurred while updating the
entries. See the inner exception for
details. --->
System.Data.UpdateException: An error
occurred while updating the entries.
See the inner exception for details.
---> System.Data.SqlClient.SqlException:
Invalid object name 'dbo.Carts'.
If I profile the database I can see the user connect, look for the database in sys.tables run this query:
SELECT TOP (1)
[Extent1].[Id] AS [Id],
[Extent1].[ModelHash] AS [ModelHash]
FROM [dbo].[EdmMetadata] AS [Extent1]
ORDER BY [Extent1].[Id] DESC
Then attempt to insert my cart object. It never tries to create the Carts table. I'm guessing there's something wrong with the connection string, but I can't find examples anywhere on how to do this.
DbContext will not create table just because it doesn't exists. Once you are using existing database you must also manually create tables or create custom initializer. Default initializers are only able to drop the database and create new one with all required tables.
You can for example call:
context.Database.Delete();
context.Database.Create();
Or:
context.Database.CreateIfNotExists();
Or:
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>());
// You don't need to call this. Initialization takes place anyway if context
// needs it but you can enforce initialization for example in the application
// startup instead of before the first database operation
context.Database.Initialize(true);
I created a new Entity Frameworks Code First app and the DbSet (People) is returning null.
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Repository : DbContext
{
public DbSet<Person> People;
}
web.config: connection string
<connectionStrings>
<add name="Repository"
connectionString="Data Source=|DataDirectory|Repository.sdf"
providerName="System.Data.SqlServerCe.4.0"/>
</connectionStrings>
Now when I call
Repository _repo = new Repository()
_repo.People;
_repo.People will be null
What I am missing?
Microsoft.Data.Entity.Ctp.dll is
referenced
I have tried with and
without a database initializer.
That's because you define a field of DbSet<Person> on Repository class instead of a property. Once you add a property or change it to be a automatic property,People will start to give you values instead of null. So all you need to do is to change your Repository class to:
public class Repository : DbContext
{
public DbSet<Person> People { get; set; }
}
I just had the same issue. The problem was that I did set these properties as 'internal' while they must have been 'public'. Just in case someone is still searching :)
I just had the same issue. The problem was that I did set these properties as 'internal' while they must have been 'public'. Just in case someone is still searching :)
I guess, these properties can be internal/public too, if you use them like this:
public class Repository : DbContext
{
internal DbSet<Person> People { get; set; }
public Repository()
{
//your code here...
People = Set<Person>();
}
}