I'm trying to use Entity Framework 4 for a small database application I'm writing to keep record of downloaded files. When running the application I set a break point after the tableName.Add() method, before the .SaveChanges() method and I can see the data saved into the entity; then I have another break point after calling the .SaveChanges() method, and look into the database to find there is no record saved to it. I have found a lot of similar questions, but I have not found the solution to my particular problem. Here is the code:
public void StartNewDownload(string FileID)
{
DateTime startTime = DateTime.Now;
FilesDBEntities db = new FilesDBEntities();
int startedID = (from dr in db.tblDownloadResults
where dr.Value.Equals("Started")
select dr.ResultID).First();
tblDownloads myDownload = new tblDownloads { FileID = FileID, StartDateTime = startTime, ResultID = startedID };
db.tblDownloads.Add(myDownload);
db.SaveChanges();
}
Any help is appreciated.
Thanks!
Pawel, you guided me in the right direction. The entity had the data, but the database I was looking into did not. But after reading your comment I ran the program from Visual Studio and used Process Monitor to monitor any operations to *.sdf files. This helped finding out that upon building the solution, it would create another database file to the bin\Debug folder. I forgot the database Build Action property was set as "Content".
Thanks!!
You can use SQL Server Profiler to see if the entity framework has really called the database.
(The tool is not included in SQL Server Express)
Related
I've pretty much looked everywhere I can, and I'm having a hard time trying to find the solution. it took me a week to create an immensely complex calculation query using a stored procedure, and I'd like to fetch the results from this query and place into a POCO class, similar to what I've done before using EF 6.
Map Stored Procedure Column names to POCO DTO
Basically this:
var p1 = new SqlParameter { ParameterName = "Param1", Value = 1 };
var p2 = new SqlParameter { ParameterName = "Param2", Value = 2 };
string query = "EXEC Calcs_Selections #Param1, #Param2";
var calcs = context.Database.SqlQuery<CalcViewPOCO>(query, p1, p2).ToList();
I've read literature found here:
EF Core Querying Raw SQL
Raw SQL Query without DbSet - Entity Framework Core
And discovered there is no more "free sql" in EF Core anymore. The FromSQL basically projects the results into a real entity found in the database, which I don't want because I don't have a table that has the same columns found. Instead, one solution is to extend the DBContext, and create a new DBSet
But I'm really not sure how to do this. I have a database first model, and used Scaffold-DbContext:
Getting Started with EF Core on ASP.NET Core with an Existing Database
I don't want to add to the context that was created automatically, in my case ProjectAContext, since if I make any more changes to the database, and run scaffolding again, it will overwrite my changes.
Though I couldn't wait any longer for the newer versions of EF Core to add functionality to what I asked, I found a library that helped me solve this solution.
https://github.com/snickler/EFCore-FluentStoredProcedure
It allowed me to take a result set, and map to a list of DTOs.
Sample shown on from the repo:
var dbContext = GetDbContext();
dbContext.LoadStoredProc("dbo.SomeSproc")
.WithSqlParam("fooId", 1)
.ExecuteStoredProc((handler) =>
{
var fooResults = handler.ReadToList<FooDto>();
// do something with your results.
});
My DB is not getting copied over to my device, but it does to the simulator.
Here is what I am doing:
Create a new sqllite3 db from terminal:
sqlite> create table myTable (id integer primary key, name text);
sqlite> insert into myTable (name) values ('john');
sqlite> select * from myTable;
1|john
This creates a db in this path: users/John/iosApp.db
Then I close the terminal and copy that db to my xamarin project and set its buildAction to 'content'.
Here is my model:
[Table("myTable")]
public class MyTable
{
[PrimaryKey, AutoIncrementAttribute, Column("id")]
public int ID {get; set;}
[Column("name")]
public string Name { get; set; }
}
And I do this to copy the db to the Document folder:
string pathToDatabase = "iosApp.db";
userPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), pathToDatabase);
File.Delete (userPath); // delete first and copy next
File.Copy (pathToDatabase, userPath);
var myDB = new SQLiteConnection (userPath);
MyTable myTable = myDB.Get<MyTable> (1);
then I run the app and I set a breaking point after the last line in the code above and I hover over the myTable:
if I am using the simulator, I see the schema and value of 1 for ID and 'john' for Name.
if I am using the device, I see the schema but 0 value for ID and null for Name!
Looking at the path when I am using the device, points to this:
"/private/var/mobile/Applications/277749D4-C5CC-4BF4-8EF0-23B23833FCB1/Documents/iosApp.db"
I loaded the files in using iFunBox and the db file is there with the exact size
I have tried all the following:
Clean All in the project
Rebuild All
removed the 'debug' folder from the project
restarted Xamarin
and even restart the machine
But still the same behavior, what else should I try to be able to see the values of ID and Name?
my sdk version is attached
UPDATE:
After a lot of changes and cleaning up, I managed to display the value of all columns except the identity column displayed as 0. Puzzled, I went back to the xamarin sample project: http://developer.xamarin.com/recipes/ios/data/sqlite/create_a_database_with_sqlitenet/
it displayed the value of the identity correctly.
Trying to bring in similar code to my project, but no success.
To role out the possibility of version issue, I went and downloaded the latest sqlite from this link:
http://components.xamarin.com/gettingstarted/sqlite-net/true
The same behavior... I created a whole new page in my project, used the references the sample used and only has the code to create a sample table. Same behavior, the identity value is displayed in the other project but not mine. This leads me to conclude that there is something completely is wacky in my project. Now I am considering creating a whole new project and move my files to the new one after making sure first that the piece of being able to see the value of my id in my model shown up. Stay toned, I will make sure to update this thread.
If you have any pointers, please share them
I couldn't find a solution to my problem, but I found an alternate method to create the DB that turns out to be even nicer than the original one.
One important thing to note is that in the original problem (details above), the DB code was working for months since I started developing the application. I don't know when it started behaving badly, but I suspect it was due to the download of the new Xamarin 3.0. I can't think of any other reason.
So, to solve my issue, There are two main things I did:
I followed this link on how to create DB and tables and do CRUD operations: http://components.xamarin.com/gettingstarted/sqlite-net/true
This method seems to be the newest way to create DB. It was: published on
June 24, 2014. It has an SQLite.dll, whereas my previous solution was using a SQLite.cs file. So, now I am creating my DB now at runtime.
Something didn't work still with the new method. It was giving me an object null exception error. I didn't spend much time investigating about it. When I provided values for my primary key and identity values, the error went away. Actually, this could have been the solution to my previous problem. I would have tried providing the identity values against the old code, if I am not already happier with the new method.
I hope this helps someone.
Don't know if this is intended or a bug, but the following code below using BeforeSaveEntity will only modify the entity for newly created records (EntityState = Added), and won't work for modified, is this correct?
protected override bool BeforeSaveEntity(EntityInfo entityInfo)
{
var entity = entityInfo.Entity;
if (entity is User)
{
var user = entity as User;
user.ModifiedDate = DateTime.Now;
user.ModifiedBy = 1;
}
...
The root of this issue is that on the breeze server we don’t have any built in change tracking mechanism for changes made on the server. Server entities can be pure poco. The breeze client has a rich change tracking capability for any client side changes but when you get to the server you need to manage this yourself.
The problem occurs because of an optimization we perform on the server so that we only update those properties that are changed. i.e. so that any SQL update statements are only made to the changed columns. Obviously this isn’t a problem for Adds or Deletes or those cases where we update a column that was already updated on the client. But if you update a field on the server that was not updated on the client then breeze doesn't know anything about it.
In theory we could snapshot each entity coming into the server and then iterate over every field on the entity to determine if any changes were made during save interception but we really hate the perf implications especially since this case will rarely occur.
So the suggestion made in another answer here to update the server side OriginalValuesMap is correct and will do exactly what you need.
In addition, as of version 1.1.3, there is an additional EntityInfo.ForceUpdate flag that you can set that will tell breeze to update every column in the specified entity. This isn't quite as performant as the suggestion above, but it is simpler, and the effects will be the same in either case.
Hope this helps.
I had the same problem, and I solved that doing this:
protected override bool BeforeSaveEntity(EntityInfo entityInfo)
{
if(entityInfo.EntityState== EntityState.Modified)
{
var entity = entityInfo.Entity;
entityInfo.OriginalValuesMap.Add("ModificationDate", entity.ModificationDate);
entity.ModificationDate = DateTime.Now;
}
}
I think you can apply this easily to your case.
I am using Entity Framework 4 (database-first approach) in my ASP.NET 4.0 Webforms app.
What I'm basically doing is fetching the entity to be edited from my ObjectContext, and displaying the fields the user should enter data into (or modify existing data) on a web form.
When time comes to store the data back, I'm reading out the values from the web form, building up a new Entity instance, and then I have a generic method called AddOrUpdate that detects whether this is a new entity (so it needs to insert it), or if it's an existing one (so it needs to update the existing data).
My method using the EntityKey and checks to see if the object context already knows about this object - very similar to what Cesar de la Torre of Microsoft shows here in his blog post:
public static void AddOrUpdate(ObjectContext context, EntityObject objectDetached)
{
if (objectDetached.EntityState == EntityState.Detached)
{
object currentEntityInDb = null;
if (context.TryGetObjectByKey(objectDetached.EntityKey, out currentEntityInDb))
{
// attach and update the existing entity
}
else
{
// insert new entity into entity set
context.AddObject(objectDetached.EntityKey.EntitySetName, objectDetached);
}
}
}
This worked just fine - for the longest time. But today, suddenly, out of the blue, I keep getting exceptions like this on the context.TryGetObjectByKey statement:
System.InvalidOperationException: Object mapping could not be found for Type with identity 'MyEntityType'
I cannot remember having changed anything in this core code at all - and the entity type is defined, the ID value that's stored in the EntityKey does indeed exist in the database... everything should be fine - but it keeps failing on me...
What on earth happened here??
I did find a few blog and forum posts on the topic, but none could really enlighten me or help me fix the issue. I must have messed up something - bad - but I really cannot see the forest for the trees - any hints?
Generally this sort of issue happens when EF cant find the assembly that has the type. With out seeing the full exception is difficult to figure out exactly but it seems your recent changes and the way you are using EF seems to be the cause.
EF ususally picks the type directly from the type itself when it has to access it using ObjectSet on the context. In the other cases where the type is not available from the context of the call it looks at the calling assembly and any dll's referenced by the calling assembly. Id it cant find it it throws the error message.
You can use the LoadFromAssembly method in the MetadataWorkspace of the context.
ObjectContext.MetadataWorkspace.LoadFromAssembly(assembly).
This way EF will know where to look for your types.
I am accessing my database through ADO.NET Entity framework in MVC 3 Application.
I am updating my database through Stored Procedure.
But the changes are not reflected at run time.I mean to say i am able to see the changes only after restarting it.
What is the reason for the problem and How can i avoid it ?
I am using Repository pattern So at repository My code look like this
Ther Is One Function Which Save Changes
public void SaveNewAnswer(AnswerViewModel answer,string user)
{
SurveyAdminDBEntities _entities = new SurveyAdminDBEntities();
_entities.usp_SaveNewAnswer(answer.QuestionId, answer.AnswerName, answer.AnswerText, answer.AnswerOrder, answer.Status, user);
_entities.SaveChanges();
}
Data Retreival Code
public IEnumerableGetMultipleChoiceQuestions(string questionId)
{
SurveyAdminDBEntities _entities = new SurveyAdminDBEntities();
_entities.AcceptAllChanges();
_entities.SaveChanges();
return _entities.usp_GetMultipleChoiceQuestions(Int32.Parse(questionId));
}
But Changes are not reflected till the time i don't clode the session of the browser and run it again .
Please help !
Thank You In advance
Are you calling context.SaveChanges() on your Entities (DbContext/ObjectContext) object? Are you using a transaction that you haven't committed?
If you have an uncommitted transaction in your sproc, you can try creating your own entity transaction and seeing if committing your transaction will commit the nested transaction as well. The problem is that calling SaveChanges() automatically begins and commits a transaction, so this may not be any different than that.
I would also call _entities.AcceptAllChanges() in your save operation.
public void SaveNewAnswer(AnswerViewModel answer,string user)
{
SurveyAdminDBEntities _entities = new SurveyAdminDBEntities();
_entities.Connection.Open();
System.Data.Common.DbTransaction tran = _entities.Connection.BeginTransaction();
try
{
_entities.usp_SaveNewAnswer(answer.QuestionId, answer.AnswerName, answer.AnswerText, answer.AnswerOrder, answer.Status, user);
_entities.SaveChanges(); // automatically uses the open transaction instead of a new one
tran.Commit();
}
catch
{
tran.Rollback();
}
finally
{
if (_entities.Connection.State == System.Data.ConnectionState.Open)
_entities.Connection.Close();
_entities.AcceptAllChanges();
}
}
Is your stored procedure doing an explicit commit? Things run in a database session will be available for that session, but not available to any other session until the action is committed.
When you pull data out of your database into your context that data is kept in memory, separate from the actual database itself.
You will see the changes if you create a new context object instance and load the data from the database with it.
It's good practice to not use the same instance of your context object but create them on an as needed basis for individual transactions with the database. In your case if you're updating via function imports instead of the context.SaveChanges() method then you need to refresh your context with the updated data after you commit those changes.
Add this to your connect string (assuming sql 2005)
transaction binding=Explicit Unbind;
if the data is no longer available after session reset, then the problem is indeed with a transaction, if the data is then available after reset, then your problem is something different and we'll likely need more details.