Entity Framework 4.1Code First connecting to Sql Server 2005 - entity-framework

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);

Related

add-migration queries the database for the columns I'm trying to add, fails with "Error: Invalid column name 'newColumn1', 'newColumn2', 'newColumn3'"

I'm trying to add three columns to an existing table via code first migrations with EF Core (package version 3.1.8). When I run add-migration <name> -c <context> -o <output folder>, it's throwing this error (along with a massive stack trace...):
An error occurred while accessing the Microsoft.Extensions.Hosting services. Continuing without the
application service provider. Error: Invalid column name 'NewColumn1'.
Invalid column name 'NewColumn2'.
Invalid column name 'NewColumn3'.
Unable to create an object of type 'MyDbContext'. For the different patterns supported at
design time, see https://go.microsoft.com/fwlink/?linkid=851728
Really baffled by this. This is the fourth migration I've added today, none of the previous ones had this issue.
This migration should add the three columns, data for the predefined rows for these columns, and add a default value constraint to newColumn1. The column data types:
newColumn1: bit, defaults to 0
newColumn2: nvarchar(50)
newColumn3: nvarchar(50)
My entity before adding my trouble migration:
public class MyEntity
{
[Key]
public int Id { get; set; }
[MaxLength(50), Required]
public string AttributeName { get; set; }
[Required]
public bool Required { get; set; }
}
This entity changed to the following prior to attempting to add this migration:
public class MyEntity
{
[Key]
public int Id { get; set; }
[MaxLength(50), Required]
public string AttributeName { get; set; }
[Required]
public bool Required { get; set; }
public bool NewColumn1{ get; set; }
[MaxLength(50)]
public string NewColumn2 { get; set; }
[MaxLength(50)]
public string NewColumn3 { get; set; }
}
In MyDbContext.OnModelCreating, I have the following new code:
builder.Entity<MyEntity>().Property(x => x.NewColumn1).HasDefaultValue(false);
The IEntityTypeConfiguration<MyEntity> has also, as previously mentioned, been updated to have data for all new columns for the predefined rows. No rows exist in the database besides the predefined rows.
I have a theory as to what's going on. I think add-migration requires an instance of MyDbContext, and when it gets instantiated it verifies that the database looks the way it expects. The context expects the table represented by MyEntity to have the three new columns that are defined in the entity, but they don't exist in the database. What I'm curious of is why this just started now? This is my fourth migration of the day, my other migrations added tables, columns, data....why would this just now start becoming an issue?
The msft documentation link in the error makes me think I need to implement IDesignTimeDbContextFactory<MyDbContext>, configure it in such a way that it makes it not choke. But looking at the behavior of DbContextOptionsBuilder, it doesn't look like any of the provided options will allow me to bypass the behavior I'm getting.
The database has been updated with all previous migrations, and I checked the DbContextModelSnapshot file...the new columns aren't anywhere in there (as expected). The database I'm targeting is a local SQL Server database.

Entity Framework 6.X and one-to-one relationship

I have the following model:
public partial class Driver
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Nickname { get; set; }
public virtual AspNetUser AspNetUser { get; set; }
......
}
public partial class AspNetUser
{
public string Id { get; set; }
public string UserName { get; set; }
public virtual Driver Driver { get; set; }
......
}
and the following mapping:
this.HasOptional(c => c.Driver)
.WithOptionalPrincipal(a => a.AspNetUser)
.Map(m => m.MapKey("AspNetUserId"));
It creates correct DB model, adds nullable AspNetUserId FK to Driver table.
But how to link one object with another in code. I don't have AspNetUserId property, so, I try to set object, like this:
_db.Drivers.Attach(driver);
_db.AspNetUsers.Attach(aspNetUser);
driver.AspNetUser = aspNetUser;
_db.SaveChanges();
but then I got an exception :
"An error occurred while saving entities that do not expose foreign
key properties for their relationships. The EntityEntries property
will return null because a single entity cannot be identified as the
source of the exception. Handling of exceptions while saving can be
made easier by exposing foreign key properties in your entity types.
See the InnerException for details."
"Store update, insert, or delete statement affected an unexpected
number of rows (0). Entities may have been modified or deleted since
entities were loaded. See
http://go.microsoft.com/fwlink/?LinkId=472540 for information on
understanding and handling optimistic concurrency exceptions."
How to solve it with EF 6.X ?
This is happening when the Driver is already associated with AspNetUser. When you attach the driver with AspNetUser property being null, EF assumes the original value of AspNetUserId being null and generates update statement with AspNetUserId IS NULL additional criteria, which of course does not match the existing record, the command returns 0 records affected and EF generates the exception in question.
The solution is (1) to load the original Driver.AspNetUser property value from the database before setting the new value. Also, in order to correctly handle the case when the new AspNetUser is already associated with a different Driver, you should (2) load AspNetUser.Driver property as well:
_db.Drivers.Attach(driver);
_db.AspNetUsers.Attach(aspNetUser);
_db.Entry(driver).Reference(e => e.AspNetUser).Load(); // (1)
_db.Entry(aspNetUser).Reference(e => e.Driver).Load(); // (2)
driver.AspNetUser = aspNetUser;
_db.SaveChanges();

Cannot insert explicit value for identity column - into related table

I have a database first model.
My application UI provides a group of checkboxes, one for each value in Data_Type.
When the user checks one, I expect a row to be added in BUS_APPL_DATA_TYPE,
however I'm getting an error about Cannot insert explicit value for identity column in DATA_TYPE (And I absolutely do not actually want to insert data in this table)
My EF Model class for BUS_APPL has this property
public ICollection<BusApplDataType> BusApplDataType { get; set; }
And that EF Model class looks like
public partial class BusApplDataType
{
public int BusApplId { get; set; }
public int DataTypeId { get; set; }
[Newtonsoft.Json.JsonIgnore]
public BusAppl BusAppl { get; set; }
public DataType DataType { get; set; }
}
What exactly do I need to add to the BusApplDataType collection to get a record to be inserted in BUS_APPL_DATA_TYPE?
Edit:
At a breakpoint right before SaveChanges.
The item at index 2 is an existing one and causes no issues.
The item at index 3 is new. Without this everything updates fine. There is a DATA_TYPE with id 5 in the database.
The surrounding code, if it helps.
[HttpPut("{id}")]
public IActionResult Update(int id, [FromBody] BusAppl item)
{
...
var existing = _context.BusAppl.FirstOrDefault(t => t.Id == id);
...
existing.BusApplDataType = item.BusApplDataType; //A bunch of lines like this, only this one causes any issue.
...
_context.BusAppl.Update(existing);
_context.SaveChanges();
return new NoContentResult();
}
My issue was that I needed to use my context to look up the actual entity, using info passed, instead of using the one with all the same values that was passed into my api directly.

Entity Framework Code First - Cannot insert duplicate key in object 'dbo.T_CRProviders'

I have some urgent issue which I could not find answer for across the web.
I am using CodeFirst EF 4.3.1 and I am getting an error:
Violation of PRIMARY KEY constraint 'PK_T_CRProviders'. Cannot insert duplicate key in object 'dbo.T_CRProviders'.
My code is:
Models:
public enum CRProviderEnums
{
PE_Abcd = 0,
PE_Efgh
}
[Table("T_CRProviders")]
public class CRProvider
{
[Key]
[Required]
public int Enum { get; set; }
[Required]
public string Name { get; set; }
}
[Table("T_CRSupportedResources")]
public class CRSupportedResource
{
[Key]
public Guid SupportedResourceId { get; set; }
[Required]
public CRProvider Provider { get; set; }
}
DbContext:
public class RSContext : DbContext
{
public DbSet<CRProvider> CRProviders { get; set; }
public DbSet<CRSupportedResource> CRSupportedResources { get; set; }
}
Table T_CRProviders looks like this: Enum (PK), Name
Table T_CRSupportedResources looks like this: SupportedResourceId (PK), Provider_Enum (FK).
In the database table T_CRProviders I already have a provider with the following values:
Enum: 0 (which is PE_Abcd)
Name: "PE_Abcd"
Now my main() calls a method AddSupportedResource. This method adds to table T_CRSupportedResources a new CRSupportedResource which refers to provider 0 (PE_Abcd). The method looks like this:
public void AddSupportedResource()
{
CRSupportedResource supportedResource = new CRSupportedResource()
{
SupportedResourceId = Guid.NewGuid(),
Provider = new CRProvider()
{
Enum = (int)CRProviderEnums.PE_Abcd,
Name = "PE_Abcd"
}
};
using (RSContext myContext = new RSContext())
{
myContext.CRSupportedResources.Add(supportedResource);
myContext.SaveChanges();
}
}
I expect that this method will leave table T_CRProviders untouched, and add a new row to table T_CRSupportedResources which will look like this:
SupportedResourceId: DE532083-68CF-484A-8D2B-606BC238AB61
Provider_Enum (FK): 0 (which is PE_Abcd).
Instead, upon SaveChanges, Entity framework also tries to add Provider to the T_CRProviders table, and since such a provider already exists it throws the following exception:
An error occurred while updating the entries.
Violation of PRIMARY KEY constraint 'PK_T_CRProviders'. Cannot insert duplicate key in object 'dbo.T_CRProviders'.
The statement has been terminated.
My question:
How can I instruct the EF not to update table T_CRProviders upon updating table T_CRSupportedResources?
Btw, in the SQL Server I see that table T_CRSupportedResources has a foreign key named FK_RW_TCRSupportedCloudResources_RW_TCRCloudProviders_Provider_Enum and its Update Rule has the value of No Action.
I expect that this method will leave table T_CRProviders untouched,
and add a new row to table T_CRSupportedResources
No it will not happen. You are creating detached entity graph consisting of existing entity a and new entity. EF doesn't know about the existence of your entity until you inform it about it - there are no DB queries validating existence performed by EF on behind.
If you call Add method all entities in your entity graph are added as new. If you don't want to insert all of them you can start with using Attach and manually change state for new ones. For example like:
myContext.CRSupportedResources.Attach(supportedResource);
myContext.Entry(supportedResource).State = EntityState.Added;
Actually, there is a way to do this.
See the answer to my question in the following link:
http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/62f3e5bc-c972-4622-b830-e7d7fe710101

EF CTP5 error: Invalid object name

I followed the example on scottgu's blog about EF code first CTP5 but I get the error that
System.Data.SqlClient.SqlException:
Invalid object name 'dbo.Products'.
this is the code I got.
<add name="CTP5Context"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|EFCTP5.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
public class CTP5Context : DbContext
{
public DbSet<Product> Products { get; set; }
}
public class Product
{
public int Id { get; set; }
public string ProductName { get; set; }
public int Amount { get; set; }
}
var context = new CTP5Context();
var products = context.Products;
return View(products);
im kinda clueless here I done the same as the blogpost, its not my first time with EF (But CTP5 tho), I'm I overlooking something?
If your table name is Product in the database, try this:
[Table("Product", SchemaName = "dbo")]
public class Product
{
public int Id { get; set; }
public string ProductName { get; set; }
public int Amount { get; set; }
}
To use the Table attribute You will need to add the following using statement:
using System.ComponentModel.DataAnnotations;
Hope this helps! It worked for me.
I had the same problem but I've done 2 changes and it works for me. I changed connection string (Added initial catalog)
<add name="CTP5Context"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\northwind.mdf;User Instance=true;initial catalog=Northwind"
providerName="System.Data.SqlClient" />
and in the Global.asax I've added following line in Application_Start()
Database.SetInitializer<Northwind>(new System.Data.Entity.DropCreateDatabaseAlways<Northwind>());
The exception looks like it's coming from the database. Are you sure your table name is 'Products' or is it 'Product' (singular instead of plural?)
It seems EF Code First works differently depending on which type of database you're connecting to. If you work with SQLCE which is what ScottGu is using to showcase EF Code First, then all tables will be created with names that are not plural. However, if you use SQL Server 2008 (that's what I tested with), it expected tables names to be plural. There are few ways around this, you could add the table name attribute as Omar shows, or you could override the OnModelCreating event for the context.
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
base.OnModelCreating(modelBuilder);
}
Make sure your Products table was created with the dbo Schema, a lot of times the schema will be something other than dbo, such as it can be your username or server name (if the account you're working with isnt in the db_owner schema). Open up the DB (since it's SQLExpress) with Server Explorer in Visual Studio)
To do this right click on the table name and select Open Table Definition then inside the table definition right click and select Properties and in the properties window check what is listed in the schema value. If it's not DBO then you should be able to change it to dbo and save it.