Entitiy Framework context.Database.ExecuteSqlCommand won't save changes to DB - sql-server

I am using EF for my web application and have encountered a strange error. I am trying to update a record in my DB, but even though the context.Database.ExecuteSqlCommand call returns 1, when I then call context.SaveChanges(), it returns 0 and the changes are not visible in the database.
Here is the code:
List<int> ids = new List<int> { 1, 2, 3 };
using (var context = new TestDbContext())
{
int rows=context.Database.ExecuteSqlCommand("UPDATE [Records] SET [ExampleFlag] = 1 WHERE Id in (#ids)",new SqlParameter("#ids",String.Join(",", ids)));
int rows2 = context.SaveChanges();
}
For some reason when debugging, rows equals 1, but rows 2 equals 0. As if it couldn't commit the changes to the database.
Any ideas on what may cause this?

These two ways to write to the database are almost two different worlds.
The core function of an Object-Relational Mapper (ORM) like Entity Framework is to keep an object model (for example in C#) and a relational database model in sync with one another. Therefore it is capable of tracking changes in the object model and writing these changes to the database.
Some ORM's, as a kind of courtesy, offer lower-level APIs to interact with the database. However, these functions don't interact with the ORM function, vise versa.
In other words, whatever statement is executed by DbContext.Database.ExecuteSqlCommand, EF's change tracker is completely oblivious of it. If no entity objects were modified by C# code, the change tracker has nothing to do. The executed SQL code has no effect on tracked entity objects.

Related

How to work with unsaved entities even though ID attribute is needed?

I'm creating a React application where my data has the following structure:
interface BookCase {
id: number;
bookShelves: BookShelf[];
}
interface BookShelf {
id: number;
}
Every bookcase and every bookshelf has an id property. I use this for the key attribute and for locating a bookshelf inside the bookShelves array. The id is generated in the backend by the database (With a BigSerial in PostgreSQL) on save.
I now want to create a new bookcase inside my frontend without immediately saving it to the backend. First I want to work with it, perform some operations on it (e.g. place a book on the shelf), and afterwards send the whole batch of changes with the new entities to the backend where it will then be persisted in the database.
Of course I do not yet have an id, although I need one to work on the bookcases. Should I rewrite my application to also accept null for id (I would prefer not to)? Should I just randomly create an temporary id, possibly having duplicates with the ids already present in the database (or for example use a negative value like -1)? Then I would need to replace all the ids afterwards after it has been saved to the database.
With UUIDs I could generate it on the frontend, but I guess there also has to be a common pattern to work with just incrementing integers as the id.
I do not think there is a clear answer here.
Essentially you have a object-relational mapping and there are various ways to handle it. Entity Framework for example just uses the default for the data type. So if the entity does not exist yet the ID will be 0 and any persisted entities have values starting at 1 so there are no conflicts.
One way i usually handle saving is by returning the updated record from the request, so you just replace your old one with that and you have the correct ID value applied automatically.

Inserts using Dapper.NET

I am using Dapper.NET for my database connections.
So far, I have resorted to hand writing all the SQL I need for Inserts and Updates, I've found this old post from Sam Saffron
Performing Inserts and Updates with Dapper
However, it doesn't lead to anything conclusive with regards to how to do inserts and updates from POCO objects, other than a few links to code that are several years old by now.
Since then, has a new small helper library to autogenerate what is needed popped up?
You can use Dapper.Contrib
//Insert one entity
connection.Insert(new Car { Name = "Volvo" });
//Insert a list of entities
connection.Insert(cars);
//Update one entity
connection.Update(new Car() { Id = 1, Name = "Saab" });
//Update a list of entities
connection.Update(cars);
See more examples here.

Concept of a database driven program in VB.NET

I have been developing programs in VB.NET for a few years and am familiar with it. The area where I do not have a lot of exposure is databases.
I am writing a program (for my personal use) called movie manager. It will store information on movies I have. I have selected Sql Server Compact Edition database. Assume I have a database with two tables namely Info and Cast. Info table has a few columns such as movie_name, release_date and so on. Cast table has few cols such as first_name,last_name etc.
Right now I have created a DataSet which reads all the info of tables from database (opens connection, fills tables info, closes connection). This way in a global variable I have a snapshot of database.
My queries :
Once I have data with me, every time I need to add, edit or delete a record I have to open a connection, fire an sql and close the connection. Right ? Is there a way to do this without using Sql ? Plus is this concept okay.
Since I am not using structures so I need to create empty datasets to store temp information. Is this convenient ?
If I have to search for a specific thing in dataset table, then do I have to loop thru all items or can I use sql on dataset or is there an alternate ?
1)Once I have data with me, every time I need to add, edit or delete a record I have to open a connection, fire an sql and close the connection. Right ? Is there a way to do this without using Sql ? Plus is this concept okay.
No. To update a database, you have to use the database. Create a stored procedure in the database to handle your functionality and then call it from the code and pass in whatever data needs saved. DO NOT USE INLINE SQL. Paramterized stored procedures are the way to go.
2) Since I am not using structures so I need to create empty datasets to store temp information. Is this convenient ?
It depends on what you're doing. I would create an object model to retain my updated data and then I'd pass the properties into the stored procedure when it was time to save my changes.
3) If I have to search for a specific thing in dataset table, then do I have to loop thru all items or can I use sql on dataset or is there an alternate ?
You can loop the rows or you can use linq to pull what you need out. Linq is really nice as it's basically .NET coded queries against a collection.
There are plenty of tutorials/guides out there to show you how to update via stored proc call form your code. There are a ton of linq tutorials as well. Basically, a linq query against your table will look something like:
dim result as Generic.List(of String) =
(from r in table.AsEnumerable()
select r
where r["columnName"] = "the value").ToList()
This syntax is probably a bit off, but it looks something like that.
Edit
Your Model:
Public Class EmployeeModel
Public Property Id
Public Property FirstName
Public Property Last Name
Public Property JobCode
Public Sub EmployeeModel(your params)
//set properties
End Sub
End Class
Your DAL:
Public Shared Class EmployeeDAL
Public Shared Sub SaveEmployee(ByRef model as EmployeeModel)
// call your sp_SaveEmployee stored procedure and set the parameters to the model properties
// #id = EmpoyeeModel.Id
// #JobCode = Employee.JobCode
// ...
End Sub
End Class
I use VB every few months, so there are probably some small syntax errors in there. But that's basically all you need to do. The function to save your data is in the DAL, not in the class itself. If you don't want to use a DAL, you can put the save functionality in your class, though. It'll work the same way, it's just not as clearly separated.
On your Questions.
number 1: You have to connect to database in order to store and retrieve data. There are lots of ways on how to deal with it and one way of it is to use app.config or you may simply create a function that calls the connection every time you need it.
number 2: Since you are dealing with dataset here are some tips you might want to look at DataSet
number 3: You can also try using Data Adapter and Data Table. I am not sure what you meant by your question number 3.
Cheers
I have problem with the way you are using your database and the ram of your computer.
Problem1: since you already have a database for holding the movies information why are you again holding the same information in memory?, creating an extra overhead. if your answer is for performance or i have cheap memory then why don't you use xml or flatfile instead? Database is not needed with this senario.
Problem2: You are like a soldier who dosent know about the weapon he use? right? because you are asking silly questions your first question about opening connection.. the answer is yes you have to open the connection every time save/read the data and close it as soon as possible.
your second question about convinent the answer is no. instead create class with all field as property and some method for initialization,saving,deleting. this way you have to write less code. nad suppose you have a movie names xyz there can be another movie xyz how will you distinguish it? if you have whole information b4 you you can do it via release date ,casts etc, but still it will be hard, so create a primary key for both your table
and finally your 3rd question , it will be easier to use use sql queries than looping thru the dataset(get rid of the dataset as soon as possible)
wish yu good luck on the road to rdbms

ADO.NET Data Services on Silverlight: Using the generated key within the same transaction

We have a Silverlight application that uses WCF Data Services. We want to add logging functionality: when a new row is generated, the primary key for this new row is also recorded in the logging table. The row generation and the logging should occur within the same transaction. The primary keys are generated via the database (using the IDENTITY keyword).
This might best be illustrated with an example. Here, I create a new Customer row, and in the same transaction I write the Customer's primary key to an AuditLog row. This example uses a thick client and the Entity Framework:
using (var ts = new TransactionScope())
{
AuditTestEntities entities = new AuditTestEntities();
Customer c = new Customer();
c.CustomerName = "Acme Pty Ltd";
entities.AddToCustomer(c);
Debug.Assert(c.CustomerID == 0);
entities.SaveChanges();
// The EntityFramework automatically updated the customer object
// with the newly generated key
Debug.Assert(c.CustomerID != 0);
AuditLog al = new AuditLog();
al.EntryDateTime = DateTime.Now;
al.Description = string.Format("Created customer with customer id {0}", c.CustomerID);
entities.AddToAuditLog(al);
entities.SaveChanges();
ts.Complete();
}
It's a trivial problem when developing a thick client using Entity Framework.
However, using Silverlight and ADO.NET data services:
SaveChanges can only be invoked
asynchronously
I'm not sure TransactionScope is available
I'm not sure if generated keys can be reflected in the client Edit: According to Alex James they are indeed reflected in the client
So, will this even be possible?
Short Answer: No this is not even possible
Okay... so:
Generated Keys are reflected in the client.
You can transact one SaveChanges operation by using DataServiceContext.SaveChanges(SaveChangesOption.Batch)
But unfortunately you can't do anything to tie one request to the response of another, and wrap them both in one transaction.
However...
If you change the model by making a CustomerAuditLog method that derives from AuditLog:
// Create and insert customer ...
// Create audit log and relate to un-insert customer
CustomerAuditLog al = new CustomerAuditLog();
al.EntryDateTime = DateTime.Now;
al.Description = string.Format("Created customer with {Customer.ID}");
// assuming your entities implement INotifyPropertyChanging and you are using
// the Data Services Update to .NET 3.5 SP1 to use DataServiceCollection
// to notify the DataServiceContext that a relationship has been formed.
//
// If not you will manually need to tell Astoria about the relationship too.
al.Customer = c;
entities.AddToAuditLog(al);
entities.SaveChanges();
And having some sort of logic deep in your underlying DataSource or maybe even the database to replace {Customer.ID} with the appropriate value.
You might be able to get it to work, because if two inserts happen in the same transaction and one (CustomerAuditLog) depends on another (Customer) they should be ordered appropriately by the underlying data source.
But as you can see this approach is kind of hacky, you don't want a Type for each possible audit message do you! And ... it might not even work.
Hope this helps
Alex
Data Services Team, Microsoft

Is there any overhead with LINQ or the Entity Framework when getting large columns as part of an entity?

Let's say you have a table containing articles and you want want to display a list of them, excluding the actual article text. When you get a list of the article objects using LINQ or the Entity Framework, is there a LOT of overhead associated with getting that text column too? I assume that when you start enumerating the list, the article text will be stored in memory until the objects are disposed of.
So would it make sense to create an intermediary object that doesn't contain the text column? If so, how would you do this? Make a class inside your DAL, allow the ORM to automatically create one by setting up a stored procedure, or some other process?
The overhead isn't huge (just the cost of sending the data over the wire), but if you don't need the data sure, don't return it. I find the easiest way is to use anonymous types:
from a in Context.Articles
select new {Name = a.Name, Author = a.Author};
Since you're not actually materializing any Article instances, the Entity Framework won't need to fill out all the properties of an instance.
If you don't need the data you should definitely create a different type. By convention I typically name this sort of class "nnnInfo" or "nnnListItem". To create ArticleListItem, in L2S, simply drag the table to your DataContext designer a second time. Then rename it from 'Article1' to 'ArticleListItem' and remove the unneeded properties (rt click, delete). In EF, the process would be similar. As Craig notes, you could use anonymous types, but by creating a concrete type, you can reuse throughout your app, expose via services, etc.
A second way to do this would be to create the class manually and write an extension method to return ArticleListItem:
public static IQueryable<ArticleListItem> ToListItems(this IQueryable<Article> articles)
{
return from a in articles select new ArticleListItem{ Title = a.Title, ...}
}
This would allow you to "cast" any queries against Article as ArticleListItem...

Resources