Entity Framework: ObjectStateEntry error - c#

I have code using entity framework as shown below. I am getting the following excpetion. What is the reason for this? How to overcome this?
The ObjectStateManager does not contain an ObjectStateEntry with a reference to an object of type 'MyEntityDataModelEDM.Payment'.
Note: I wrote this code based on the reply in Context Per Request: How to update Entity
CODE
public class MyPaymentRepository
{
private string connectionStringVal;
public MyPaymentRepository()
{
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();
sqlBuilder.DataSource = ".";
sqlBuilder.InitialCatalog = "LibraryReservationSystem";
sqlBuilder.IntegratedSecurity = true;
// Initialize the EntityConnectionStringBuilder.
EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();
entityBuilder.Provider = "System.Data.SqlClient";
entityBuilder.ProviderConnectionString = sqlBuilder.ToString();
entityBuilder.Metadata = #"res://*/MyEDMtest.csdl|res://*/MyEDMtest.ssdl|res://*/MyEDMtest.msl";
connectionStringVal = entityBuilder.ToString();
}
public MyEntityDataModelEDM.Payment GetPaymentByID(int paymentID)
{
MyEntityDataModelEDM.Payment payment;
using (var myDatabaseContext = new MyEntityDataModelEDM.LibraryReservationSystemEntities(connectionStringVal))
{
Func<MyEntityDataModelEDM.Payment, bool> predicate = (p => p.PaymentID == paymentID);
payment = myDatabaseContext.Payments.SingleOrDefault(predicate);
}
return payment;
}
public void UpdateDBWithContextChanges(MyEntityDataModelEDM.Payment paymentEntity)
{
using (var myDatabaseContext = new MyEntityDataModelEDM.LibraryReservationSystemEntities(connectionStringVal))
{
myDatabaseContext.ObjectStateManager.ChangeObjectState(paymentEntity, System.Data.EntityState.Modified);
myDatabaseContext.SaveChanges();
}
}
}
CLIENT
static void Main(string[] args)
{
MyRepository.MyPaymentRepository rep = new MyRepository.MyPaymentRepository();
MyEntityDataModelEDM.Payment p2 = rep.GetPaymentByID(1);
p2.PaymentType = "CHANGE";
rep.UpdateDBWithContextChanges(p2);
}
REFERENCE:
The ObjectStateManager does not contain an ObjectStateEntry with a reference to an object

You did not attach it to the context first. See the answer to the referenced question.

Related

Entitiy framework and sqlite as file path not working

I have been trying Browse a sqlite db file and read data using Entity framework .
But following way does not work
I am initiating the MydbContext with sqlite file path
eg
using (var sourceContext = new MydbContext(#"D:\test\data.sqlite"))
{
var a= sourceContext.MyModel.ToList();
}
public MydbContext(string path)
: base(GetConnectionString(path))
{
Configuration.LazyLoadingEnabled = false;
}
public static string GetConnectionString(string path)
{
var entityConnectionString = new EntityConnectionStringBuilder
{
Metadata = "res://*",
Provider = "System.Data.SQLite.EF6",
ProviderConnectionString = sqlLiteConnectionString,
}.ConnectionString;
}
Please suggest if there is a proper way to achieve this using sqlite and ef.
Got the answer from comments
private static SQLiteConnection GetConnectionString(string path)
{
var con= new SQLiteConnection()
{
ConnectionString =
new SQLiteConnectionStringBuilder()
{ DataSource = path, ForeignKeys = true,BinaryGUID = false }
.ConnectionString
};
return con;
}

How to manually (via code) apply DbMigration which was manually crafted?

I manually created a class
public class AddClientsTable : DbMigration, IMigrationMetadata
{
string IMigrationMetadata.Id
{
get { return "201611281757258_AddClientsTable"; }
}
string IMigrationMetadata.Source
{
get { return null; }
}
string IMigrationMetadata.Target
{
get { return "AddClientsTable-Migration"; }
}
public override void Up() {
CreateTable("Clients", t => new {
ClientId = t.Guid(name:"ClientId"),
Name = t.String()
})
.PrimaryKey( t => t.ClientId, "ClientId")
.Index( t => t.ClientId, "PK_Clients", true);
}
public override void Down() {
DropIndex("Clients", "PK_Clients");
DropTable("Clients");
}
}
and i want to apply it via code-first migrations from code like this :
var migration = new AddClientsTable();
migration.Up();
context.RunMigration(migration);
which I stole from here but when I run the code I'm getting this exception :
Unable to cast object of type 'System.Data.Entity.Migrations.Model.CreateIndexOperation' to type 'System.Data.Entity.Migrations.Model.HistoryOperation'.
HistoryOperation is the operation which updates __MigrationHistory table ? so How do I do that via code ?
Am I missing something or the EntityFrameowrk Update-Database command does more than what I'm aware of ?
It doesn't make sense to cherry pick a migration and run it, because the migrations are cumulative and must be run in sequence. As such, you'd be better to run the equivalent of update-database powershell command at application startup.
Here's some code we use to do that:
In the Configuration.cs class constructor (this file was made when you enable-migrations)
AutomaticMigrationsEnabled = false;
AutomaticMigrationDataLossAllowed = false;
then at app startup call the following method:
public static void ApplyDatabaseMigrations()
{
//Configuration is the class created by Enable-Migrations
DbMigrationsConfiguration dbMgConfig = new Configuration()
{
ContextType = typeof(MyDbContext) //+++++CHANGE ME+++++
};
using (var databaseContext = new MyDbContext()) //+++++CHANGE ME+++++
{
try
{
var database = databaseContext.Database;
var migrationConfiguration = dbMgConfig;
migrationConfiguration.TargetDatabase =
new DbConnectionInfo(database.Connection.ConnectionString,
"System.Data.SqlClient");
var migrator = new DbMigrator(migrationConfiguration);
migrator.Update();
}
catch (AutomaticDataLossException adle)
{
dbMgConfig.AutomaticMigrationDataLossAllowed = true;
var mg = new DbMigrator(dbMgConfig);
var scriptor = new MigratorScriptingDecorator(mg);
string script = scriptor.ScriptUpdate(null, null);
throw new Exception(adle.Message + " : " + script);
}
}
}

Entity Framework 6 set connection string in code

I have a dll that uses the Entity Framework 6 to do some database operations. I'm using a database first approach.
The model and everything concerning the Entity Framework, like the connection string in the App.config, were created via the wizzard in Visual Studio.
So I compiled the dll and put it together with the corresponding .config in the folder where the application using the dll expects it.
Everything works fine until I get to the point where an actual database call is made. There I get the error:
Cannot find connection string for MyDatabaseEntity
The automatically generated connectionstring is, as I said, in the config file of the dll. I cannot change the App.config of the application.
But the application hands over an object that has all the information I need to build the connection string myself.
So I'm looking for a way to set the connection string in the code without relying on a config file.
All the tutorials I find for a database first approach use this method though.
I found a post here that says to simply give the connection string as a parameter when creating the Object like
MyDatabaseEntities = new MyDatabaseEntities(dbConnect);
but ´MyDatabaseEntities´ doesn't have a constructor that takes any parameters
public partial class MyDatabaseEntities : DbContext
{
public MyDatabaseEntities()
: base("name=MyDatabaseEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<MyTable> MyTable { get; set; }
}
How about:
public partial class MyDatabaseEntities : DbContext
{
public MyDatabaseEntities(string connectionString)
: base(connectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<MyTable> MyTable { get; set; }
}
Then initialize your database like you did before:
string myConnectionString = "...";
MyDatabaseEntities = new MyDatabaseEntities(myConnectionString);
I had the similar issue. My Edmx and App.Config was in a different project. My startup project was different, had 3 different connection strings, we need to choose one on the fly depending on the environment. So couldn't use a fixed connection string. I created a partial class overload of the Context.cs using the same namespace. Following was my default Context.cs;
namespace CW.Repository.DBModel
{
public partial class CWEntities : DbContext
{
public CWEntities()
: base("name=CWEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
...
...
}
}
My partial class overload;
namespace CW.Repository.DBModel
{
public partial class CWEntities : DbContext
{
public CWEntities(string ConnectionString)
: base(ConnectionString)
{
}
}
}
Lastly, as my connection strings were not for EF, I converted them to a EF connection string.
public static string GetEntityConnectionString(string connectionString)
{
var entityBuilder = new EntityConnectionStringBuilder();
// WARNING
// Check app config and set the appropriate DBModel
entityBuilder.Provider = "System.Data.SqlClient";
entityBuilder.ProviderConnectionString = connectionString + ";MultipleActiveResultSets=True;App=EntityFramework;";
entityBuilder.Metadata = #"res://*/DBModel.CWDB.csdl|res://*/DBModel.CWDB.ssdl|res://*/DBModel.CWDB.msl";
return entityBuilder.ToString();
}
Lastly, the calling
var Entity = new CWEntities(CWUtilities.GetEntityConnectionString(ConnectionString));
I got this solution using below code, I can hardcode connection string using C# code without using config file.
public class SingleConnection
{
private SingleConnection() { }
private static SingleConnection _ConsString = null;
private String _String = null;
public static string ConString
{
get
{
if (_ConsString == null)
{
_ConsString = new SingleConnection { _String = SingleConnection.Connect() };
return _ConsString._String;
}
else
return _ConsString._String;
}
}
public static string Connect()
{
//Build an SQL connection string
SqlConnectionStringBuilder sqlString = new SqlConnectionStringBuilder()
{
DataSource = "SIPL35\\SQL2016".ToString(), // Server name
InitialCatalog = "Join8ShopDB", //Database
UserID = "Sa", //Username
Password = "Sa123!##", //Password
};
//Build an Entity Framework connection string
EntityConnectionStringBuilder entityString = new EntityConnectionStringBuilder()
{
Provider = "System.Data.SqlClient",
Metadata = "res://*/ShopModel.csdl|res://*/ShopModel.ssdl|res://*/ShopModel.msl",
ProviderConnectionString = #"data source=SIPL35\SQL2016;initial catalog=Join8ShopDB2;user id=Sa;password=Sa123!##;"// sqlString.ToString()
};
return entityString.ConnectionString;
}
and using DbContext using like this:
Join8ShopDBEntities dbContext = new Join8ShopDBEntities(SingleConnection.ConString);
Thanks a lot . I changed little for Code First EF6.
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.Entity.Core.EntityClient;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data
{
public class SingleConnection
{
private SingleConnection() { }
private static SingleConnection _ConsString = null;
private String _String = null;
public static string ConString
{
get
{
if (_ConsString == null)
{
_ConsString = new SingleConnection { _String = SingleConnection.Connect() };
return _ConsString._String;
}
else
return _ConsString._String;
}
}
public static string Connect()
{
string conString = ConfigurationManager.ConnectionStrings["YourConnectionStringsName"].ConnectionString;
if (conString.ToLower().StartsWith("metadata="))
{
System.Data.Entity.Core.EntityClient.EntityConnectionStringBuilder efBuilder = new System.Data.Entity.Core.EntityClient.EntityConnectionStringBuilder(conString);
conString = efBuilder.ProviderConnectionString;
}
SqlConnectionStringBuilder cns = new SqlConnectionStringBuilder(conString);
string dataSource = cns.DataSource;
SqlConnectionStringBuilder sqlString = new SqlConnectionStringBuilder()
{
DataSource = cns.DataSource, // Server name
InitialCatalog = cns.InitialCatalog, //Database
UserID = cns.UserID, //Username
Password = cns.Password, //Password,
MultipleActiveResultSets = true,
ApplicationName = "EntityFramework",
};
//Build an Entity Framework connection string
EntityConnectionStringBuilder entityString = new EntityConnectionStringBuilder()
{
Provider = "System.Data.SqlClient",
Metadata = "res://*",
ProviderConnectionString = sqlString.ToString()
};
return entityString.ConnectionString;
}
}
}
You can use singleton patter for it . For example
private YouurDBContext context;
public YouurDBContext Context
{
get
{
if (context==null)
{
context = new YouurDBContext();
}
return context;
}
set { context = value; }
}

how to reattach the IQueryable object to a new instance of Context object

i want to save the last searched query in a global variable and when i use that in another method it says :
ObjectDisposedException was unhandled by user code: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
IQueryable lastQry = null;
private void SearchMethod()
{
using(var ctx = new entityContex())
{
var qry = ctx.Table1.Where(t=> t.Name.StartWith(txtName.Text)).Take(100);
lastQry = qry;
dgvResult.DataSource = qry.ToList();
}
}
private void RefreshResult()
{
using(var ctx = new entityContex())
{
if(lastQry != null)
//here is the Error ! <<---------------->>
dgvResult.DataSource = lastQry.ToList();
}
}
One way would be to create and store a delegate which runs the query:
Func<entityContex, IQueryable</*Table1 type*/>> queryExecutor = null;
private void SearchMethod()
{
using(var ctx = new entityContex())
{
queryExecutor = c => c.Table1.Where(t=> t.Name.StartWith(txtName.Text)).Take(100);
var qry = queryExecutor(ctx);
dgvResult.DataSource = qry.ToList();
}
}
private void RefreshResult()
{
using(var ctx = new entityContex())
{
if(queryExecutor != null)
dgvResult.DataSource = queryExecutor(ctx).ToList();
}
}
Rather than storing the IQueryable, store the list:
List<Table1> lastQry = null;
private void SearchMethod()
{
using(var ctx = new entityContex())
{
var qry =
ctx.Table1
.Where(t=> t.Name.StartWith(txtName.Text))
.Take(100)
.ToList(); // <--
lastQry = qry;
dgvResult.DataSource = qry;
}
}
private void RefreshResult()
{
using(var ctx = new entityContex())
{
if(lastQry != null)
dgvResult.DataSource = lastQry;
}
}

The EntityKey property can only be set when the current value of the property is null

I have the following scenario, How can i do this without getting the System.InvalidOperationException error.
SomeClass.cs:
using (var eo = new MyEntities())
{
targetRole = (from p in eo.UserRoles
where p.Code == 2
select p).FirstOrDefault();
}
var user = new User
{
UserName = userName,
Password = txtPassword.Text.Trim(),
UserRole = targetRole
};
AnotherClass.AddObject(user);
AnotherClass.cs
public static void AddObject(object poco)
{
using (var eo = new MyEntities())
{
eo.AddObject("Users", poco);
eo.SaveChanges(); //<--- Exceptions Thrown.
}
}
I found the answer myself, I need to attach the targetRole object to the current context:
AnotherClass.cs :
public static void AddObject(object poco)
{
using (var eo = new MyEntities())
{
eo.UserRoles.Attach(targetRole); //<-- the magic
eo.AddObject("Users", poco);
eo.SaveChanges(); //<--- it works like a charm. Hoorah
}
}

Categories